samba-tool: add a function to cleanly demote a DC
[Samba/gebeck_regimport.git] / source4 / scripting / python / samba / netcmd / spn.py
blob0f01a49fc4a96b137b9f99d45fe1ed0ef1edb791
1 #!/usr/bin/env python
3 # spn management
5 # Copyright Matthieu Patou mat@samba.org 2010
6 # Copyright Giampaolo Lauria 2011 <lauria2@yahoo.com>
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 import samba.getopt as options
23 import ldb
24 from samba import provision
25 from samba.samdb import SamDB
26 from samba.auth import system_session
27 from samba.netcmd.common import _get_user_realm_domain
28 from samba.netcmd import (
29 Command,
30 CommandError,
31 SuperCommand,
32 Option
36 class cmd_spn_list(Command):
37 """List spns of a given user."""
39 synopsis = "%prog <user> [options]"
41 takes_args = ["user"]
43 def run(self, user, credopts=None, sambaopts=None, versionopts=None):
44 lp = sambaopts.get_loadparm()
45 creds = credopts.get_credentials(lp)
46 paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
47 sam = SamDB(paths.samdb, session_info=system_session(),
48 credentials=creds, lp=lp)
49 # TODO once I understand how, use the domain info to naildown
50 # to the correct domain
51 (cleaneduser, realm, domain) = _get_user_realm_domain(user)
52 self.outf.write(cleaneduser+"\n")
53 res = sam.search(expression="samaccountname=%s" % ldb.binary_encode(cleaneduser),
54 scope=ldb.SCOPE_SUBTREE,
55 attrs=["servicePrincipalName"])
56 if len(res) >0:
57 spns = res[0].get("servicePrincipalName")
58 found = False
59 flag = ldb.FLAG_MOD_ADD
60 if spns != None:
61 self.outf.write(
62 "User %s has the following servicePrincipalName: \n" %
63 res[0].dn)
64 for e in spns:
65 self.outf.write("\t %s\n" % e)
66 else:
67 self.outf.write("User %s has no servicePrincipalName" %
68 res[0].dn)
69 else:
70 raise CommandError("User %s not found" % user)
73 class cmd_spn_add(Command):
74 """Create a new spn."""
76 synopsis = "%prog <name> <user> [options]"
78 takes_options = [
79 Option("--force", help="Force the addition of the spn"\
80 " even it exists already", action="store_true"),
82 takes_args = ["name", "user"]
84 def run(self, name, user, force=False, credopts=None, sambaopts=None, versionopts=None):
85 lp = sambaopts.get_loadparm()
86 creds = credopts.get_credentials(lp)
87 paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
88 sam = SamDB(paths.samdb, session_info=system_session(),
89 credentials=creds, lp=lp)
90 res = sam.search(expression="servicePrincipalName=%s" % ldb.binary_encode(name),
91 scope=ldb.SCOPE_SUBTREE,
93 if len(res) != 0 and not force:
94 raise CommandError("Service principal %s already"
95 " affected to another user" % name)
97 (cleaneduser, realm, domain) = _get_user_realm_domain(user)
98 res = sam.search(expression="samaccountname=%s" % ldb.binary_encode(cleaneduser),
99 scope=ldb.SCOPE_SUBTREE,
100 attrs=["servicePrincipalName"])
101 if len(res) >0:
102 res[0].dn
103 msg = ldb.Message()
104 spns = res[0].get("servicePrincipalName")
105 tab = []
106 found = False
107 flag = ldb.FLAG_MOD_ADD
108 if spns != None:
109 for e in spns:
110 if str(e) == name:
111 found = True
112 tab.append(str(e))
113 flag = ldb.FLAG_MOD_REPLACE
114 tab.append(name)
115 msg.dn = res[0].dn
116 msg["servicePrincipalName"] = ldb.MessageElement(tab, flag,
117 "servicePrincipalName")
118 if not found:
119 sam.modify(msg)
120 else:
121 raise CommandError("Service principal %s already"
122 " affected to %s" % (name, user))
123 else:
124 raise CommandError("User %s not found" % user)
127 class cmd_spn_delete(Command):
128 """Delete a spn."""
130 synopsis = "%prog <name> [user] [options]"
132 takes_args = ["name", "user?"]
134 def run(self, name, user=None, credopts=None, sambaopts=None, versionopts=None):
135 lp = sambaopts.get_loadparm()
136 creds = credopts.get_credentials(lp)
137 paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
138 sam = SamDB(paths.samdb, session_info=system_session(),
139 credentials=creds, lp=lp)
140 res = sam.search(expression="servicePrincipalName=%s" % ldb.binary_encode(name),
141 scope=ldb.SCOPE_SUBTREE,
142 attrs=["servicePrincipalName", "samAccountName"])
143 if len(res) >0:
144 result = None
145 if user is not None:
146 (cleaneduser, realm, domain) = _get_user_realm_domain(user)
147 for elem in res:
148 if str(elem["samAccountName"]).lower() == cleaneduser:
149 result = elem
150 if result is None:
151 raise CommandError("Unable to find user %s with"
152 " spn %s" % (user, name))
153 else:
154 if len(res) != 1:
155 listUser = ""
156 for r in res:
157 listUser = "%s\n%s" % (listUser, str(r.dn))
158 raise CommandError("More than one user has the spn %s "\
159 "and no specific user was specified, list of users"\
160 " with this spn:%s" % (name, listUser))
161 else:
162 result=res[0]
165 msg = ldb.Message()
166 spns = result.get("servicePrincipalName")
167 tab = []
168 if spns != None:
169 for e in spns:
170 if str(e) != name:
171 tab.append(str(e))
172 flag = ldb.FLAG_MOD_REPLACE
173 msg.dn = result.dn
174 msg["servicePrincipalName"] = ldb.MessageElement(tab, flag,
175 "servicePrincipalName")
176 sam.modify(msg)
177 else:
178 raise CommandError("Service principal %s not affected" % name)
181 class cmd_spn(SuperCommand):
182 """Service Principal Name (SPN) management"""
184 subcommands = {}
185 subcommands["add"] = cmd_spn_add()
186 subcommands["list"] = cmd_spn_list()
187 subcommands["delete"] = cmd_spn_delete()