[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Mon Mar 1 04:57:02 UTC 2021


The branch, master has been updated
       via  1c3e7f0f4de Suggest running './configure' rather than 'waf configure'.
       via  309c81e7e2a daemons: Do not notify systemd in child processes started by main samba
       via  65f21ed5e46 lib:util: Move variable initialization out of conditional compilation block
       via  f13b1da0466 test: samba-tool user show: Test ';format=[GeneralizedTime,UnixTime,TimeSpec] attributes
       via  c6a570004d9 samba-tool user: add ';format=[GeneralizedTime,UnixTime,TimeSpec]' support in "samba-tool user show"
       via  4d0491324a6 samba-tool user: add ';format=[GeneralizedTime,UnixTime,TimeSpec]' support
       via  98ee82d4fc8 samba-tool user: use an implicit_attrs list instead of add_ATTR variables
       via  06851084cac pyglue: add float2nttime() and nttime2float()
       via  71e8b24b8a0 pyldb: catch potential overflow error in py_timestring
       via  fdc44a14e47 samba-tool user: use remote domain information
       via  26f63e648ae samba-tool user: fix some typos
       via  3174c6dd418 s4:dsdb/dirsync: fix a typo in a comment
       via  485743dac38 s3:libsmb: fix a typo in a comment
       via  bb00979c081 selftest: fix typos in README files
      from  d6ddb8aa2a9 vfs: update status of SMB_VFS_LISTXATTR

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


- Log -----------------------------------------------------------------
commit 1c3e7f0f4de105abfde74778bfea9d5cc9be8c8e
Author: Jelmer Vernooij <jelmer at jelmer.uk>
Date:   Sat Feb 27 16:49:38 2021 +0000

    Suggest running './configure' rather than 'waf configure'.
    
    waf actively discourages system-wide waf installs, so the latter is unlikely
    to work.
    
    Signed-off-by: Jelmer Vernooij <jelmer at jelmer.uk>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Mon Mar  1 04:56:15 UTC 2021 on sn-devel-184

commit 309c81e7e2a124982cf1ab961070f7c0420b5ae7
Author: Samuel Cabrero <scabrero at samba.org>
Date:   Fri Feb 26 10:36:02 2021 +0100

    daemons: Do not notify systemd in child processes started by main samba
    
    When samba runs as ADDC only the main 'samba' daemon have to notify
    its status to systemd because our systemd unit files contains implied
    NotifyAccess=main since commit d1740fb3d5a72cb49e30b330bb0b01e7ef3e09cc.
    
    This commit adds a function to disable the systemd notification in the
    smbd and winbinddd child processes started by the main 'samba' daemon in
    AD DC mode to avoid warnings like:
    
    systemd[1]: samba-ad-dc.service: Got notification message from PID 26194,
    	    but reception only permitted for main PID 26187
    systemd[1]: samba-ad-dc.service: Got notification message from PID 26222,
    	    but reception only permitted for main PID 26187
    
    $ pstree -p
    ...
    ├─samba(26187)─┬─tfork(26189)(26188)───s3fs[master](26189)───tfork(26194)(26193)───smbd(26194)─┬─cleanupd(+
    │              │                                                                               ├─lpqd(2623+
    │              │                                                                               └─smbd-noti+
    │              ├─tfork(26191)(26190)───rpc[master](26191)─┬─tfork(26198)(26195)───rpc(0)(26198)
    │              │                                          ├─tfork(26200)(26199)───rpc(1)(26200)
    │              │                                          ├─tfork(26206)(26201)───rpc(2)(26206)
    │              │                                          └─tfork(26212)(26207)───rpc(3)(26212)
    │              ├─tfork(26196)(26192)───nbt[master](26196)
    │              ├─tfork(26202)(26197)───wrepl[master](26202)
    │              ├─tfork(26204)(26203)───ldap[master](26204)─┬─tfork(26242)(26241)───ldap(0)(26242)
    │              │                                           ├─tfork(26244)(26243)───ldap(1)(26244)
    │              │                                           ├─tfork(26246)(26245)───ldap(2)(26246)
    │              │                                           └─tfork(26248)(26247)───ldap(3)(26248)
    │              ├─tfork(26208)(26205)───cldap[master](26208)
    │              ├─tfork(26210)(26209)───kdc[master](26210)───tfork(26218)(26215)───krb5kdc(26218)
    │              ├─tfork(26213)(26211)───drepl[master](26213)
    │              ├─tfork(26216)(26214)───winbindd[master(26216)───tfork(26222)(26219)───winbindd(26222)───wi+
    │              ├─tfork(26220)(26217)───ntp_signd[maste(26220)
    │              ├─tfork(26223)(26221)───kcc[master](26223)
    │              ├─tfork(26225)(26224)───dnsupdate[maste(26225)
    │              └─tfork(26227)(26226)───dns[master](26227)
    
    Signed-off-by: Samuel Cabrero <scabrero at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 65f21ed5e463770ddb9d595de5e5e7047b3884ef
Author: Samuel Cabrero <scabrero at suse.de>
Date:   Thu Feb 25 17:13:46 2021 +0100

    lib:util: Move variable initialization out of conditional compilation block
    
    Signed-off-by: Samuel Cabrero <scabrero at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit f13b1da0466a77c7e7ede406bc1e5be168a9aec1
Author: Björn Baumbach <bb at sernet.de>
Date:   Wed Jan 20 16:10:48 2021 +0100

    test: samba-tool user show: Test ';format=[GeneralizedTime,UnixTime,TimeSpec] attributes
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit c6a570004d9b31e154dfbc1a08d1aa983d22173e
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jan 19 11:47:02 2021 +0100

    samba-tool user: add ';format=[GeneralizedTime,UnixTime,TimeSpec]' support in "samba-tool user show"
    
    This is useful to convert various time values to other formats.
    
    Pair-Programmed-With: Björn Baumbach <bb at sernet.de>
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 4d0491324a60f1fbd3f739e607c68fe460802db4
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jan 19 11:47:20 2021 +0100

    samba-tool user: add ';format=[GeneralizedTime,UnixTime,TimeSpec]' support
    
    These are useful to convert various time values to other formats.
    
    Pair-Programmed-With: Björn Baumbach <bb at sernet.de>
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 98ee82d4fc89bdea316b02fc066e26f9fa6f1f97
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jan 18 15:51:37 2021 +0100

    samba-tool user: use an implicit_attrs list instead of add_ATTR variables
    
    We'll extent GetPasswordCommand.get_password_attributes() to handle
    more virtual formats in future. It'll be much easier to
    to maintain a list of attributes we need to filter out again.
    
    sAMAccountName and userPrincipalName are always implicitly
    requested in order to keep the existing code sane.
    
    supplementalCredentials and unicodePwd are requested by default
    when generating virtual password attributes.
    
    Pair-Programmed-With: Björn Baumbach <bb at sernet.de>
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 06851084cac3cfeab08ddb89d48dded4c0d50156
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Dec 2 15:42:10 2020 +0100

    pyglue: add float2nttime() and nttime2float()
    
    The float value is what the native python time.time()
    returns, it's basically a struct timespec converted to
    double/float.
    
    Pair-Programmed-With: Björn Baumbach <bb at sernet.de>
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 71e8b24b8a031de26b21539e36a60f459257d2fd
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jan 19 16:53:55 2021 +0100

    pyldb: catch potential overflow error in py_timestring
    
    Pair-Programmed-With: Björn Baumbach <bb at sernet.de>
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit fdc44a14e470df785a39bbf15691b443284a7c4d
Author: Björn Baumbach <bb at sernet.de>
Date:   Tue Jan 19 10:53:48 2021 +0100

    samba-tool user: use remote domain information
    
    Required, when running get_account_attributes() against a remote samdb.
    
    avoid:
    ERROR(<class 'AttributeError'>): uncaught exception - 'NoneType' object has no attribute 'get'
      File "bin/python/samba/netcmd/__init__.py", line 186, in _run
        return self.run(*args, **kwargs)
      File "bin/python/samba/netcmd/user.py", line 2769, in run
        obj = self.get_account_attributes(samdb, username,
      File "bin/python/samba/netcmd/user.py", line 1250, in get_account_attributes
        realm = self.lp.get("realm")
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 26f63e648ae102a0b305b2db45ffd89b60af4ff7
Author: Björn Baumbach <bb at sernet.de>
Date:   Tue Jan 19 18:04:38 2021 +0100

    samba-tool user: fix some typos
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 3174c6dd4181030086351c21b54d4854498788ae
Author: Björn Baumbach <bb at sernet.de>
Date:   Thu Jan 21 13:20:17 2021 +0100

    s4:dsdb/dirsync: fix a typo in a comment
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 485743dac38bc074ed72db423fe0886f34faf150
Author: Björn Baumbach <bb at sernet.de>
Date:   Thu Jan 21 13:18:41 2021 +0100

    s3:libsmb: fix a typo in a comment
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit bb00979c081f5eaba1ccc4ae0b7439708276c835
Author: Björn Baumbach <bb at sernet.de>
Date:   Thu Jan 21 13:16:34 2021 +0100

    selftest: fix typos in README files
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

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

Summary of changes:
 buildtools/wafsamba/samba_wildcard.py    |   2 +-
 lib/ldb/common/ldb_msg.c                 |   1 +
 lib/ldb/pyldb.c                          |   7 +
 lib/ldb/tests/python/api.py              |  19 ++
 lib/util/become_daemon.c                 |  31 ++-
 lib/util/become_daemon.h                 |  12 +
 python/pyglue.c                          |  47 ++++
 python/samba/__init__.py                 |   2 +
 python/samba/netcmd/user.py              | 444 +++++++++++++++++++++++--------
 python/samba/tests/glue.py               |  19 ++
 python/samba/tests/samba_tool/user.py    | 132 +++++++++
 selftest/flapping.d/README               |   2 +-
 selftest/knownfail.d/README              |   2 +-
 source3/libsmb/libsmb_dir.c              |   2 +-
 source3/smbd/server.c                    |  13 +-
 source3/winbindd/winbindd.c              |  13 +-
 source4/dsdb/samdb/ldb_modules/dirsync.c |   4 +-
 17 files changed, 616 insertions(+), 136 deletions(-)


Changeset truncated at 500 lines:

diff --git a/buildtools/wafsamba/samba_wildcard.py b/buildtools/wafsamba/samba_wildcard.py
index 5d85ec0f2ac..1ea2803d5ca 100644
--- a/buildtools/wafsamba/samba_wildcard.py
+++ b/buildtools/wafsamba/samba_wildcard.py
@@ -136,7 +136,7 @@ def fake_build_environment(info=True, flush=False):
     try:
         proj = ConfigSet.ConfigSet(Options.lockfile)
     except IOError:
-        raise Errors.WafError("Project not configured (run 'waf configure' first)")
+        raise Errors.WafError("Project not configured (run './configure' first)")
 
     bld.load_envs()
 
diff --git a/lib/ldb/common/ldb_msg.c b/lib/ldb/common/ldb_msg.c
index 2346e66ec39..0179c35659b 100644
--- a/lib/ldb/common/ldb_msg.c
+++ b/lib/ldb/common/ldb_msg.c
@@ -1270,6 +1270,7 @@ char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
 
 	if (r != 17) {
 		talloc_free(ts);
+		errno = EOVERFLOW;
 		return NULL;
 	}
 
diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index 813cdb0870e..7802757eb78 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -4192,6 +4192,13 @@ static PyObject *py_timestring(PyObject *module, PyObject *args)
 	if (!PyArg_ParseTuple(args, "l", &t_val))
 		return NULL;
 	tresult = ldb_timestring(NULL, (time_t) t_val);
+	if (tresult == NULL) {
+		/*
+		 * Most likely EOVERFLOW from gmtime()
+		 */
+		PyErr_SetFromErrno(PyExc_OSError);
+		return NULL;
+	}
 	ret = PyUnicode_FromString(tresult);
 	talloc_free(tresult);
 	return ret;
diff --git a/lib/ldb/tests/python/api.py b/lib/ldb/tests/python/api.py
index 5198f3fbbb5..940c9051932 100755
--- a/lib/ldb/tests/python/api.py
+++ b/lib/ldb/tests/python/api.py
@@ -5,10 +5,12 @@
 import os
 from unittest import TestCase
 import sys
+sys.path.insert(0, "bin/python")
 import gc
 import time
 import ldb
 import shutil
+import errno
 
 
 TDB_PREFIX = "tdb://"
@@ -41,10 +43,27 @@ class NoContextTests(TestCase):
         self.assertEqual("19700101000000.0Z", ldb.timestring(0))
         self.assertEqual("20071119191012.0Z", ldb.timestring(1195499412))
 
+        self.assertEqual("00000101000000.0Z", ldb.timestring(-62167219200))
+        self.assertEqual("99991231235959.0Z", ldb.timestring(253402300799))
+
+        # should result with OSError EOVERFLOW from gmtime()
+        with self.assertRaises(OSError) as err:
+            ldb.timestring(-62167219201)
+        self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+        with self.assertRaises(OSError) as err:
+            ldb.timestring(253402300800)
+        self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+        with self.assertRaises(OSError) as err:
+            ldb.timestring(0x7fffffffffffffff)
+        self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+
     def test_string_to_time(self):
         self.assertEqual(0, ldb.string_to_time("19700101000000.0Z"))
         self.assertEqual(1195499412, ldb.string_to_time("20071119191012.0Z"))
 
+        self.assertEqual(-62167219200, ldb.string_to_time("00000101000000.0Z"))
+        self.assertEqual(253402300799, ldb.string_to_time("99991231235959.0Z"))
+
     def test_binary_encode(self):
         encoded = ldb.binary_encode(b'test\\x')
         decoded = ldb.binary_decode(encoded)
diff --git a/lib/util/become_daemon.c b/lib/util/become_daemon.c
index 89991b7981c..800a57437cc 100644
--- a/lib/util/become_daemon.c
+++ b/lib/util/become_daemon.c
@@ -33,6 +33,18 @@
 
 #include "become_daemon.h"
 
+static bool sd_notifications = true;
+
+/*******************************************************************
+ Enable or disable daemon status systemd notifications
+********************************************************************/
+void daemon_sd_notifications(bool enable)
+{
+	sd_notifications = enable;
+	DBG_DEBUG("Daemon status systemd notifications %s\n",
+		  sd_notifications ? "enabled" : "disabled");
+}
+
 /*******************************************************************
  Close the low 3 fd's and open dev/null in their place.
 ********************************************************************/
@@ -76,7 +88,7 @@ void become_daemon(bool do_fork, bool no_session, bool log_stdout)
 			_exit(0);
 		}
 #if defined(HAVE_LIBSYSTEMD_DAEMON) || defined(HAVE_LIBSYSTEMD)
-	} else {
+	} else if (sd_notifications) {
 		sd_notify(0, "STATUS=Starting process...");
 #endif
 	}
@@ -108,15 +120,17 @@ void become_daemon(bool do_fork, bool no_session, bool log_stdout)
 
 void exit_daemon(const char *msg, int error)
 {
-#if defined(HAVE_LIBSYSTEMD_DAEMON) || defined(HAVE_LIBSYSTEMD)
 	if (msg == NULL) {
 		msg = strerror(error);
 	}
 
-	sd_notifyf(0, "STATUS=daemon failed to start: %s\n"
+#if defined(HAVE_LIBSYSTEMD_DAEMON) || defined(HAVE_LIBSYSTEMD)
+	if (sd_notifications) {
+		sd_notifyf(0, "STATUS=daemon failed to start: %s\n"
 				  "ERRNO=%i",
 				  msg,
 				  error);
+	}
 #endif
 	DBG_ERR("daemon failed to start: %s, error code %d\n",
 		msg, error);
@@ -129,8 +143,11 @@ void daemon_ready(const char *daemon)
 		daemon = "Samba";
 	}
 #if defined(HAVE_LIBSYSTEMD_DAEMON) || defined(HAVE_LIBSYSTEMD)
-	sd_notifyf(0, "READY=1\nSTATUS=%s: ready to serve connections...",
-		   daemon);
+	if (sd_notifications) {
+		sd_notifyf(0,
+			   "READY=1\nSTATUS=%s: ready to serve connections...",
+			   daemon);
+	}
 #endif
 	DBG_ERR("daemon '%s' finished starting up and ready to serve "
 		"connections\n", daemon);
@@ -142,7 +159,9 @@ void daemon_status(const char *daemon, const char *msg)
 		daemon = "Samba";
 	}
 #if defined(HAVE_LIBSYSTEMD_DAEMON) || defined(HAVE_LIBSYSTEMD)
-	sd_notifyf(0, "STATUS=%s: %s", daemon, msg);
+	if (sd_notifications) {
+		sd_notifyf(0, "STATUS=%s: %s", daemon, msg);
+	}
 #endif
 	DBG_ERR("daemon '%s' : %s\n", daemon, msg);
 }
diff --git a/lib/util/become_daemon.h b/lib/util/become_daemon.h
index d697a689cdc..149d4c0175e 100644
--- a/lib/util/become_daemon.h
+++ b/lib/util/become_daemon.h
@@ -41,6 +41,18 @@
 **/
 void close_low_fds(bool stdin_too, bool stdout_too, bool stderr_too);
 
+/**
+ * @brief Enable or disable daemon status systemd notifications
+ *
+ * When samba runs as AD DC only the main 'samba' process has to
+ * notify systemd. Child processes started by the main 'samba', like
+ * smbd and winbindd should call this function to disable sd_notify()
+ * calls.
+ *
+ * @param[in] enable True to enable notifications, false to disable
+**/
+void daemon_sd_notifications(bool enable);
+
 /**
  * @brief Become a daemon, optionally discarding the controlling terminal
  *
diff --git a/python/pyglue.c b/python/pyglue.c
index 156eaf73150..ed79df10be2 100644
--- a/python/pyglue.c
+++ b/python/pyglue.c
@@ -134,6 +134,49 @@ static PyObject *py_nttime2unix(PyObject *self, PyObject *args)
 	return PyLong_FromLong((uint64_t)t);
 }
 
+static PyObject *py_float2nttime(PyObject *self, PyObject *args)
+{
+	double ft = 0;
+	double ft_sec = 0;
+	double ft_nsec = 0;
+	struct timespec ts;
+	NTTIME nt = 0;
+
+	if (!PyArg_ParseTuple(args, "d", &ft)) {
+		return NULL;
+	}
+
+	ft_sec = (double)(int)ft;
+	ft_nsec = (ft - ft_sec) * 1.0e+9;
+
+	ts.tv_sec = (int)ft_sec;
+	ts.tv_nsec = (int)ft_nsec;
+
+	nt = full_timespec_to_nt_time(&ts);
+
+	return PyLong_FromLongLong((uint64_t)nt);
+}
+
+static PyObject *py_nttime2float(PyObject *self, PyObject *args)
+{
+	double ft = 0;
+	struct timespec ts;
+	const struct timespec ts_zero = { .tv_sec = 0, };
+	NTTIME nt = 0;
+
+	if (!PyArg_ParseTuple(args, "K", &nt)) {
+		return NULL;
+	}
+
+	ts = nt_time_to_full_timespec(nt);
+	if (is_omit_timespec(&ts)) {
+		return PyFloat_FromDouble(1.0);
+	}
+	ft = timespec_elapsed2(&ts_zero, &ts);
+
+	return PyFloat_FromDouble(ft);
+}
+
 static PyObject *py_nttime2string(PyObject *self, PyObject *args)
 {
 	PyObject *ret;
@@ -374,6 +417,10 @@ static PyMethodDef py_misc_methods[] = {
 		"unix2nttime(timestamp) -> nttime" },
 	{ "nttime2unix", (PyCFunction)py_nttime2unix, METH_VARARGS,
 		"nttime2unix(nttime) -> timestamp" },
+	{ "float2nttime", (PyCFunction)py_float2nttime, METH_VARARGS,
+		"pytime2nttime(floattimestamp) -> nttime" },
+	{ "nttime2float", (PyCFunction)py_nttime2float, METH_VARARGS,
+		"nttime2pytime(nttime) -> floattimestamp" },
 	{ "nttime2string", (PyCFunction)py_nttime2string, METH_VARARGS,
 		"nttime2string(nttime) -> string" },
 	{ "set_debug_level", (PyCFunction)py_set_debug_level, METH_VARARGS,
diff --git a/python/samba/__init__.py b/python/samba/__init__.py
index fa047a813e2..cabae4eaf1f 100644
--- a/python/samba/__init__.py
+++ b/python/samba/__init__.py
@@ -368,6 +368,8 @@ fault_setup = _glue.fault_setup
 set_debug_level = _glue.set_debug_level
 get_debug_level = _glue.get_debug_level
 unix2nttime = _glue.unix2nttime
+float2nttime = _glue.float2nttime
+nttime2float = _glue.nttime2float
 nttime2string = _glue.nttime2string
 nttime2unix = _glue.nttime2unix
 unix2nttime = _glue.unix2nttime
diff --git a/python/samba/netcmd/user.py b/python/samba/netcmd/user.py
index bbfa7e989dd..4d181ea793b 100644
--- a/python/samba/netcmd/user.py
+++ b/python/samba/netcmd/user.py
@@ -44,6 +44,7 @@ from samba import (
     gensec,
     generate_random_password,
     Ldb,
+    nttime2float,
 )
 from samba.net import Net
 
@@ -152,27 +153,6 @@ def get_crypt_value(alg, utf8pw, rounds=0):
             crypt_salt, len(crypt_value), expected_len))
     return crypt_value
 
-# Extract the rounds value from the options of a virtualCrypt attribute
-# i.e. options = "rounds=20;other=ignored;" will return 20
-# if the rounds option is not found or the value is not a number, 0 is returned
-# which indicates that the default number of rounds should be used.
-
-
-def get_rounds(options):
-    if not options:
-        return 0
-
-    opts = options.split(';')
-    for o in opts:
-        if o.lower().startswith("rounds="):
-            (key, _, val) = o.partition('=')
-            try:
-                return int(val)
-            except ValueError:
-                return 0
-    return 0
-
-
 try:
     import hashlib
     h = hashlib.sha1()
@@ -1109,6 +1089,13 @@ class GetPasswordCommand(Command):
         super(GetPasswordCommand, self).__init__()
         self.lp = None
 
+    def inject_virtual_attributes(self, samdb):
+        # We use sort here in order to have a predictable processing order
+        # this might not be strictly needed, but also doesn't hurt here
+        for a in sorted(virtual_attributes.keys()):
+            flags = ldb.ATTR_FLAG_HIDDEN | virtual_attributes[a].get("flags", 0)
+            samdb.schema_attribute_add(a, flags, ldb.SYNTAX_OCTET_STRING)
+
     def connect_system_samdb(self, url, allow_local=False, verbose=False):
 
         # using anonymous here, results in no authentication
@@ -1148,55 +1135,110 @@ class GetPasswordCommand(Command):
             raise CommandError("You need to specify an URL that gives privileges as SID_NT_SYSTEM(%s)" %
                                (security.SID_NT_SYSTEM))
 
-        # We use sort here in order to have a predictable processing order
-        # this might not be strictly needed, but also doesn't hurt here
-        for a in sorted(virtual_attributes.keys()):
-            flags = ldb.ATTR_FLAG_HIDDEN | virtual_attributes[a].get("flags", 0)
-            samdb.schema_attribute_add(a, flags, ldb.SYNTAX_OCTET_STRING)
+        self.inject_virtual_attributes(samdb)
 
         return samdb
 
     def get_account_attributes(self, samdb, username, basedn, filter, scope,
-                               attrs, decrypt):
+                               attrs, decrypt, support_pw_attrs=True):
+
+        def get_option(opts, name):
+            if not opts:
+                return None
+            for o in opts:
+                if o.lower().startswith("%s=" % name.lower()):
+                    (key, _, val) = o.partition('=')
+                    return val
+            return None
+
+        def get_virtual_attr_definition(attr):
+            for van in sorted(virtual_attributes.keys()):
+                if van.lower() != attr.lower():
+                    continue
+                return virtual_attributes[van]
+            return None
+
+        formats = [
+                "GeneralizedTime",
+                "UnixTime",
+                "TimeSpec",
+        ]
+
+        def get_virtual_format_definition(opts):
+            formatname = get_option(opts, "format")
+            if formatname is None:
+                return None
+            for fm in formats:
+                if fm.lower() != formatname.lower():
+                    continue
+                return fm
+            return None
+
+        def parse_raw_attr(raw_attr, is_hidden=False):
+            (attr, _, fullopts) = raw_attr.partition(';')
+            if fullopts:
+                opts = fullopts.split(';')
+            else:
+                opts = []
+            a = {}
+            a["raw_attr"] = raw_attr
+            a["attr"] = attr
+            a["opts"] = opts
+            a["vattr"] = get_virtual_attr_definition(attr)
+            a["vformat"] = get_virtual_format_definition(opts)
+            a["is_hidden"] = is_hidden
+            return a
 
         raw_attrs = attrs[:]
+        has_wildcard_attr = "*" in raw_attrs
+        has_virtual_attrs = False
+        requested_attrs = []
+        implicit_attrs = []
+
+        for raw_attr in raw_attrs:
+            a = parse_raw_attr(raw_attr)
+            requested_attrs.append(a)
+
         search_attrs = []
-        attr_opts = {}
-        for a in raw_attrs:
-            (attr, _, opts) = a.partition(';')
-            if opts:
-                attr_opts[attr] = opts
-            else:
-                attr_opts[attr] = None
-            search_attrs.append(attr)
-        lower_attrs = [x.lower() for x in search_attrs]
-
-        require_supplementalCredentials = False
-        for a in virtual_attributes.keys():
-            if a.lower() in lower_attrs:
-                require_supplementalCredentials = True
-        add_supplementalCredentials = False
-        add_unicodePwd = False
-        if require_supplementalCredentials:
-            a = "supplementalCredentials"
-            if a.lower() not in lower_attrs:
-                search_attrs += [a]
-                add_supplementalCredentials = True
-            a = "unicodePwd"
-            if a.lower() not in lower_attrs:
-                search_attrs += [a]
-                add_unicodePwd = True
-        add_sAMAcountName = False
-        a = "sAMAccountName"
-        if a.lower() not in lower_attrs:
-            search_attrs += [a]
-            add_sAMAcountName = True
-
-        add_userPrincipalName = False
-        upn = "userPrincipalName"
-        if upn.lower() not in lower_attrs:
-            search_attrs += [upn]
-            add_userPrincipalName = True
+        has_virtual_attrs = False
+        for a in requested_attrs:
+            if a["vattr"] is not None:
+                has_virtual_attrs = True
+                continue
+            if a["vformat"] is not None:
+                # also add it as implicit attr,
+                # where we just do
+                # search_attrs.append(a["attr"])
+                # later on
+                implicit_attrs.append(a)
+                continue
+            if a["raw_attr"] in search_attrs:
+                continue
+            search_attrs.append(a["raw_attr"])
+
+        if not has_wildcard_attr:
+            required_attrs = [
+                "sAMAccountName",
+                "userPrincipalName"
+            ]
+            for required_attr in required_attrs:
+                a = parse_raw_attr(required_attr)
+                implicit_attrs.append(a)
+
+        if has_virtual_attrs:
+            if support_pw_attrs:
+                required_attrs = [
+                    "supplementalCredentials",
+                    "unicodePwd",
+                ]
+                for required_attr in required_attrs:
+                    a = parse_raw_attr(required_attr, is_hidden=True)
+                    implicit_attrs.append(a)
+
+        for a in implicit_attrs:
+            if a["attr"] in search_attrs:
+                continue
+            search_attrs.append(a["attr"])
 
         if scope == ldb.SCOPE_BASE:
             search_controls = ["show_deleted:1", "show_recycled:1"]
@@ -1220,22 +1262,14 @@ class GetPasswordCommand(Command):
         if "supplementalCredentials" in obj:
             sc_blob = obj["supplementalCredentials"][0]
             sc = ndr_unpack(drsblobs.supplementalCredentialsBlob, sc_blob)
-            if add_supplementalCredentials:
-                del obj["supplementalCredentials"]
         if "unicodePwd" in obj:
             unicodePwd = obj["unicodePwd"][0]
-            if add_unicodePwd:
-                del obj["unicodePwd"]
         account_name = str(obj["sAMAccountName"][0])
-        if add_sAMAcountName:
-            del obj["sAMAccountName"]
         if "userPrincipalName" in obj:
             account_upn = str(obj["userPrincipalName"][0])
         else:
-            realm = self.lp.get("realm")
+            realm = samdb.domain_dns_name()
             account_upn = "%s@%s" % (account_name, realm.lower())
-        if add_userPrincipalName:
-            del obj["userPrincipalName"]
 
         calculated = {}
 
@@ -1262,7 +1296,7 @@ class GetPasswordCommand(Command):
             # Samba adds 'Primary:SambaGPG' at the end.
             # When Windows sets the password it keeps


-- 
Samba Shared Repository



More information about the samba-cvs mailing list