[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Mon Dec 18 03:37:02 UTC 2017


The branch, master has been updated
       via  142060d WHATSNEW: Encrypted secrets
       via  957bf8c selftest fl2000dc provision with --plaintext-secrets
       via  d120d7f provision: Changes to support encrypted_secrets module
       via  1d3ae2d dsdb encrypted secrets module
       via  b29ab3a tests dsdb encrypted secrets module
       via  e5ce0a4 pyglue: Add function to generate a random byte string
      from  7fa91fc smbd: Fix coredump on failing chdir during logoff

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 142060d06f329adaa96a539b130ff2659f0d8110
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Tue Dec 12 10:49:05 2017 +1300

    WHATSNEW: Encrypted secrets
    
    Document the encrypted secrets feature in WHATSNEW.txt
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Mon Dec 18 04:36:19 CET 2017 on sn-devel-144

commit 957bf8cec4ba598bcb27169d9e1400f3ad520a31
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Fri Dec 15 07:27:10 2017 +1300

    selftest fl2000dc provision with --plaintext-secrets
    
    Provision fl2000dc provision with --plaintext-secrets to test that the
    --plaintext-secrets option functions correctly.
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit d120d7fe848aff42b2a01ee33ff9f02faaf3541d
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Fri Dec 15 07:24:14 2017 +1300

    provision: Changes to support encrypted_secrets module
    
    Changes to provision and join to create a database with
    encrypted_secrets enabled and a key file generated.
    
    Also adds the --plaintext-secrets option to join and provision commands
    to allow the creation of unencrypted databases.
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 1d3ae2d92f40567910303205da090fc86c7351b8
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Fri Dec 15 07:21:10 2017 +1300

    dsdb encrypted secrets module
    
    Encrypt the samba secret attributes on disk.  This is intended to
    mitigate the inadvertent disclosure of the sam.ldb file, and to mitigate
    memory read attacks.
    
    Currently the key file is stored in the same directory as sam.ldb but
    this could be changed at a later date to use an HSM or similar mechanism
    to protect the key.
    
    Data is encrypted with AES 128 GCM. The encryption uses gnutls where
    available and if it supports AES 128 GCM AEAD modes, otherwise nettle is
    used.
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b29ab3a0c16b2f1abed89b41c92c446e8fe59f9b
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Fri Dec 15 07:17:54 2017 +1300

    tests dsdb encrypted secrets module
    
    Add tests to check that the encrypted_secrets module encrypts
    secrets/sensitive attributes on disk.
    
    This test also proves that the provision and join operations correctly
    configure the encrypted_secrets module.
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit e5ce0a4d73a196ee4c92b68eb744434cfcf942ec
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Thu Nov 2 10:15:29 2017 +1300

    pyglue: Add function to generate a random byte string
    
    Adds a function to generate a random byte string using the samba random
    routines.
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 WHATSNEW.txt                                       |   33 +
 librpc/idl/drsblobs.idl                            |   30 +
 python/pyglue.c                                    |   21 +
 python/samba/__init__.py                           |    1 +
 python/samba/join.py                               |   21 +-
 python/samba/netcmd/domain.py                      |   24 +-
 python/samba/provision/__init__.py                 |   50 +-
 python/samba/tests/encrypted_secrets.py            |   83 +
 selftest/knownfail.d/encrypted_secrets             |    8 +
 selftest/target/Samba4.pm                          |    8 +-
 source4/dsdb/samdb/ldb_modules/encrypted_secrets.c | 1755 ++++++++++++++++++++
 source4/dsdb/samdb/ldb_modules/samba_dsdb.c        |   29 +-
 .../ldb_modules/tests/test_encrypted_secrets.c     | 1186 +++++++++++++
 source4/dsdb/samdb/ldb_modules/wscript             |   32 +
 source4/dsdb/samdb/ldb_modules/wscript_build       |   13 +
 .../dsdb/samdb/ldb_modules/wscript_build_server    |   17 +
 source4/dsdb/samdb/samdb.h                         |    1 +
 source4/selftest/tests.py                          |   17 +
 source4/setup/provision_init.ldif                  |    1 +
 19 files changed, 3304 insertions(+), 26 deletions(-)
 create mode 100644 python/samba/tests/encrypted_secrets.py
 create mode 100644 selftest/knownfail.d/encrypted_secrets
 create mode 100644 source4/dsdb/samdb/ldb_modules/encrypted_secrets.c
 create mode 100644 source4/dsdb/samdb/ldb_modules/tests/test_encrypted_secrets.c


Changeset truncated at 500 lines:

diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 257e087..9bcd03c 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -51,6 +51,39 @@ This can be set with the following settings:
 
   'mdns name = mdns'
 
+Encrypted secrets
+=================
+Attributes deemed to be sensitive are now encrypted on disk. The sensitive
+values are currently:
+	pekList
+	msDS-ExecuteScriptPassword
+	currentValue
+	dBCSPwd
+	initialAuthIncoming
+	initialAuthOutgoing
+	lmPwdHistory
+	ntPwdHistory
+	priorValue
+	supplementalCredentials
+	trustAuthIncoming
+	trustAuthOutgoing
+	unicodePwd
+	clearTextPassword
+
+This encryption is enabled by default on a new provision or join, it
+can be disabled at provision or join time with the new option
+--plaintext-secrets.
+
+However, an in-place upgrade will not encrypt the database.
+
+Once encrypted, it is not possible to do an in-place downgrade (eg to
+4.7) of the database. To obtain an unencrypted copy of the database a
+new DC join should be performed, specifying the --plaintext-secrets
+option.
+
+The key file "encrypted_secrets.key" is created in the same directory
+as the database and should NEVER be disclosed.  It is included by the
+samba_backup script.
 
 smb.conf changes
 ================
diff --git a/librpc/idl/drsblobs.idl b/librpc/idl/drsblobs.idl
index 9fca2cb..5fd11bb 100644
--- a/librpc/idl/drsblobs.idl
+++ b/librpc/idl/drsblobs.idl
@@ -721,4 +721,34 @@ interface drsblobs {
 	[nopython] void decode_ForestTrustInfo(
 		[in] ForestTrustInfo blob
 		);
+
+	typedef enum {
+		ENC_SECRET_AES_128_AEAD = 1
+	} EncryptedSecretAlgorithm;
+
+	const uint32 ENCRYPTED_SECRET_MAGIC_VALUE = 0xCA5CADED;
+
+	typedef [public] struct {
+		DATA_BLOB cleartext;
+	} PlaintextSecret;
+
+	/* The AEAD routines uses this as the additional authenticated data */
+	typedef [public] struct {
+		uint32 magic;
+		uint32 version;
+		uint32 algorithm;
+		uint32 flags;
+	} EncryptedSecretHeader;
+
+	typedef [public] struct {
+		/*
+		 * The iv is before the header to ensure that the first bytes of
+		 * the encrypted values are not predictable.
+		 * We do this so that if the decryption gets disabled, we don't
+		 * end up with predictable unicodePasswords.
+		 */
+		DATA_BLOB iv;
+		EncryptedSecretHeader header;
+		[flag(NDR_REMAINING)] DATA_BLOB encrypted;
+	} EncryptedSecret;
 }
diff --git a/python/pyglue.c b/python/pyglue.c
index d928b4c..68b14a0 100644
--- a/python/pyglue.c
+++ b/python/pyglue.c
@@ -89,6 +89,22 @@ static PyObject *py_check_password_quality(PyObject *self, PyObject *args)
 	return PyBool_FromLong(check_password_quality(pass));
 }
 
+static PyObject *py_generate_random_bytes(PyObject *self, PyObject *args)
+{
+	int len;
+	PyObject *ret;
+	uint8_t *bytes = NULL;
+
+	if (!PyArg_ParseTuple(args, "i", &len))
+		return NULL;
+
+	bytes = talloc_zero_size(NULL, len);
+	generate_random_buffer(bytes, len);
+	ret = PyBytes_FromStringAndSize((const char *)bytes, len);
+	talloc_free(bytes);
+	return ret;
+}
+
 static PyObject *py_unix2nttime(PyObject *self, PyObject *args)
 {
 	time_t t;
@@ -335,6 +351,11 @@ static PyMethodDef py_misc_methods[] = {
 		"is the NTVFS file server built in this installation?" },
 	{ "is_heimdal_built", (PyCFunction)py_is_heimdal_built, METH_NOARGS,
 		"is Samba built with Heimdal Kerberbos?" },
+	{ "generate_random_bytes",
+		(PyCFunction)py_generate_random_bytes,
+		METH_VARARGS,
+		"generate_random_bytes(len) -> bytes\n"
+		"Generate random bytes with specified length." },
 	{ NULL }
 };
 
diff --git a/python/samba/__init__.py b/python/samba/__init__.py
index 6ba7c99..f62f5e3 100644
--- a/python/samba/__init__.py
+++ b/python/samba/__init__.py
@@ -389,6 +389,7 @@ unix2nttime = _glue.unix2nttime
 generate_random_password = _glue.generate_random_password
 generate_random_machine_password = _glue.generate_random_machine_password
 check_password_quality = _glue.check_password_quality
+generate_random_bytes = _glue.generate_random_bytes
 strcasecmp_m = _glue.strcasecmp_m
 strstr_m = _glue.strstr_m
 is_ntvfs_fileserver_built = _glue.is_ntvfs_fileserver_built
diff --git a/python/samba/join.py b/python/samba/join.py
index 3aefb7b..63e9b90 100644
--- a/python/samba/join.py
+++ b/python/samba/join.py
@@ -55,7 +55,8 @@ class dc_join(object):
     def __init__(ctx, logger=None, server=None, creds=None, lp=None, site=None,
                  netbios_name=None, targetdir=None, domain=None,
                  machinepass=None, use_ntvfs=False, dns_backend=None,
-                 promote_existing=False, clone_only=False):
+                 promote_existing=False, clone_only=False,
+                 plaintext_secrets=False):
         if site is None:
             site = "Default-First-Site-Name"
 
@@ -67,6 +68,7 @@ class dc_join(object):
         ctx.site = site
         ctx.targetdir = targetdir
         ctx.use_ntvfs = use_ntvfs
+        ctx.plaintext_secrets = plaintext_secrets
 
         ctx.promote_existing = promote_existing
         ctx.promote_from_dn = None
@@ -837,7 +839,8 @@ class dc_join(object):
                 hostname=ctx.myname, domainsid=ctx.domsid,
                 machinepass=ctx.acct_pass, serverrole="active directory domain controller",
                 sitename=ctx.site, lp=ctx.lp, ntdsguid=ctx.ntds_guid,
-                use_ntvfs=ctx.use_ntvfs, dns_backend=ctx.dns_backend)
+                use_ntvfs=ctx.use_ntvfs, dns_backend=ctx.dns_backend,
+                plaintext_secrets=ctx.plaintext_secrets)
         print "Provision OK for domain DN %s" % presult.domaindn
         ctx.local_samdb = presult.samdb
         ctx.lp          = presult.lp
@@ -1398,11 +1401,12 @@ class dc_join(object):
 def join_RODC(logger=None, server=None, creds=None, lp=None, site=None, netbios_name=None,
               targetdir=None, domain=None, domain_critical_only=False,
               machinepass=None, use_ntvfs=False, dns_backend=None,
-              promote_existing=False):
+              promote_existing=False, plaintext_secrets=False):
     """Join as a RODC."""
 
     ctx = dc_join(logger, server, creds, lp, site, netbios_name, targetdir, domain,
-                  machinepass, use_ntvfs, dns_backend, promote_existing)
+                  machinepass, use_ntvfs, dns_backend, promote_existing,
+                  plaintext_secrets)
 
     lp.set("workgroup", ctx.domain_name)
     logger.info("workgroup is %s" % ctx.domain_name)
@@ -1449,10 +1453,11 @@ def join_RODC(logger=None, server=None, creds=None, lp=None, site=None, netbios_
 def join_DC(logger=None, server=None, creds=None, lp=None, site=None, netbios_name=None,
             targetdir=None, domain=None, domain_critical_only=False,
             machinepass=None, use_ntvfs=False, dns_backend=None,
-            promote_existing=False):
+            promote_existing=False, plaintext_secrets=False):
     """Join as a DC."""
     ctx = dc_join(logger, server, creds, lp, site, netbios_name, targetdir, domain,
-                  machinepass, use_ntvfs, dns_backend, promote_existing)
+                  machinepass, use_ntvfs, dns_backend, promote_existing,
+                  plaintext_secrets)
 
     lp.set("workgroup", ctx.domain_name)
     logger.info("workgroup is %s" % ctx.domain_name)
@@ -1498,10 +1503,10 @@ def join_clone(logger=None, server=None, creds=None, lp=None,
 def join_subdomain(logger=None, server=None, creds=None, lp=None, site=None,
         netbios_name=None, targetdir=None, parent_domain=None, dnsdomain=None,
         netbios_domain=None, machinepass=None, adminpass=None, use_ntvfs=False,
-        dns_backend=None):
+        dns_backend=None, plaintext_secrets=False):
     """Join as a DC."""
     ctx = dc_join(logger, server, creds, lp, site, netbios_name, targetdir, parent_domain,
-                  machinepass, use_ntvfs, dns_backend)
+                  machinepass, use_ntvfs, dns_backend, plaintext_secrets)
     ctx.subdomain = True
     if adminpass is None:
         ctx.adminpass = samba.generate_random_password(12, 32)
diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index 6f6ef61..6702bc3 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -247,6 +247,9 @@ class cmd_domain_provision(Command):
          Option("--ol-mmr-urls", type="string", metavar="LDAPSERVER",
                 help="List of LDAP-URLS [ ldap://<FQHN>:<PORT>/  (where <PORT> has to be different than 389!) ] separated with comma (\",\") for use with OpenLDAP-MMR (Multi-Master-Replication), e.g.: \"ldap://s4dc1:9000,ldap://s4dc2:9000\""),
          Option("--use-rfc2307", action="store_true", help="Use AD to store posix attributes (default = no)"),
+         Option("--plaintext-secrets", action="store_true",
+                help="Store secret/sensitive values as plain text on disk" +
+                     "(default is to encrypt secret/ensitive values)"),
         ]
 
     openldap_options = [
@@ -316,7 +319,8 @@ class cmd_domain_provision(Command):
             ldap_backend_extra_port=None,
             ldap_backend_forced_uri=None,
             ldap_dryrun_mode=None,
-            base_schema=None):
+            base_schema=None,
+            plaintext_secrets=False):
 
         self.logger = self.get_logger("provision")
         if quiet:
@@ -485,7 +489,8 @@ class cmd_domain_provision(Command):
                   ldap_backend_extra_port=ldap_backend_extra_port,
                   ldap_backend_forced_uri=ldap_backend_forced_uri,
                   nosync=ldap_backend_nosync, ldap_dryrun_mode=ldap_dryrun_mode,
-                  base_schema=base_schema)
+                  base_schema=base_schema,
+                  plaintext_secrets=plaintext_secrets)
 
         except ProvisioningError, e:
             raise CommandError("Provision failed", e)
@@ -638,6 +643,9 @@ class cmd_domain_join(Command):
                    "BIND9_DLZ uses samba4 AD to store zone information, "
                    "NONE skips the DNS setup entirely (this DC will not be a DNS server)",
                default="SAMBA_INTERNAL"),
+        Option("--plaintext-secrets", action="store_true",
+               help="Store secret/sensitive values as plain text on disk" +
+                    "(default is to encrypt secret/ensitive values)"),
         Option("--quiet", help="Be quiet", action="store_true"),
         Option("--verbose", help="Be verbose", action="store_true")
        ]
@@ -655,7 +663,7 @@ class cmd_domain_join(Command):
             versionopts=None, server=None, site=None, targetdir=None,
             domain_critical_only=False, parent_domain=None, machinepass=None,
             use_ntvfs=False, dns_backend=None, adminpass=None,
-            quiet=False, verbose=False):
+            quiet=False, verbose=False, plaintext_secrets=False):
         lp = sambaopts.get_loadparm()
         creds = credopts.get_credentials(lp)
         net = Net(creds, lp, server=credopts.ipaddress)
@@ -686,13 +694,16 @@ class cmd_domain_join(Command):
             join_DC(logger=logger, server=server, creds=creds, lp=lp, domain=domain,
                     site=site, netbios_name=netbios_name, targetdir=targetdir,
                     domain_critical_only=domain_critical_only,
-                    machinepass=machinepass, use_ntvfs=use_ntvfs, dns_backend=dns_backend)
+                    machinepass=machinepass, use_ntvfs=use_ntvfs,
+                    dns_backend=dns_backend,
+                    plaintext_secrets=plaintext_secrets)
         elif role == "RODC":
             join_RODC(logger=logger, server=server, creds=creds, lp=lp, domain=domain,
                       site=site, netbios_name=netbios_name, targetdir=targetdir,
                       domain_critical_only=domain_critical_only,
                       machinepass=machinepass, use_ntvfs=use_ntvfs,
-                      dns_backend=dns_backend)
+                      dns_backend=dns_backend,
+                      plaintext_secrets=plaintext_secrets)
         elif role == "SUBDOMAIN":
             if not adminpass:
                 logger.info("Administrator password will be set randomly!")
@@ -705,7 +716,8 @@ class cmd_domain_join(Command):
                            netbios_name=netbios_name, netbios_domain=netbios_domain,
                            targetdir=targetdir, machinepass=machinepass,
                            use_ntvfs=use_ntvfs, dns_backend=dns_backend,
-                           adminpass=adminpass)
+                           adminpass=adminpass,
+                           plaintext_secrets=plaintext_secrets)
         else:
             raise CommandError("Invalid role '%s' (possible values: MEMBER, DC, RODC, SUBDOMAIN)" % role)
 
diff --git a/python/samba/provision/__init__.py b/python/samba/provision/__init__.py
index 5de9864..cc654f3 100644
--- a/python/samba/provision/__init__.py
+++ b/python/samba/provision/__init__.py
@@ -29,6 +29,7 @@ __docformat__ = "restructuredText"
 from base64 import b64encode
 import errno
 import os
+import stat
 import re
 import pwd
 import grp
@@ -554,6 +555,9 @@ def provision_paths_from_lp(lp, dnsdomain):
     paths.kdcconf = os.path.join(paths.private_dir, "kdc.conf")
     paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
     paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
+    paths.encrypted_secrets_key_path = os.path.join(
+        paths.private_dir,
+        "encrypted_secrets.key")
 
     paths.dns = os.path.join(paths.binddns_dir, "dns", dnsdomain + ".zone")
     paths.namedconf = os.path.join(paths.binddns_dir, "named.conf")
@@ -792,7 +796,7 @@ def setup_name_mappings(idmap, sid, root_uid, nobody_uid,
 
 def setup_samdb_partitions(samdb_path, logger, lp, session_info,
                            provision_backend, names, serverrole,
-                           erase=False):
+                           erase=False, plaintext_secrets=False):
     """Setup the partitions for the SAM database.
 
     Alternatively, provision() may call this, and then populate the database.
@@ -821,6 +825,10 @@ def setup_samdb_partitions(samdb_path, logger, lp, session_info,
     if provision_backend.type != "ldb":
         ldap_backend_line = "ldapBackend: %s" % provision_backend.ldap_uri
 
+    required_features = "# No required features"
+    if not plaintext_secrets:
+        required_features = "requiredFeatures: encryptedSecrets"
+
     samdb.transaction_start()
     try:
         logger.info("Setting up sam.ldb partitions and settings")
@@ -831,7 +839,8 @@ def setup_samdb_partitions(samdb_path, logger, lp, session_info,
 
         setup_add_ldif(samdb, setup_path("provision_init.ldif"), {
                 "BACKEND_TYPE": provision_backend.type,
-                "SERVER_ROLE": serverrole
+                "SERVER_ROLE": serverrole,
+                "REQUIRED_FEATURES": required_features
                 })
 
         logger.info("Setting up sam.ldb rootDSE")
@@ -1006,6 +1015,30 @@ def setup_privileges(path, session_info, lp):
     privilege_ldb.erase()
     privilege_ldb.load_ldif_file_add(setup_path("provision_privilege.ldif"))
 
+def setup_encrypted_secrets_key(path):
+    """Setup the encrypted secrets key file.
+
+    Any existing key file will be deleted and a new random key generated.
+
+    :param path: Path to the secrets key file.
+
+    """
+    if os.path.exists(path):
+        os.unlink(path)
+
+    flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
+    mode = stat.S_IRUSR | stat.S_IWUSR
+
+    umask_original = os.umask(0)
+    try:
+        fd = os.open(path, flags, mode)
+    finally:
+        os.umask(umask_original)
+
+    with os.fdopen(fd, 'w') as f:
+        key = samba.generate_random_bytes(16)
+        f.write(key)
+
 
 def setup_registry(path, session_info, lp):
     """Setup the registry.
@@ -1193,7 +1226,8 @@ def create_default_gpo(sysvolpath, dnsdomain, policyguid, policyguid_dc):
 
 
 def setup_samdb(path, session_info, provision_backend, lp, names,
-        logger, fill, serverrole, schema, am_rodc=False):
+        logger, fill, serverrole, schema, am_rodc=False,
+        plaintext_secrets=False):
     """Setup a complete SAM Database.
 
     :note: This will wipe the main SAM database file!
@@ -1202,7 +1236,7 @@ def setup_samdb(path, session_info, provision_backend, lp, names,
     # Also wipes the database
     setup_samdb_partitions(path, logger=logger, lp=lp,
         provision_backend=provision_backend, session_info=session_info,
-        names=names, serverrole=serverrole)
+        names=names, serverrole=serverrole, plaintext_secrets=plaintext_secrets)
 
     # Load the database, but don's load the global schema and don't connect
     # quite yet
@@ -1975,7 +2009,8 @@ def provision(logger, session_info, smbconf=None,
         useeadb=False, am_rodc=False, lp=None, use_ntvfs=False,
         use_rfc2307=False, maxuid=None, maxgid=None, skip_sysvolacl=True,
         ldap_backend_forced_uri=None, nosync=False, ldap_dryrun_mode=False,
-        ldap_backend_extra_port=None, base_schema=None):
+        ldap_backend_extra_port=None, base_schema=None,
+        plaintext_secrets=False):
     """Provision samba4
 
     :note: caution, this wipes all existing data!
@@ -2101,6 +2136,8 @@ def provision(logger, session_info, smbconf=None,
     directory_create_or_exists(paths.binddns_dir, 0o770)
     directory_create_or_exists(os.path.join(paths.private_dir, "tls"))
     directory_create_or_exists(paths.state_dir)
+    if not plaintext_secrets:
+        setup_encrypted_secrets_key(paths.encrypted_secrets_key_path)
 
     if paths.sysvol and not os.path.exists(paths.sysvol):
         os.makedirs(paths.sysvol, 0775)
@@ -2172,7 +2209,8 @@ def provision(logger, session_info, smbconf=None,
         samdb = setup_samdb(paths.samdb, session_info,
                             provision_backend, lp, names, logger=logger,
                             serverrole=serverrole,
-                            schema=schema, fill=samdb_fill, am_rodc=am_rodc)
+                            schema=schema, fill=samdb_fill, am_rodc=am_rodc,
+                            plaintext_secrets=plaintext_secrets)
 
         if serverrole == "active directory domain controller":
             if paths.netlogon is None:
diff --git a/python/samba/tests/encrypted_secrets.py b/python/samba/tests/encrypted_secrets.py
new file mode 100644
index 0000000..3b6934f
--- /dev/null
+++ b/python/samba/tests/encrypted_secrets.py
@@ -0,0 +1,83 @@
+# Unix SMB/CIFS implementation.
+#
+#   Copyright (C) Andrew Bartlett <abartlet at samba.org> 2017
+#
+# 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/>.
+#
+
+"""Smoke test for encrypted secrets
+
+A quick test to confirm that the secret attributes are being stored
+encrypted on disk.
+"""
+
+
+import os
+import ldb
+import samba
+from samba.tests import TestCase
+from samba.credentials import Credentials
+from samba.samdb import SamDB
+from samba.auth import system_session
+from samba.ndr import ndr_unpack
+from samba.dcerpc import drsblobs
+
+
+class EncryptedSecretsTests(TestCase):
+
+    def setUp(self):
+        super(EncryptedSecretsTests, self).setUp()
+        self.lp = samba.tests.env_loadparm()
+        self.creds = Credentials()
+        self.session = system_session()
+        self.creds.guess(self.lp)
+        self.session = system_session()
+        self.ldb = SamDB(session_info=self.session,
+                         credentials=self.creds,
+                         lp=self.lp)
+
+    def test_encrypted_secrets(self):
+        """Test that secret attributes are stored encrypted on disk"""
+        basedn = self.ldb.domain_dn()
+        backend_filename = "%s.ldb" % basedn.upper()
+        backend_subpath = os.path.join("sam.ldb.d",
+                                       backend_filename)
+        backend_path = self.lp.private_path(backend_subpath)
+        backenddb = ldb.Ldb(backend_path)
+
+        dn = "CN=Administrator,CN=Users,%s" % basedn
+
+        res = backenddb.search(scope=ldb.SCOPE_BASE,
+                               base=dn,
+                               attrs=["unicodePwd"])
+        self.assertIs(True, len(res) > 0)
+        obj = res[0]
+        blob = obj["unicodePwd"][0]
+        self.assertTrue(len(blob) > 30)
+        # Now verify that the header contains the correct magic value.
+        encrypted = ndr_unpack(drsblobs.EncryptedSecret, blob)
+        magic = 0xca5caded
+        self.assertEquals(magic, encrypted.header.magic)
+
+    def test_required_features(self):


-- 
Samba Shared Repository



More information about the samba-cvs mailing list