From 8eadc19f35ee90ca318c43a90fef7fcdbec263bd Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 14 Dec 2023 14:43:44 +1300 Subject: [PATCH] python/netcmd: Add "samba-tool user get-kerberos-ticket" to get a ticket for a gMSA Signed-off-by: Andrew Bartlett Reviewed-by: Douglas Bagnall --- docs-xml/manpages/samba-tool.8.xml | 5 + python/samba/netcmd/user/__init__.py | 7 +- .../netcmd/user/readpasswords/__init__.py | 1 + .../user/readpasswords/get_kerberos_ticket.py | 146 ++++++++++++++++++ python/samba/netcmd/user/setexpiry.py | 2 +- 5 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 python/samba/netcmd/user/readpasswords/get_kerberos_ticket.py 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 @@ Gets the password of a user account. + + user get-kerberos-ticket <replaceable>username</replaceable> [options] + Gets a Kerberos Ticket Granting Ticket as the account. + + user syncpasswords <replaceable>--cache-ldb-initialize</replaceable> [options] Syncs the passwords of all user accounts, using an optional script. 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/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 +# Copyright Theresa Halloran 2011 +# Copyright Andrew Bartlett 2023 +# +# 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 . +# + +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 (|--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) diff --git a/python/samba/netcmd/user/setexpiry.py b/python/samba/netcmd/user/setexpiry.py index 9d53d280239..7f4af6ee23f 100644 --- a/python/samba/netcmd/user/setexpiry.py +++ b/python/samba/netcmd/user/setexpiry.py @@ -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. -- 2.47.3