[SCM] Samba Shared Repository - branch master updated
Andrew Bartlett
abartlet at samba.org
Fri Mar 1 01:28:01 UTC 2024
The branch, master has been updated
via d6bfd26049b pytests: samba-tool domain kds root_key
via d0234391a8a samba-tool: add `samba-tool domain kds root_key delete`
via 710093dc279 samba-tool: add `samba-tool domain kds root_key create`
via ee1e9f1fb22 samba-tool: add `samba-tool domain kds root_key view`
via a92699cda06 samba-tool: add `samba-tool domain kds root_key list`
via 884d40ca165 samba-tool: don't error if there are no sub-commands
via 79342a8411d provision: add a default root key
via 53bf56c62b1 pytest:dsdb: check that there is a gkdi root key
via c6208a3b0ec pytest:gkdi: shift create_root_key into a function
via e1ab10b1fc1 pytest:samba-tool: add a flag to print more in runcmd
via ae0f38c319c samba-tool user delete: use account type constant
via e5efa217467 samba-tool domain: add LDB Result to json encoders
via bbd9249a9c2 ldb:pyldb exposes Result type
via 17dbaf4d330 python:samdb: wrapper for _dsdb_create_gkdi_root_key()
via a7c955dc7f9 s4:pydsdb: python bindings for gkdi_new_root_key()
via 214ac139d86 samba-tool domain kds root_key
via 327f5dc4e58 samba-tool domain kds: add root key sub-command
via fbd9740272e samba-tool domain: add kds sub-branch
via d46daab2aed s4:dsdb: Add functions for GKDI root key creation
via e7a96915e82 lib:crypto: Check for overflow in GKDI rollover interval calculation
via 2be2dca44a6 lib:crypto: Correct GKDI interval start time calculation
via 924eb6bac50 lib:crypto: Add error checking to GKDI key start time calculation
via 02f18a88dad selftest: Ignore msKds-DomainID in ldapcmp_restoredc.sh and samba.tests.domain_backup_offline
from 667265b6851 ctdb-tests: Limit red-black tree test to 5s of random inserts
https://git.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit d6bfd26049b954ff976a528818e1019c4414f8e6
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Fri Feb 16 16:36:06 2024 +1300
pytests: samba-tool domain kds root_key
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
Autobuild-Date(master): Fri Mar 1 01:27:30 UTC 2024 on atb-devel-224
commit d0234391a8a47f6f39f7965c03fbda8f61815251
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Wed Feb 28 17:55:54 2024 +1300
samba-tool: add `samba-tool domain kds root_key delete`
For deleting root keys.
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 710093dc27922c0e28a8950120821df6f853b3ee
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Wed Feb 28 17:55:16 2024 +1300
samba-tool: add `samba-tool domain kds root_key create`
For making new root keys.
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit ee1e9f1fb220fb3c2c3cf0c87b92900acb8e8909
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Wed Feb 28 17:54:24 2024 +1300
samba-tool: add `samba-tool domain kds root_key view`
This is for looking at one root key. There isn't much to know.
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit a92699cda06bf278d91c1351685613ccaa91cd9d
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Wed Feb 28 17:34:25 2024 +1300
samba-tool: add `samba-tool domain kds root_key list`
This lists root keys, in descending chronological order according to the
use_start_toime attribute. That's becuase you usually only care about
the newest one.
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 884d40ca16549d5a69119a2a2470ae4e45ee816a
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu Feb 29 16:29:30 2024 +1300
samba-tool: don't error if there are no sub-commands
This is useful when you commit samba-tool tests before you commit the
samba-tool code, and you want the tests to fail rather than error.
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 79342a8411d6e1534e03ce43be0506007959c115
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Wed Feb 28 15:28:22 2024 +1300
provision: add a default root key
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 53bf56c62b18da1bfd85099454ebc654ab738785
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Wed Feb 28 15:32:41 2024 +1300
pytest:dsdb: check that there is a gkdi root key
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit c6208a3b0ec1d8a6c76755d66846d28deb274123
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu Feb 22 16:17:37 2024 +1300
pytest:gkdi: shift create_root_key into a function
This is so the samba-tool domain kds root_key tests can use it as a
function.
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit e1ab10b1fc19ac35ea1dcaf0161d59d394fc363c
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Fri Feb 23 16:24:11 2024 +1300
pytest:samba-tool: add a flag to print more in runcmd
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit ae0f38c319c95817b8f51ce3b427821c53d9cb86
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Fri Feb 16 15:35:06 2024 +1300
samba-tool user delete: use account type constant
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit e5efa217467b5b9e582c62830a94712da7c0e840
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu Feb 22 16:16:17 2024 +1300
samba-tool domain: add LDB Result to json encoders
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit bbd9249a9c2eb574289ccc7a940646acb2035aaa
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu Feb 15 04:07:34 2024 +0000
ldb:pyldb exposes Result type
You perhaps never want to manually create results (as in `x = Result()`)
-- except maybe in tests -- and that would be why we never added it in
the first place (or rather, we never noticed that it ws missing).
But we do want to sometimes go `isinstance(x, ldb.Result)`, and that
is how we noticed it was missing now.
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 17dbaf4d330dd4d1940c37598d798b228c74149b
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Wed Feb 28 17:15:44 2024 +1300
python:samdb: wrapper for _dsdb_create_gkdi_root_key()
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit a7c955dc7f9c378a55443ff54c85bdcf79502ee1
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Wed Feb 28 17:15:09 2024 +1300
s4:pydsdb: python bindings for gkdi_new_root_key()
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 214ac139d86a5ab334c22216ab316e3ac9635dad
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu Feb 22 16:51:42 2024 +1300
samba-tool domain kds root_key
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 327f5dc4e58a250049d993a25e076c2563311aea
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Wed Feb 28 17:29:40 2024 +1300
samba-tool domain kds: add root key sub-command
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit fbd9740272eeabdc278e49c3af30862146a48168
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu Feb 22 16:51:56 2024 +1300
samba-tool domain: add kds sub-branch
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit d46daab2aed0d66c909285f3e0524ac1142d2ab2
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Feb 13 16:09:57 2024 +1300
s4:dsdb: Add functions for GKDI root key creation
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit e7a96915e8207f562000f60869e449ddf8bc915f
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Mon Feb 19 10:34:02 2024 +1300
lib:crypto: Check for overflow in GKDI rollover interval calculation
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 2be2dca44a6d602d41ae623d96ed3d12b7b43d4f
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Mon Feb 19 10:33:41 2024 +1300
lib:crypto: Correct GKDI interval start time calculation
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 924eb6bac50885a4d90cba227de569087185a06d
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Feb 13 13:04:48 2024 +1300
lib:crypto: Add error checking to GKDI key start time calculation
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 02f18a88dad8d8cc6b15fc8f2ebde2560741e265
Author: Andrew Bartlett <abartlet at samba.org>
Date: Fri Mar 1 12:14:58 2024 +1300
selftest: Ignore msKds-DomainID in ldapcmp_restoredc.sh and samba.tests.domain_backup_offline
Like serverReferenceBL etc, this will point to a DC that created the object, and
as part of the backup and restore, this DC will be deleted. It is just for
tracking the object creation, so this is fine.
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
-----------------------------------------------------------------------
Summary of changes:
lib/crypto/gkdi.c | 57 +-
lib/crypto/gkdi.h | 2 +-
lib/ldb/pyldb.c | 1 +
python/samba/netcmd/__init__.py | 2 +-
python/samba/netcmd/domain/__init__.py | 2 +
.../dcerpc => netcmd/domain/kds}/__init__.py | 20 +-
python/samba/netcmd/domain/kds/root_key.py | 440 +++++++++++++
python/samba/netcmd/encoders.py | 6 +-
python/samba/netcmd/user/delete.py | 5 +-
python/samba/provision/__init__.py | 4 +
python/samba/samdb.py | 6 +
python/samba/tests/domain_backup_offline.py | 2 +-
python/samba/tests/dsdb_quiet_provision_tests.py | 59 ++
python/samba/tests/gkdi.py | 291 +++++----
python/samba/tests/samba_tool/base.py | 22 +-
.../samba/tests/samba_tool/domain_kds_root_key.py | 717 +++++++++++++++++++++
source4/dsdb/gmsa/gkdi.c | 356 ++++++++++
source4/dsdb/gmsa/gkdi.h | 46 ++
source4/dsdb/pydsdb.c | 84 +++
source4/dsdb/samdb/samdb.h | 6 +
source4/dsdb/wscript_build | 4 +-
source4/selftest/tests.py | 5 +
testprogs/blackbox/ldapcmp_restoredc.sh | 6 +
23 files changed, 1991 insertions(+), 152 deletions(-)
copy python/samba/{tests/dcerpc => netcmd/domain/kds}/__init__.py (66%)
create mode 100644 python/samba/netcmd/domain/kds/root_key.py
create mode 100644 python/samba/tests/dsdb_quiet_provision_tests.py
create mode 100644 python/samba/tests/samba_tool/domain_kds_root_key.py
create mode 100644 source4/dsdb/gmsa/gkdi.c
create mode 100644 source4/dsdb/gmsa/gkdi.h
Changeset truncated at 500 lines:
diff --git a/lib/crypto/gkdi.c b/lib/crypto/gkdi.c
index 92348f286ac..af00ea4217e 100644
--- a/lib/crypto/gkdi.c
+++ b/lib/crypto/gkdi.c
@@ -175,11 +175,45 @@ struct Gkid gkdi_get_interval_id(const NTTIME time)
time / gkdi_key_cycle_duration % gkdi_l2_key_iteration);
}
-NTTIME gkdi_get_key_start_time(const struct Gkid gkid)
+bool gkdi_get_key_start_time(const struct Gkid gkid, NTTIME *start_time_out)
{
- return (gkid.l0_idx * gkdi_l1_key_iteration * gkdi_l2_key_iteration +
- gkid.l1_idx * gkdi_l2_key_iteration + gkid.l2_idx) *
- gkdi_key_cycle_duration;
+ if (!gkid_is_valid(gkid)) {
+ return false;
+ }
+
+ {
+ enum GkidType key_type = gkid_key_type(gkid);
+ if (key_type != GKID_L2_SEED_KEY) {
+ return false;
+ }
+ }
+
+ {
+ /*
+ * Make sure that the GKID is not so large its start time can’t
+ * be represented in NTTIME.
+ */
+ static const struct Gkid max_gkid = {
+ UINT64_MAX /
+ (gkdi_l1_key_iteration * gkdi_l2_key_iteration *
+ gkdi_key_cycle_duration),
+ UINT64_MAX /
+ (gkdi_l2_key_iteration *
+ gkdi_key_cycle_duration) %
+ gkdi_l1_key_iteration,
+ UINT64_MAX / gkdi_key_cycle_duration %
+ gkdi_l2_key_iteration};
+ if (!gkid_less_than_or_equal_to(gkid, max_gkid)) {
+ return false;
+ }
+ }
+
+ *start_time_out = ((uint64_t)gkid.l0_idx * gkdi_l1_key_iteration *
+ gkdi_l2_key_iteration +
+ (uint64_t)gkid.l1_idx * gkdi_l2_key_iteration +
+ (uint64_t)gkid.l2_idx) *
+ gkdi_key_cycle_duration;
+ return true;
}
/*
@@ -188,7 +222,7 @@ NTTIME gkdi_get_key_start_time(const struct Gkid gkid)
*/
NTTIME gkdi_get_interval_start_time(const NTTIME time)
{
- return time % gkdi_key_cycle_duration;
+ return time / gkdi_key_cycle_duration * gkdi_key_cycle_duration;
}
bool gkid_less_than_or_equal_to(const struct Gkid g1, const struct Gkid g2)
@@ -207,7 +241,18 @@ bool gkid_less_than_or_equal_to(const struct Gkid g1, const struct Gkid g2)
bool gkdi_rollover_interval(const int64_t managed_password_interval,
NTTIME *result)
{
- if (managed_password_interval < 0) {
+ /*
+ * This is actually a conservative reckoning. The interval could be one
+ * higher than this maximum and not overflow. But there’s no reason to
+ * support intervals that high (and Windows will start producing strange
+ * results for intervals beyond that).
+ */
+ const int64_t maximum_interval = UINT64_MAX / gkdi_key_cycle_duration *
+ 10 / 24;
+
+ if (managed_password_interval < 0 ||
+ managed_password_interval > maximum_interval)
+ {
return false;
}
diff --git a/lib/crypto/gkdi.h b/lib/crypto/gkdi.h
index 0786d228a19..244563d18b6 100644
--- a/lib/crypto/gkdi.h
+++ b/lib/crypto/gkdi.h
@@ -133,7 +133,7 @@ static const int64_t gkdi_max_clock_skew = 3000000000; /* five minutes */
struct Gkid gkdi_get_interval_id(const NTTIME time);
-NTTIME gkdi_get_key_start_time(const struct Gkid gkid);
+bool gkdi_get_key_start_time(const struct Gkid gkid, NTTIME *start_time_out);
NTTIME gkdi_get_interval_start_time(const NTTIME time);
diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index 23637a6b2a2..20b3c26f958 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -5019,6 +5019,7 @@ static PyObject* module_init(void)
PyModule_AddObject(m, "MessageElement", (PyObject *)&PyLdbMessageElement);
PyModule_AddObject(m, "Module", (PyObject *)&PyLdbModule);
PyModule_AddObject(m, "Tree", (PyObject *)&PyLdbTree);
+ PyModule_AddObject(m, "Result", (PyObject *)&PyLdbResult);
PyModule_AddObject(m, "Control", (PyObject *)&PyLdbControl);
PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
diff --git a/python/samba/netcmd/__init__.py b/python/samba/netcmd/__init__.py
index 01497055d68..e83c8390c55 100644
--- a/python/samba/netcmd/__init__.py
+++ b/python/samba/netcmd/__init__.py
@@ -428,7 +428,7 @@ class SuperCommand(Command):
epilog = "\nAvailable subcommands:\n"
subcmds = sorted(self.subcommands.keys())
- max_length = max([len(c) for c in subcmds])
+ max_length = max([len(c) for c in subcmds], default=0)
for cmd_name in subcmds:
cmd = self.subcommands[cmd_name]
if cmd.hidden:
diff --git a/python/samba/netcmd/domain/__init__.py b/python/samba/netcmd/domain/__init__.py
index 1c527f1baec..b9b31a5ae8e 100644
--- a/python/samba/netcmd/domain/__init__.py
+++ b/python/samba/netcmd/domain/__init__.py
@@ -36,6 +36,7 @@ from .demote import cmd_domain_demote
from .functional_prep import cmd_domain_functional_prep
from .info import cmd_domain_info
from .join import cmd_domain_join
+from .kds import cmd_domain_kds
from .keytab import cmd_domain_export_keytab
from .leave import cmd_domain_leave
from .level import cmd_domain_level
@@ -62,6 +63,7 @@ class cmd_domain(SuperCommand):
subcommands["demote"] = cmd_domain_demote()
subcommands["provision"] = cmd_domain_provision()
subcommands["dcpromo"] = cmd_domain_dcpromo()
+ subcommands["kds"] = cmd_domain_kds()
subcommands["level"] = cmd_domain_level()
subcommands["passwordsettings"] = cmd_domain_passwordsettings()
subcommands["classicupgrade"] = cmd_domain_classicupgrade()
diff --git a/python/samba/tests/dcerpc/__init__.py b/python/samba/netcmd/domain/kds/__init__.py
similarity index 66%
copy from python/samba/tests/dcerpc/__init__.py
copy to python/samba/netcmd/domain/kds/__init__.py
index b8df5a2c31f..3725725b2ba 100644
--- a/python/samba/tests/dcerpc/__init__.py
+++ b/python/samba/netcmd/domain/kds/__init__.py
@@ -1,7 +1,8 @@
-# -*- coding: utf-8 -*-
-#
# Unix SMB/CIFS implementation.
-# Copyright © Jelmer Vernooij <jelmer at samba.org> 2008
+#
+# samba-tool commands for Key Distribution Services
+#
+# Copyright © Catalyst.Net Ltd. 2024
#
# 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
@@ -15,5 +16,16 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from samba.netcmd import SuperCommand
+
+from .root_key import cmd_domain_kds_root_key
+
+
+class cmd_domain_kds(SuperCommand):
+ """Key Distribution Service management."""
-"""Tests for the DCE/RPC Python bindings."""
+ subcommands = {
+ "root-key": cmd_domain_kds_root_key(),
+ }
diff --git a/python/samba/netcmd/domain/kds/root_key.py b/python/samba/netcmd/domain/kds/root_key.py
new file mode 100644
index 00000000000..dcbdec27399
--- /dev/null
+++ b/python/samba/netcmd/domain/kds/root_key.py
@@ -0,0 +1,440 @@
+# Unix SMB/CIFS implementation.
+#
+# samba-tool commands for Key Distribution Services
+#
+# Copyright © Catalyst.Net Ltd. 2024
+#
+# 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 samba.getopt as options
+from ldb import SCOPE_SUBTREE
+from samba.netcmd import Command, CommandError, Option, SuperCommand
+from samba.dcerpc import misc
+from ldb import MessageElement, LdbError
+from samba import string_is_guid
+
+
+from samba.nt_time import (string_from_nt_time,
+ nt_time_from_string,
+ nt_now,
+ timedelta_from_nt_time_delta)
+
+
+def root_key_base_dn(ldb):
+ base_dn = ldb.get_config_basedn()
+ base_dn.add_child(
+ "CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services")
+ return base_dn
+
+
+def get_root_key_by_name_or_dn(ldb, name, attrs=None):
+ if string_is_guid(str(name)):
+ key = 'name'
+ else:
+ key = 'dn'
+
+ if attrs is None:
+ attrs = ['*']
+
+ base_dn = root_key_base_dn(ldb)
+
+ expression = ("(&(objectClass = msKds-ProvRootKey)"
+ f"({key} = {name}))")
+
+ res = ldb.search(base_dn,
+ scope=SCOPE_SUBTREE,
+ expression=expression,
+ attrs=attrs)
+
+ if len(res) == 0:
+ raise CommandError(f"no such root key: {name}")
+ if len(res) != 1:
+ # the database is in a sorry state
+ raise CommandError(f"duplicate root keys matching {name}")
+
+ return res[0]
+
+
+def get_sorted_root_keys(ldb, attrs=None, n=None):
+ if attrs is None:
+ attrs = ['*']
+
+ base_dn = root_key_base_dn(ldb)
+
+ res = ldb.search(base_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(objectClass = msKds-ProvRootKey)",
+ attrs=attrs,
+ controls=["server_sort:1:1:msKds-UseStartTime"])
+
+ return res
+
+
+def delta_string(d):
+ """Turn a datetime.timedelta into an approximate string."""
+ td = timedelta_from_nt_time_delta(d)
+ secs = td.total_seconds()
+ absolute = abs(secs)
+ if absolute < 2:
+ return 'about now'
+ s = 'about '
+ if absolute < 120:
+ s += f'{int(absolute)} seconds'
+ elif absolute < 7200:
+ s += f'{int(absolute / 60)} minutes'
+ elif absolute < 48 * 3600:
+ s += f'{int(absolute / 3600)} hours'
+ else:
+ s += f'{int(absolute / (24 * 3600))} days'
+
+ if secs <= 0:
+ s += ' ago'
+ else:
+ s += ' in the FUTURE'
+
+ return s
+
+
+# These next ridiculously simple looking functions are for the
+# ENCODERS mapping below.
+
+def guid_to_string(v):
+ return str(misc.GUID(v))
+
+
+def string_from_nt_time_string(nt_time):
+ nt_time = int(nt_time)
+ return string_from_nt_time(nt_time)
+
+
+# ENCODERS is a mapping of attribute names to encoding functions for
+# the corresponding values. Anything not mentioned will go through
+# str(), which for MessageElements is the same as bytes.decode().
+ENCODERS = {
+ "msKds-UseStartTime": string_from_nt_time_string,
+ "msKds-CreateTime": string_from_nt_time_string,
+ "msKds-RootKeyData": bytes.hex,
+ "msKds-SecretAgreementParam": bytes.hex,
+ "objectGUID": guid_to_string,
+ "msKds-KDFParam": bytes.hex,
+ "msKds-PublicKeyLength": int,
+ "msKds-PrivateKeyLength": int,
+ "msKds-Version": int,
+}
+
+
+def encode_by_key(k, v):
+ """Convert an attribute into a printable form, using the the attribute
+ name to guess the best format."""
+ fn = ENCODERS.get(k, lambda x: str(x))
+
+ if not isinstance(v, MessageElement): # probably Dn
+ return fn(v)
+
+ if len(v) == 1:
+ return fn(v[0])
+
+ return [fn(x) for x in v]
+
+
+# these attributes we normally wany to show. 'name' is a GUID string
+# (and has the same value as cn, the rdn).
+BASE_ATTRS = ["name",
+ "msKds-UseStartTime",
+ "msKds-CreateTime",
+ ]
+
+# these attributes are secret, and also pretty opaque and useless to
+# look at (unless you want to steal the secret).
+SECRET_ATTRS = ["msKds-RootKeyData",
+ "msKds-SecretAgreementParam"]
+
+# these are things you might want to look at, but generally don't.
+VERBOSE_ATTRS = ["whenCreated",
+ "whenChanged",
+ "objectGUID",
+ "msKds-KDFAlgorithmID",
+ "msKds-KDFParam",
+ "msKds-SecretAgreementAlgorithmID",
+ "msKds-PublicKeyLength",
+ "msKds-PrivateKeyLength",
+ "msKds-Version",
+ "msKds-DomainID",
+ "cn",
+ ]
+
+
+class RootKeyCommand(Command):
+ """Base class with a common method for presenting root key data."""
+ def show_root_key_message(self, msg,
+ output_format=None,
+ show_secrets=False,
+ preamble=None,
+ now=None):
+ if output_format == 'json':
+ out = {}
+ if preamble is not None:
+ out['message'] = preamble
+ for k, v in msg.items():
+ if not show_secrets and k in SECRET_ATTRS:
+ continue
+ out[k] = encode_by_key(k, v)
+ self.print_json(out)
+ return
+
+ if now is None:
+ now = nt_now()
+ create_time = int(msg['msKds-createTime'][0])
+ start_time = int(msg['msKds-UseStartTime'][0])
+ create_delta_string = delta_string(create_time - now)
+ start_delta_string = delta_string(start_time - now)
+
+ if preamble is not None:
+ self.message(preamble)
+
+ self.message(f"name {msg['name']}")
+ self.message(f" created {string_from_nt_time(create_time)} ({create_delta_string})")
+ self.message(f" usable from {string_from_nt_time(start_time)} ({start_delta_string})")
+
+ if show_secrets:
+ for k in SECRET_ATTRS:
+ v = msg[k][0].hex()
+ self.message(f" {k:14} {v}")
+
+ remaining_keys = [k for k in msg if k not in BASE_ATTRS + SECRET_ATTRS]
+
+ for k in remaining_keys:
+ v = encode_by_key(k, msg[k])
+ self.message(f" {k:14} {v}")
+
+ self.message('')
+
+
+class cmd_domain_kds_root_key_create(RootKeyCommand):
+ """Create a KDS root key object."""
+
+ synopsis = "%prog [-H <URL>] [options]"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "credopts": options.CredentialsOptions,
+ "hostopts": options.HostOptions,
+ }
+
+ takes_options = [
+ Option("--json", help="Output results in JSON format.",
+ dest="output_format", action="store_const", const="json"),
+ Option("--use-start-time", help="Use of the key begins at this time."),
+ Option("-v", "--verbose", help="Be verbose", action="store_true"),
+ ]
+
+ def run(self, hostopts=None, sambaopts=None, credopts=None,
+ output_format=None, use_start_time=None, verbose=None):
+ kwargs = {}
+ if use_start_time is not None:
+ try:
+ nt_use = nt_time_from_string(use_start_time)
+ kwargs['use_start_time'] = nt_use
+ except ValueError as e:
+ raise CommandError(e) from None
+
+ ldb = self.ldb_connect(hostopts, sambaopts, credopts)
+ dn = ldb.new_gkdi_root_key(**kwargs)
+ guid = dn.get_rdn_value()
+
+ attrs = BASE_ATTRS[:]
+ if verbose:
+ attrs += VERBOSE_ATTRS
+
+ msg = get_root_key_by_name_or_dn(ldb, guid, attrs=attrs)
+ start_time = int(msg['msKds-UseStartTime'][0])
+ used_from_string = (f"usable from {string_from_nt_time(start_time)} "
+ f"({delta_string(start_time - nt_now())})")
+
+ message = f"created root key {guid}, {used_from_string}"
+
+ if verbose:
+ self.show_root_key_message(msg,
+ output_format,
+ preamble=f"{message}\n")
+
+ elif output_format == 'json':
+ kwargs = {k: msg[k] for k in attrs}
+ self.print_json_status(message=message, dn=str(dn), **kwargs)
+ else:
+ self.message(message)
+
+
+class cmd_domain_kds_root_key_delete(RootKeyCommand):
+ """Delete a KDS root key."""
+
+ synopsis = "%prog [-H <URL>] [options]"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "credopts": options.CredentialsOptions,
+ "hostopts": options.HostOptions,
+ }
+
+ takes_options = [
+ Option("--name", help="The key to delete"),
+ Option("--json", help="Output results in JSON format.",
+ dest="output_format", action="store_const", const="json"),
+ ]
+
+ def run(self, hostopts=None, sambaopts=None, credopts=None, name=None, output_format=None):
+ ldb = self.ldb_connect(hostopts, sambaopts, credopts)
+ try:
+ root_key = get_root_key_by_name_or_dn(ldb, name)
+ except LdbError as e:
+ raise CommandError(e)
+
+ ldb.delete(root_key.dn)
+
+ guid = root_key.dn.get_rdn_value()
+ message = f"deleted root key {guid}"
+
+ if output_format == 'json':
+ self.print_json_status(message)
+ else:
+ self.message(message)
+
+
+class cmd_domain_kds_root_key_list(RootKeyCommand):
+ """List KDS root keys."""
--
Samba Shared Repository
More information about the samba-cvs
mailing list