python/netcmd: Add "samba-tool user get-kerberos-ticket" to get a ticket for a gMSA
authorAndrew Bartlett <abartlet@samba.org>
Thu, 14 Dec 2023 01:43:44 +0000 (14:43 +1300)
committerDouglas Bagnall <dbagnall@samba.org>
Thu, 21 Dec 2023 02:05:38 +0000 (02:05 +0000)
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
docs-xml/manpages/samba-tool.8.xml
python/samba/netcmd/user/__init__.py
python/samba/netcmd/user/readpasswords/__init__.py
python/samba/netcmd/user/readpasswords/get_kerberos_ticket.py [new file with mode: 0644]
python/samba/netcmd/user/setexpiry.py

index 6b3a73020e33f54f7bd691636caceafc636979f7..3471b0e199186351d5a026c70eee3e76b0cde685 100644 (file)
        <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>
index 6175e651ed9aa40c8f91272366b2c99a13e5efe4..fab657c2278fbcbeca7954edd99adcb24da2a4d5 100644 (file)
@@ -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()
index 8ca999b02159198d45519143ddb5bfaf27c72be6..75ba31365b74fdf93ec5e101b2753d8e9bb26b30 100644 (file)
@@ -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/get_kerberos_ticket.py b/python/samba/netcmd/user/readpasswords/get_kerberos_ticket.py
new file mode 100644 (file)
index 0000000..3a8296b
--- /dev/null
@@ -0,0 +1,146 @@
+# user management
+#
+# user get-kerberos-ticket command - obtain a TGT for a database user
+#
+# Copyright Jelmer Vernooij 2010 <jelmer@samba.org>
+# Copyright Theresa Halloran 2011 <theresahalloran@gmail.com>
+# Copyright Andrew Bartlett 2023 <abartlet@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]
+            creds.set_utf16_password(utf16_pw)
+        except KeyError:
+            pass
+
+        if utf16_pw is None:
+            try:
+                nt_pass = samr.Password()
+                nt_pass.hash = list(obj["unicodePwd"][0])
+                creds.set_nt_hash(nt_pass)
+            except KeyError:
+                pass
+
+        if nt_pass is None and utf16_pw is None:
+            if samdb.url.startswith("ldap://") or samdb.url.startswith("ldaps://"):
+                raise CommandError("No password was available for this user.  "
+                                   "Only Group Managed Service accounts allow access to passwords over LDAP, "
+                                   "you may need to access the sam.ldb directly on the Samba AD DC and export the file.")
+            else:
+                raise CommandError("No password was available for this user")
+        creds.guess(lp_ctx)
+        creds.get_named_ccache(lp_ctx, output_krb5_ccache)
index 9d53d280239517b6e444000dfdaebc38ff8347c1..7f4af6ee23f5e20cdec8ca23a5a52bf492e2bd83 100644 (file)
@@ -46,7 +46,7 @@ sudo samba-tool user setexpiry User2 --noexpiry
 Example2 shows how to set the account expiration of user User2 so it will never expire.  The user in this example resides on the  local server.   sudo is used so a user may run the command as root.
 
 Example3:
-samba-tool user setexpiry --days=20 --filter=samaccountname=User3
+samba-tool user setexpiry --days=20 --filter='(samaccountname=User3)'
 
 Example3 shows how to set the account expiration date to end of day 20 days from the current day.  The username or sAMAccountName is specified using the --filter= parameter and the username in this example is User3.