summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/scripting/python/samba/netcmd/__init__.py2
-rw-r--r--source4/scripting/python/samba/netcmd/spn.py217
-rwxr-xr-xsource4/selftest/tests.sh1
-rwxr-xr-xsource4/setup/tests/blackbox_spn.sh33
4 files changed, 253 insertions, 0 deletions
diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py
index 6fd72944ec..08ddcefe91 100644
--- a/source4/scripting/python/samba/netcmd/__init__.py
+++ b/source4/scripting/python/samba/netcmd/__init__.py
@@ -160,5 +160,7 @@ from samba.netcmd.vampire import cmd_vampire
commands["vampire"] = cmd_vampire()
from samba.netcmd.machinepw import cmd_machinepw
commands["machinepw"] = cmd_machinepw()
+from samba.netcmd.spn import cmd_spn
+commands["spn"] = cmd_spn()
from samba.netcmd.group import cmd_group
commands["group"] = cmd_group()
diff --git a/source4/scripting/python/samba/netcmd/spn.py b/source4/scripting/python/samba/netcmd/spn.py
new file mode 100644
index 0000000000..e2eb05d9d2
--- /dev/null
+++ b/source4/scripting/python/samba/netcmd/spn.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python
+#
+# spn management
+#
+# Copyright Matthieu Patou mat@samba.org 2010
+#
+# 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
+import ldb
+import re
+from samba import provision
+from samba.samdb import SamDB
+from samba.auth import system_session
+from samba.netcmd import (
+ Command,
+ CommandError,
+ SuperCommand,
+ Option
+ )
+
+def _get_user_realm_domain(user):
+ """ get the realm or the domain and the base user
+ from user like:
+ * username
+ * DOMAIN\username
+ * username@REALM
+ """
+ baseuser = user
+ realm = ""
+ domain = ""
+ m = re.match(r"(\w+)\\(\w+$)", user)
+ if m:
+ domain = m.group(1)
+ baseuser = m.group(2)
+ return (baseuser.lower(), domain.upper(), realm)
+ m = re.match(r"(\w+)@(\w+)", user)
+ if m:
+ baseuser = m.group(1)
+ realm = m.group(2)
+ return (baseuser.lower(), domain, realm.upper())
+
+class cmd_spn_list(Command):
+ """List spns of a given user."""
+ synopsis = "%prog spn list <user>"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "credopts": options.CredentialsOptions,
+ "versionopts": options.VersionOptions,
+ }
+
+ takes_args = ["user"]
+
+ def run(self, user, credopts=None, sambaopts=None, versionopts=None):
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+ paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
+ sam = SamDB(paths.samdb, session_info=system_session(),
+ credentials=creds, lp=lp)
+ # TODO once I understand how, use the domain info to naildown
+ # to the correct domain
+ (cleaneduser, realm, domain) = _get_user_realm_domain(user)
+ print cleaneduser
+ res = sam.search(expression="samaccountname=%s" % cleaneduser,
+ scope=ldb.SCOPE_SUBTREE,
+ attrs=["servicePrincipalName"])
+ if len(res) >0:
+ spns = res[0].get("servicePrincipalName")
+ found = False
+ flag = ldb.FLAG_MOD_ADD
+ if spns != None:
+ print "User %s has the following servicePrincipalName: " % str(res[0].dn)
+ for e in spns:
+ print "\t %s" % (str(e))
+
+ else:
+ print "User %s has no servicePrincipalName" % str(res[0].dn)
+ else:
+ raise CommandError("User %s not found" % user)
+
+class cmd_spn_add(Command):
+ """Create a new spn."""
+ synopsis = "%prog spn add [--force] <name> <user>"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "credopts": options.CredentialsOptions,
+ "versionopts": options.VersionOptions,
+ }
+ takes_options = [
+ Option("--force", help="Force the addition of the spn"\
+ " even it exists already", action="store_true"),
+ ]
+ takes_args = ["name", "user"]
+
+ def run(self, name, user, force=False, credopts=None, sambaopts=None, versionopts=None):
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+ paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
+ sam = SamDB(paths.samdb, session_info=system_session(),
+ credentials=creds, lp=lp)
+ res = sam.search(expression="servicePrincipalName=%s" % name,
+ scope=ldb.SCOPE_SUBTREE,
+ )
+ if len(res) != 0 and not force:
+ raise CommandError("Service principal %s already"
+ " affected to another user" % name)
+
+ (cleaneduser, realm, domain) = _get_user_realm_domain(user)
+ res = sam.search(expression="samaccountname=%s" % cleaneduser,
+ scope=ldb.SCOPE_SUBTREE,
+ attrs=["servicePrincipalName"])
+ if len(res) >0:
+ res[0].dn
+ msg = ldb.Message()
+ spns = res[0].get("servicePrincipalName")
+ tab = []
+ found = False
+ flag = ldb.FLAG_MOD_ADD
+ if spns != None:
+ for e in spns:
+ if str(e) == name:
+ found = True
+ tab.append(str(e))
+ flag = ldb.FLAG_MOD_REPLACE
+ tab.append(name)
+ msg.dn = res[0].dn
+ msg["servicePrincipalName"] = ldb.MessageElement(tab, flag,
+ "servicePrincipalName")
+ if not found:
+ sam.modify(msg)
+ else:
+ raise CommandError("Service principal %s already"
+ " affected to %s" % (name, user))
+ else:
+ raise CommandError("User %s not found" % user)
+
+
+class cmd_spn_delete(Command):
+ """Delete a spn."""
+ synopsis = "%prog spn delete <name> [user]"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "credopts": options.CredentialsOptions,
+ "versionopts": options.VersionOptions,
+ }
+
+ takes_args = ["name", "user?"]
+
+ def run(self, name, user=None, credopts=None, sambaopts=None, versionopts=None):
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+ paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
+ sam = SamDB(paths.samdb, session_info=system_session(),
+ credentials=creds, lp=lp)
+ res = sam.search(expression="servicePrincipalName=%s" % name,
+ scope=ldb.SCOPE_SUBTREE,
+ attrs=["servicePrincipalName", "samAccountName"])
+ if len(res) >0:
+ result = None
+ if user is not None:
+ (cleaneduser, realm, domain) = _get_user_realm_domain(user)
+ for elem in res:
+ if str(elem["samAccountName"]).lower() == cleaneduser:
+ result = elem
+ if result is None:
+ raise CommandError("Unable to find user %s with"
+ " spn %s" % (user, name))
+ else:
+ if len(res) != 1:
+ listUser = ""
+ for r in res:
+ listUser = "%s\n%s" % (listUser, str(r.dn))
+ raise CommandError("More than one user has the spn %s "\
+ "and no specific user was specified, list of users"\
+ " with this spn:%s" % (name, listUser))
+ else:
+ result=res[0]
+
+
+ msg = ldb.Message()
+ spns = result.get("servicePrincipalName")
+ tab = []
+ if spns != None:
+ for e in spns:
+ if str(e) != name:
+ tab.append(str(e))
+ flag = ldb.FLAG_MOD_REPLACE
+ msg.dn = result.dn
+ msg["servicePrincipalName"] = ldb.MessageElement(tab, flag,
+ "servicePrincipalName")
+ sam.modify(msg)
+ else:
+ raise CommandError("Service principal %s not affected" % name)
+
+class cmd_spn(SuperCommand):
+ """User management [server connection needed]"""
+
+ subcommands = {}
+ subcommands["add"] = cmd_spn_add()
+ subcommands["list"] = cmd_spn_list()
+ subcommands["delete"] = cmd_spn_delete()
+
diff --git a/source4/selftest/tests.sh b/source4/selftest/tests.sh
index 3d331f34a9..c70eb877cf 100755
--- a/source4/selftest/tests.sh
+++ b/source4/selftest/tests.sh
@@ -520,6 +520,7 @@ plantestsuite "blackbox.upgradeprovision.py" none PYTHON="$PYTHON" $samba4srcdir
plantestsuite "blackbox.setpassword.py" none PYTHON="$PYTHON" $samba4srcdir/setup/tests/blackbox_setpassword.sh "$PREFIX/provision"
plantestsuite "blackbox.newuser.py" none PYTHON="$PYTHON" $samba4srcdir/setup/tests/blackbox_newuser.sh "$PREFIX/provision"
plantestsuite "blackbox.group.py" none PYTHON="$PYTHON" $samba4srcdir/setup/tests/blackbox_group.sh "$PREFIX/provision"
+plantestsuite "blackbox.spn.py" dc:local PYTHON="$PYTHON" $samba4srcdir/setup/tests/blackbox_spn.sh "$PREFIX/dc"
# DRS python tests
plantestsuite "drs_delete_object.python" vampire_dc PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" DC1=\$DC_SERVER DC2=\$VAMPIRE_DC_SERVER $SUBUNITRUN delete_object -U"\$DOMAIN/\$DC_USERNAME"%"\$DC_PASSWORD"
diff --git a/source4/setup/tests/blackbox_spn.sh b/source4/setup/tests/blackbox_spn.sh
new file mode 100755
index 0000000000..f2fd8acfbb
--- /dev/null
+++ b/source4/setup/tests/blackbox_spn.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+if [ $# -lt 1 ]; then
+cat <<EOF
+Usage: blackbox_group.sh PREFIX
+EOF
+exit 1;
+fi
+
+PREFIX="$1"
+shift 1
+
+. `dirname $0`/../../../testprogs/blackbox/subunit.sh
+
+
+net="./bin/net"
+
+CONFIG="--configfile=$PREFIX/etc/smb.conf"
+
+#creation of two test subjects
+testit "addspn" $net spn add FOO/bar Administrator $CONFIG
+testit "delspn" $net spn delete FOO/bar $CONFIG
+testit "readdspn" $net spn add FOO/bar Administrator $CONFIG
+testit_expect_failure "failexistingspn" $net spn add FOO/bar Guest $CONFIG
+testit "existingspnforce" $net spn add --force FOO/bar Guest $CONFIG
+testit_expect_failure "faildelspnnotgooduser" $net spn delete FOO/bar krbtgt $CONFIG
+testit_expect_failure "faildelspnmoreoneuser" $net spn delete FOO/bar $CONFIG
+testit "deluserspn" $net spn delete FOO/bar Guest $CONFIG
+testit "dellastuserspn" $net spn delete FOO/bar $CONFIG
+testit_expect_failure "faildelspn" $net spn delete FOO/bar $CONFIG
+testit_expect_failure "failaddspn" $net spn add FOO/bar nonexistinguser $CONFIG
+
+exit $failed