[SCM] Samba Shared Repository - branch master updated

Douglas Bagnall dbagnall at samba.org
Thu Dec 21 03:05:02 UTC 2023


The branch, master has been updated
       via  31637d40371 WHATSNEW: Add entry for "samba-tool user get-kerberos-ticket"
       via  7c9fa2804b8 selftest: Add tests for "samba-tool user get-kerberos-ticket"
       via  d8b3b1fed9a python/netcmd: Improve documentation for "samba-tool user getpassword"
       via  8eadc19f35e python/netcmd: Add "samba-tool user get-kerberos-ticket" to get a ticket for a gMSA
       via  a39e19dfa75 WHATSNEW: Add entry for "samba-tool user getpassword" changes
       via  128710c2f3c python: tests: blackbox test for GMSA
       via  339e7ae186d samba-tool: document that -H can be used with gMSA accounts
       via  72f0c99a7aa samba-tool: fix some grammar in getpassword docstrings
       via  113d2aab30f samba-tool: Make samba-tool user getpassword support a ';previous=1' option
       via  2c54a754842 samba-tool user getpassword: Prepare to support a ;previous=1 option, change behaviour for ;rounds=
       via  175a13ca134 selftest: Modify expected output of 'samba-tool user getpassword' to be more consistant
       via  562bde91b44 selftest: fix failing user setpassword test
       via  8b67a86584d samba-tool: Add support for getting the generated unicodePwd for a gMSA account
       via  9557140f196 netcmd: user: samba-tool support to allow non-windows use of GMSA accounts (show password)
       via  23326105cd6 samba-tool user getpassword: Use UTF16_MUNGED charcnv to map "UTF16" to UTF8
       via  f89a2065a68 samba-tool: Prepare to allow samba-tool user getpasswords to operate against a remote server
       via  c5a2d57e5fa netcmd: models: add object sid field to User model
       via  bf37d538e63 netcmd: getpassword: print OK message on stderr
       via  587642a63ad selftest: Avoid assertTrue() and assertFalse() where a better test exists
       via  ba29bb54cad selftest: require named parameters for callers of connect_samdb() and connect_samdb_ex()
       via  5e823724389 selftest: add get_env_credentials()
       via  18fd2e4ff35 selftest: make get_loadparm a classmethod
       via  9f8786f0edc selftest: make _get_attribute use parse_ldif
       via  a30657d42f4 selftest: make _get_attribute a method on base class
       via  6ed2b445f55 selftest: pep8: fix incorrect number of blank lines
       via  2f5b06253bb selftest: remove unused imports from virtualCryptSHA tests
       via  b236856a3e3 selftest: function _get_attribute() was in two places
      from  8cfc6ea9232 Revert "rpc_server:srvsvc - retrieve share ACL via root context"

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


- Log -----------------------------------------------------------------
commit 31637d403719613a536028ef35ef8504288b8946
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Dec 18 17:24:26 2023 +1300

    WHATSNEW: Add entry for "samba-tool user get-kerberos-ticket"
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    
    Autobuild-User(master): Douglas Bagnall <dbagnall at samba.org>
    Autobuild-Date(master): Thu Dec 21 03:04:12 UTC 2023 on atb-devel-224

commit 7c9fa2804b8e0ef3cef0365da58a8bae4f170840
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Dec 15 17:10:42 2023 +1300

    selftest: Add tests for "samba-tool user get-kerberos-ticket"
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit d8b3b1fed9a30edd16d04b2094ceaf8e3571a7de
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu Dec 14 14:50:05 2023 +1300

    python/netcmd: Improve documentation for "samba-tool user getpassword"
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 8eadc19f35ee90ca318c43a90fef7fcdbec263bd
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu Dec 14 14:43:44 2023 +1300

    python/netcmd: Add "samba-tool user get-kerberos-ticket" to get a ticket for a gMSA
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit a39e19dfa759c62cd59545da8ead13d2ae49e6e0
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Dec 18 17:14:27 2023 +1300

    WHATSNEW: Add entry for "samba-tool user getpassword" changes
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 128710c2f3c1ee3dd73eba8d755ea7caeb9f3196
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Dec 7 15:53:01 2023 +1300

    python: tests: blackbox test for GMSA
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 339e7ae186d5fe3569652f173988858b7e9651e4
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Fri Dec 15 15:12:42 2023 +1300

    samba-tool: document that -H can be used with gMSA accounts
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 72f0c99a7aa4f44cbb1b96be73e14d1f506fff7b
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Fri Dec 15 15:10:39 2023 +1300

    samba-tool: fix some grammar in getpassword docstrings
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 113d2aab30fc84e5434d5475982ae579d8433b70
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Dec 11 20:56:16 2023 +1300

    samba-tool: Make samba-tool user getpassword support a ';previous=1' option
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 2c54a754842e0deb6e6a4944fde6dec37d7742a2
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Dec 11 20:55:10 2023 +1300

    samba-tool user getpassword: Prepare to support a ;previous=1 option, change behaviour for ;rounds=
    
    This will return the previous password, but the pattern is to include
    the option in the returned attribute name, so we need to use
    vatter["raw_attr"], not 'a'.
    
    This changes the behaviour for the ;rounds= option used when we hold
    the plaintext password (possibly under GPG encryption).
    
    This is now consistant with other parameters in the LDAP attribute,
    and is now included in the returned attribute name.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 175a13ca134a2c990ae20df83f80ed4194055c96
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Dec 11 21:40:44 2023 +1300

    selftest: Modify expected output of 'samba-tool user getpassword' to be more consistant
    
    This is consistant with ;format= support for time attributes and
    other users of this parameter style elsewhere in LDAP.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 562bde91b44620a475923b90d76eb2eaf5109141
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Fri Dec 15 12:36:14 2023 +1300

    selftest: fix failing user setpassword test
    
    A side effect of being able to generate at read time unicodePwd for a gMSA is that we can also generate the unicodePwd from a virtualSambaGPG password.
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 8b67a86584d20b59a1e2af7c37f342870a505192
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Dec 11 20:49:44 2023 +1300

    samba-tool: Add support for getting the generated unicodePwd for a gMSA account
    
    This pre-hashed value may be more practical to use than the random "UTF-16"
    password.  In particular it is easy to compare with the DB values.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 9557140f1969650192569da2168677195de01933
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Fri Dec 1 16:14:16 2023 +1300

    netcmd: user: samba-tool support to allow non-windows use of GMSA accounts (show password)
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 23326105cd612d8c1fea1a4d7f1f3c5117d5a674
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Dec 12 16:38:13 2023 +1300

    samba-tool user getpassword: Use UTF16_MUNGED charcnv to map "UTF16" to UTF8
    
    This copes with random invalid UTF-16 as seen with gMSA accounts.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit f89a2065a686a20532813e8b2e80987da61333e1
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Dec 11 16:54:57 2023 +1300

    samba-tool: Prepare to allow samba-tool user getpasswords to operate against a remote server
    
    While passwords are not normally available for read, Group Managed Service Account
    passwords are, as this is how they are distributed.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit c5a2d57e5fa8d42e3a1028a4274163b56a16f079
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Dec 7 15:29:27 2023 +1300

    netcmd: models: add object sid field to User model
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit bf37d538e63791d740a9a0bc50557915e7401c0e
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Dec 7 15:28:04 2023 +1300

    netcmd: getpassword: print OK message on stderr
    
    This makes it easier to machine parse the output in tests
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 587642a63ad3d35718e0d789a8227bcac4debe36
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Dec 11 17:41:21 2023 +1300

    selftest: Avoid assertTrue() and assertFalse() where a better test exists
    
    This allows the unittest framework to show the strings that the value was
    not found in.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit ba29bb54cada2e0d01a8b6f7a7587696d44fa1f9
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Wed Dec 13 14:03:14 2023 +1300

    selftest: require named parameters for callers of connect_samdb() and connect_samdb_ex()
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 5e823724389984379ae1f624cf1051a77179ef28
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Wed Dec 13 14:00:45 2023 +1300

    selftest: add get_env_credentials()
    
    This is like get_credentials but works for tests that are based
    on environment variable for usernames and passwords.
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 18fd2e4ff35e4ec3491a1836c1896c1417126b08
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Wed Dec 13 14:00:00 2023 +1300

    selftest: make get_loadparm a classmethod
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 9f8786f0edc3427361a6777a7f1868a66ed4cc83
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Dec 14 12:57:09 2023 +1300

    selftest: make _get_attribute use parse_ldif
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit a30657d42f4368027fe699e817228d35391244b5
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Wed Dec 13 16:50:18 2023 +1300

    selftest: make _get_attribute a method on base class
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 6ed2b445f5508fce69fe9080ff21cf1a71595f08
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Wed Dec 13 16:41:11 2023 +1300

    selftest: pep8: fix incorrect number of blank lines
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 2f5b06253bb01e56518d1f7fdfb8a7b542f19609
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Wed Dec 13 16:40:17 2023 +1300

    selftest: remove unused imports from virtualCryptSHA tests
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit b236856a3e38a390ffd980fb9bd507801df826c1
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Wed Dec 13 16:39:06 2023 +1300

    selftest: function _get_attribute() was in two places
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

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

Summary of changes:
 WHATSNEW.txt                                       |  42 +++++
 docs-xml/manpages/samba-tool.8.xml                 |   5 +
 python/samba/netcmd/domain/models/user.py          |   3 +-
 python/samba/netcmd/user/__init__.py               |   7 +-
 python/samba/netcmd/user/readpasswords/__init__.py |   1 +
 python/samba/netcmd/user/readpasswords/common.py   | 118 +++++++++----
 .../user/readpasswords/get_kerberos_ticket.py      | 146 +++++++++++++++
 .../samba/netcmd/user/readpasswords/getpassword.py |  38 ++--
 .../netcmd/user/readpasswords/syncpasswords.py     |   6 +-
 python/samba/netcmd/user/setexpiry.py              |   2 +-
 python/samba/tests/__init__.py                     |  31 +++-
 python/samba/tests/samba_tool/user.py              |   9 +-
 .../tests/samba_tool/user_get_kerberos_ticket.py   | 195 +++++++++++++++++++++
 .../tests/samba_tool/user_getpassword_gmsa.py      | 171 ++++++++++++++++++
 .../samba/tests/samba_tool/user_virtualCryptSHA.py | 100 +++++------
 .../tests/samba_tool/user_virtualCryptSHA_base.py  |  30 +---
 .../tests/samba_tool/user_virtualCryptSHA_gpg.py   | 105 +++++------
 .../user_virtualCryptSHA_userPassword.py           |  59 ++++---
 python/samba/tests/samba_tool/user_wdigest.py      |   5 +-
 .../samba-tool-user-get-kerberos-ticket            |   5 +
 selftest/knownfail.d/user_getpassword_gmsa         |   1 +
 source4/selftest/tests.py                          |   5 +
 22 files changed, 847 insertions(+), 237 deletions(-)
 create mode 100644 python/samba/netcmd/user/readpasswords/get_kerberos_ticket.py
 create mode 100644 python/samba/tests/samba_tool/user_get_kerberos_ticket.py
 create mode 100644 python/samba/tests/samba_tool/user_getpassword_gmsa.py
 create mode 100644 selftest/knownfail.d/samba-tool-user-get-kerberos-ticket
 create mode 100644 selftest/knownfail.d/user_getpassword_gmsa


Changeset truncated at 500 lines:

diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 12dff08271c..aba6726840c 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -38,6 +38,48 @@ source tree.  While there will be some differences - due to features
 chosen by packagers - comparing these lists with the build dependencies
 in a package may locate other dependencies we no longer require.
 
+samba-tool user getpassword / syncpasswords ;rounds= change
+-----------------------------------------------------------
+
+The password access tool "samba-tool user getpassword" and the
+password sync tool "samba-tool user syncpasswords" allow attributes to
+be chosen for output, and accept parameters like
+pwdLastSet;format=GeneralizedTime
+
+These attributes then appear, in the same format, as the attributes in
+the LDIF output.  This was not the case for the ;rounds= parameter of
+virtualCryptSHA256 and virtualCryptSHA512, for example as
+--attributes="virtualCryptSHA256;rounds=50000"
+
+This release makes the behaviour consistent between these two
+features.  Installations using GPG-encrypted passwords (or plaintext
+storage) and the rounds= option, will find the output has changed
+
+from:
+virtualCryptSHA256: {CRYPT}$5$rounds=2561$hXem.M9onhM9Vuix$dFdSBwF
+
+to:
+virtualCryptSHA256;rounds=2561: {CRYPT}$5$rounds=2561$hXem.M9onhM9Vuix$dFdSBwF
+
+Group Managed service account client-side features
+--------------------------------------------------
+
+samba-tool has been extended to provide client-side support for Group
+Managed Service accounts.  These accounts have passwords that change
+automatically, giving the advantages of service isolation without risk
+of poor, unchanging passwords.
+
+Where possible, Samba's existing samba-tool password handling
+commands, which in the past have only operated against the local
+sam.ldb have been extended to permit operation against a remote server
+with authenticated access to "-H ldap://$DCNAME"
+
+Supported operations include:
+ - reading the current and previous gMSA password via
+   "samba-tool user getpassword"
+ - writing a Kerberos Ticket Granting Ticket (TGT) to a local
+   credentials cache with a new command
+   "samba-tool user get-kerberos-ticket"
 
 REMOVED FEATURES
 ================
diff --git a/docs-xml/manpages/samba-tool.8.xml b/docs-xml/manpages/samba-tool.8.xml
index 6b3a73020e3..3471b0e1991 100644
--- a/docs-xml/manpages/samba-tool.8.xml
+++ b/docs-xml/manpages/samba-tool.8.xml
@@ -2743,6 +2743,11 @@
 	<para>Gets the password of a user account.</para>
 </refsect3>
 
+<refsect3>
+	<title>user get-kerberos-ticket <replaceable>username</replaceable> [options]</title>
+	<para>Gets a Kerberos Ticket Granting Ticket as the account.</para>
+</refsect3>
+
 <refsect3>
 	<title>user syncpasswords <replaceable>--cache-ldb-initialize</replaceable> [options]</title>
 	<para>Syncs the passwords of all user accounts, using an optional script.</para>
diff --git a/python/samba/netcmd/domain/models/user.py b/python/samba/netcmd/domain/models/user.py
index 79e30453532..7b0785a0fb3 100644
--- a/python/samba/netcmd/domain/models/user.py
+++ b/python/samba/netcmd/domain/models/user.py
@@ -24,7 +24,7 @@ from ldb import Dn
 
 from samba.dsdb import DS_GUID_USERS_CONTAINER
 
-from .fields import DnField, StringField
+from .fields import DnField, SIDField, StringField
 from .model import Model
 
 
@@ -32,6 +32,7 @@ class User(Model):
     username = StringField("sAMAccountName")
     assigned_policy = DnField("msDS-AssignedAuthNPolicy")
     assigned_silo = DnField("msDS-AssignedAuthNPolicySilo")
+    object_sid = SIDField("objectSid")
 
     def __str__(self):
         """Return username rather than cn for User model."""
diff --git a/python/samba/netcmd/user/__init__.py b/python/samba/netcmd/user/__init__.py
index 6175e651ed9..fab657c2278 100644
--- a/python/samba/netcmd/user/__init__.py
+++ b/python/samba/netcmd/user/__init__.py
@@ -30,8 +30,10 @@ from .getgroups import cmd_user_getgroups
 from .list import cmd_user_list
 from .move import cmd_user_move
 from .password import cmd_user_password
-from .readpasswords import (cmd_user_getpassword, cmd_user_show,
-                            cmd_user_syncpasswords)
+from .readpasswords import (cmd_user_getpassword,
+                            cmd_user_show,
+                            cmd_user_syncpasswords,
+                            cmd_user_get_kerberos_ticket)
 from .rename import cmd_user_rename
 from .sensitive import cmd_user_sensitive
 from .setexpiry import cmd_user_setexpiry
@@ -57,6 +59,7 @@ class cmd_user(SuperCommand):
     subcommands["setprimarygroup"] = cmd_user_setprimarygroup()
     subcommands["setpassword"] = cmd_user_setpassword()
     subcommands["getpassword"] = cmd_user_getpassword()
+    subcommands["get-kerberos-ticket"] = cmd_user_get_kerberos_ticket()
     subcommands["syncpasswords"] = cmd_user_syncpasswords()
     subcommands["edit"] = cmd_user_edit()
     subcommands["show"] = cmd_user_show()
diff --git a/python/samba/netcmd/user/readpasswords/__init__.py b/python/samba/netcmd/user/readpasswords/__init__.py
index 8ca999b0215..75ba31365b7 100644
--- a/python/samba/netcmd/user/readpasswords/__init__.py
+++ b/python/samba/netcmd/user/readpasswords/__init__.py
@@ -22,3 +22,4 @@
 from .getpassword import cmd_user_getpassword
 from .show import cmd_user_show
 from .syncpasswords import cmd_user_syncpasswords
+from .get_kerberos_ticket import cmd_user_get_kerberos_ticket
diff --git a/python/samba/netcmd/user/readpasswords/common.py b/python/samba/netcmd/user/readpasswords/common.py
index 02f7d36f5fc..6d44881823d 100644
--- a/python/samba/netcmd/user/readpasswords/common.py
+++ b/python/samba/netcmd/user/readpasswords/common.py
@@ -30,7 +30,7 @@ import ldb
 from samba import credentials, nttime2float
 from samba.auth import system_session
 from samba.common import get_bytes, get_string
-from samba.dcerpc import drsblobs, security
+from samba.dcerpc import drsblobs, security, gmsa
 from samba.ndr import ndr_unpack
 from samba.netcmd import Command, CommandError
 from samba.samdb import SamDB
@@ -99,6 +99,9 @@ virtual_attributes = {
     "virtualSambaGPG": {
         "flags": ldb.ATTR_FLAG_FORCE_BASE64_LDIF,
     },
+    "unicodePwd": {
+        "flags": ldb.ATTR_FLAG_FORCE_BASE64_LDIF,
+    },
 }
 
 
@@ -188,23 +191,23 @@ class GetPasswordCommand(Command):
             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):
+    def connect_for_passwords(self, url,
+                              creds=None,
+                              require_ldapi=True,
+                              verbose=False):
 
         # using anonymous here, results in no authentication
         # which means we can get system privileges via
         # the privileged ldapi socket
-        creds = credentials.Credentials()
-        creds.set_anonymous()
+        anon_creds = credentials.Credentials()
+        anon_creds.set_anonymous()
 
-        if url is None and allow_local:
+        if url is None and not require_ldapi:
             pass
         elif url.lower().startswith("ldapi://"):
+            creds = anon_creds
             pass
-        elif url.lower().startswith("ldap://"):
-            raise CommandError("--url ldap:// is not supported for this command")
-        elif url.lower().startswith("ldaps://"):
-            raise CommandError("--url ldaps:// is not supported for this command")
-        elif not allow_local:
+        elif require_ldapi:
             raise CommandError("--url requires an ldapi:// url for this command")
 
         if verbose:
@@ -213,19 +216,20 @@ class GetPasswordCommand(Command):
         samdb = SamDB(url=url, session_info=system_session(),
                       credentials=creds, lp=self.lp)
 
-        try:
-            #
-            # Make sure we're connected as SYSTEM
-            #
-            res = samdb.search(base='', scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
-            assert len(res) == 1
-            sids = res[0].get("tokenGroups")
-            assert len(sids) == 1
-            sid = ndr_unpack(security.dom_sid, sids[0])
-            assert str(sid) == security.SID_NT_SYSTEM
-        except Exception as msg:
-            raise CommandError("You need to specify an URL that gives privileges as SID_NT_SYSTEM(%s)" %
-                               (security.SID_NT_SYSTEM))
+        if require_ldapi or url is None:
+            try:
+                #
+                # Make sure we're connected as SYSTEM
+                #
+                res = samdb.search(base='', scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
+                assert len(res) == 1
+                sids = res[0].get("tokenGroups")
+                assert len(sids) == 1
+                sid = ndr_unpack(security.dom_sid, sids[0])
+                assert str(sid) == security.SID_NT_SYSTEM
+            except Exception as msg:
+                raise CommandError("You need to specify an URL that gives privileges as SID_NT_SYSTEM(%s)" %
+                                   (security.SID_NT_SYSTEM))
 
         self.inject_virtual_attributes(samdb)
 
@@ -322,6 +326,7 @@ class GetPasswordCommand(Command):
                 required_attrs = [
                     "supplementalCredentials",
                     "unicodePwd",
+                    "msDS-ManagedPassword",
                 ]
                 for required_attr in required_attrs:
                     a = parse_raw_attr(required_attr, is_hidden=True)
@@ -349,6 +354,8 @@ class GetPasswordCommand(Command):
             raise CommandError("Failed to get password for user '%s': %s" % (username or filter, msg))
         obj = res[0]
 
+        calculated = {}
+
         sc = None
         unicodePwd = None
         if "supplementalCredentials" in obj:
@@ -356,6 +363,17 @@ class GetPasswordCommand(Command):
             sc = ndr_unpack(drsblobs.supplementalCredentialsBlob, sc_blob)
         if "unicodePwd" in obj:
             unicodePwd = obj["unicodePwd"][0]
+        if "msDS-ManagedPassword" in obj:
+            # unpack a GMSA managed password as if we could read the
+            # hidden password attributes.
+            managed_password = obj["msDS-ManagedPassword"][0]
+            unpacked_managed_password = ndr_unpack(gmsa.MANAGEDPASSWORD_BLOB,
+                                                   managed_password)
+            calculated["Primary:CLEARTEXT"] = \
+                unpacked_managed_password.passwords.current
+            calculated["OLDCLEARTEXT"] = \
+                unpacked_managed_password.passwords.previous
+
         account_name = str(obj["sAMAccountName"][0])
         if "userPrincipalName" in obj:
             account_upn = str(obj["userPrincipalName"][0])
@@ -363,8 +381,6 @@ class GetPasswordCommand(Command):
             realm = samdb.domain_dns_name()
             account_upn = "%s@%s" % (account_name, realm.lower())
 
-        calculated = {}
-
         def get_package(name, min_idx=0):
             if name in calculated:
                 return calculated[name]
@@ -383,6 +399,17 @@ class GetPasswordCommand(Command):
                 return binascii.a2b_hex(p.data)
             return None
 
+        def get_cleartext(attr_opts):
+            param = get_option(attr_opts, "previous")
+            if param:
+                if param != "1":
+                    raise CommandError(
+                        f"Invalid attribute parameter ;previous={param}, "
+                        "only supported value is previous=1")
+                return calculated.get("OLDCLEARTEXT")
+            else:
+                return get_package("Primary:CLEARTEXT")
+
         def get_kerberos_ctr():
             primary_krb5 = get_package("Primary:Kerberos-Newer-Keys")
             if primary_krb5 is None:
@@ -453,14 +480,14 @@ class GetPasswordCommand(Command):
                             username or account_name, e))
 
         def get_utf8(a, b, username):
-            try:
-                u = str(get_bytes(b), 'utf-16-le')
-            except UnicodeDecodeError as e:
-                self.outf.write("WARNING: '%s': CLEARTEXT is invalid UTF-16-LE unable to generate %s\n" % (
-                                username, a))
-                return None
-            u8 = u.encode('utf-8')
-            return u8
+            creds_for_charcnv = credentials.Credentials()
+            creds_for_charcnv.set_anonymous()
+            creds_for_charcnv.set_utf16_password(get_bytes(b))
+
+            # This can't fail due to character conversion issues as it
+            # includes a built-in fallback (UTF16_MUNGED) matching
+            # exactly what we need.
+            return creds_for_charcnv.get_password().encode()
 
         # Extract the WDigest hash for the value specified by i.
         # Builds an htdigest compatible value
@@ -582,7 +609,7 @@ class GetPasswordCommand(Command):
             if sv is None:
                 # No exact match on algorithm and number of rounds
                 # try and calculate one from the Primary:CLEARTEXT
-                b = get_package("Primary:CLEARTEXT")
+                b = get_cleartext(attr_opts)
                 if b is not None:
                     u8 = get_utf8(a, b, username or account_name)
                     if u8 is not None:
@@ -650,6 +677,14 @@ class GetPasswordCommand(Command):
             except ValueError:
                 return 0
 
+        def get_unicode_pwd_hash(pwd):
+            # We can't read unicodePwd directly, but we can regenerate
+            # it from msDS-ManagedPassword
+            tmp = credentials.Credentials()
+            tmp.set_anonymous()
+            tmp.set_utf16_password(pwd)
+            return tmp.get_nt_hash()
+
         # We use sort here in order to have a predictable processing order
         for a in sorted(virtual_attributes.keys()):
             vattr = None
@@ -665,7 +700,7 @@ class GetPasswordCommand(Command):
             attr_opts = vattr["opts"]
 
             if a == "virtualClearTextUTF8":
-                b = get_package("Primary:CLEARTEXT")
+                b = get_cleartext(attr_opts)
                 if b is None:
                     continue
                 u8 = get_utf8(a, b, username or account_name)
@@ -673,11 +708,11 @@ class GetPasswordCommand(Command):
                     continue
                 v = u8
             elif a == "virtualClearTextUTF16":
-                v = get_package("Primary:CLEARTEXT")
+                v = get_cleartext(attr_opts)
                 if v is None:
                     continue
             elif a == "virtualSSHA":
-                b = get_package("Primary:CLEARTEXT")
+                b = get_cleartext(attr_opts)
                 if b is None:
                     continue
                 u8 = get_utf8(a, b, username or account_name)
@@ -714,6 +749,13 @@ class GetPasswordCommand(Command):
                 v = kerberos_salt
                 if v is None:
                     continue
+            elif a == "unicodePwd" and unicodePwd is None:
+                if "Primary:CLEARTEXT" in calculated and not get_option(attr_opts, "previous"):
+                    v = get_unicode_pwd_hash(calculated["Primary:CLEARTEXT"])
+                elif "OLDCLEARTEXT" in calculated and get_option(attr_opts, "previous"):
+                    v = get_unicode_pwd_hash(calculated["OLDCLEARTEXT"])
+                else:
+                    continue
             elif a.startswith("virtualWDigest"):
                 primary_wdigest = get_package("Primary:WDigest")
                 if primary_wdigest is None:
@@ -730,7 +772,7 @@ class GetPasswordCommand(Command):
                     continue
             else:
                 continue
-            obj[a] = ldb.MessageElement(v, ldb.FLAG_MOD_REPLACE, a)
+            obj[a] = ldb.MessageElement(v, ldb.FLAG_MOD_REPLACE, vattr["raw_attr"])
 
         def get_src_attrname(srcattrg):
             srcattrl = srcattrg.lower()
diff --git a/python/samba/netcmd/user/readpasswords/get_kerberos_ticket.py b/python/samba/netcmd/user/readpasswords/get_kerberos_ticket.py
new file mode 100644
index 00000000000..3a8296b187a
--- /dev/null
+++ b/python/samba/netcmd/user/readpasswords/get_kerberos_ticket.py
@@ -0,0 +1,146 @@
+# user management
+#
+# user get-kerberos-ticket command - obtain a TGT for a database user
+#
+# Copyright Jelmer Vernooij 2010 <jelmer at samba.org>
+# Copyright Theresa Halloran 2011 <theresahalloran at gmail.com>
+# Copyright Andrew Bartlett 2023 <abartlet at samba.org>
+#
+# 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 ldb
+import samba.getopt as options
+from samba.netcmd import CommandError, Option
+from samba.credentials import Credentials
+from .common import (
+    GetPasswordCommand,
+    gpg_decrypt,
+    decrypt_samba_gpg_help,
+)
+from samba.dcerpc import samr
+
+class cmd_user_get_kerberos_ticket(GetPasswordCommand):
+    """Get a Kerberos Ticket Granting Ticket as a user
+
+This command gets a Kerberos TGT using the password for a user/computer account.
+
+The username specified on the command is the sAMAccountName.
+The username may also be specified using the --filter option.
+
+The command must be run from the root user id or another authorized
+user id. The '-H' or '--URL' option supports ldap:// for remote Group
+Managed Service accounts, and ldapi:// or tdb:// can be used to
+adjust the local path. tdb:// is used by default for a bare path.
+
+The --output-krb5-ccache option should point to a location for the
+credentials cache.  The default is a FILE: type cache if no prefix is
+specified.
+
+The '--decrypt-samba-gpg' option triggers decryption of the
+Primary:SambaGPG buffer to get the password.
+
+Check with '--help' if this feature is available
+in your environment or not (the python-gpgme package is required).  Please
+note that you might need to set the GNUPGHOME environment variable.  If the
+decryption key has a passphrase you have to make sure that the GPG_AGENT_INFO
+environment variable has been set correctly and the passphrase is already
+known by the gpg-agent.
+
+Example1:
+samba-tool user get-kerberos-ticket TestUser1 --output-krb5-ccache=/srv/service/krb5_ccache
+
+Example2:
+samba-tool user get-kerberos-ticket --filter='(samAccountName=TestUser3)' --output-krb5-ccache=FILE:/srv/service/krb5_ccache
+
+    """
+    synopsis = "%prog (<username>|--filter <filter>) [options]"
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+        "hostopts": options.HostOptions,
+    }
+
+    takes_options = [
+        Option("--filter", help="LDAP Filter to get Kerberos ticket for (must match single account)", type=str),
+        Option("--output-krb5-ccache", type=str,
+               help="Location of Kerberos credentials cache to write ticket into",
+               metavar="CCACHE", dest="output_krb5_ccache"),
+        Option("--decrypt-samba-gpg",
+               help=decrypt_samba_gpg_help,
+               action="store_true", default=False, dest="decrypt_samba_gpg"),
+    ]
+
+    takes_args = ["username?"]
+
+    def run(self, username=None, H=None, filter=None,
+            attributes=None, decrypt_samba_gpg=None,
+            sambaopts=None, versionopts=None, hostopts=None,
+            credopts=None, output_krb5_ccache=None):
+        self.lp = sambaopts.get_loadparm()
+
+        if decrypt_samba_gpg and not gpg_decrypt:
+            raise CommandError(decrypt_samba_gpg_help)
+
+        if filter is None and username is None:
+            raise CommandError("Either the username or '--filter' must be specified!")
+
+        if filter is None:
+            filter = "(&(objectClass=user)(sAMAccountName=%s))" % (ldb.binary_encode(username))
+
+        password_attrs = ["virtualClearTextUTF16", "samAccountName", "unicodePwd"]
+
+        creds = credopts.get_credentials(self.lp)
+        samdb = self.connect_for_passwords(url=hostopts.H, require_ldapi=False, creds=creds)
+
+        obj = self.get_account_attributes(samdb, username,
+                                          basedn=None,
+                                          filter=filter,
+                                          scope=ldb.SCOPE_SUBTREE,
+                                          attrs=password_attrs,
+                                          decrypt=decrypt_samba_gpg)
+
+        lp_ctx = sambaopts.get_loadparm()
+
+        creds = Credentials()
+        creds.set_username(str(obj["samAccountName"][0]))
+        creds.set_realm(samdb.domain_dns_name())
+
+        utf16_pw = None
+        nt_pass = None
+        try:
+            utf16_pw = obj["virtualClearTextUTF16"][0]


-- 
Samba Shared Repository



More information about the samba-cvs mailing list