nfs4acls: Use talloc_realloc()
[Samba.git] / python / samba / netcmd / fsmo.py
blob0b4488f7853f4c464725286f2e118f791630f4b7
1 # Changes a FSMO role owner
3 # Copyright Nadezhda Ivanova 2009
4 # Copyright Jelmer Vernooij 2009
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 import samba
21 import samba.getopt as options
22 import ldb
23 from ldb import LdbError
24 from samba.dcerpc import drsuapi, misc
25 from samba.auth import system_session
26 from samba.netcmd import (
27 Command,
28 CommandError,
29 SuperCommand,
30 Option,
32 from samba.samdb import SamDB
34 def get_fsmo_roleowner(samdb, roledn):
35 """Gets the owner of an FSMO role
37 :param roledn: The DN of the FSMO role
38 """
39 res = samdb.search(roledn,
40 scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
41 assert len(res) == 1
42 master_owner = res[0]["fSMORoleOwner"][0]
43 return master_owner
46 def transfer_dns_role(outf, sambaopts, credopts, role, samdb):
47 """Transfer dns FSMO role. """
49 if role == "domaindns":
50 domain_dn = samdb.domain_dn()
51 role_object = "CN=Infrastructure,DC=DomainDnsZones," + domain_dn
52 elif role == "forestdns":
53 forest_dn = samba.dn_from_dns_name(samdb.forest_dns_name())
54 role_object = "CN=Infrastructure,DC=ForestDnsZones," + forest_dn
56 try:
57 res = samdb.search(role_object,
58 attrs=["fSMORoleOwner"],
59 scope=ldb.SCOPE_BASE,
60 controls=["extended_dn:1:1"])
62 if 'fSMORoleOwner' in res[0]:
63 try:
64 master_guid = str(misc.GUID(ldb.Dn(samdb,
65 res[0]['fSMORoleOwner'][0])
66 .get_extended_component('GUID')))
67 master_owner = str(ldb.Dn(samdb, res[0]['fSMORoleOwner'][0]))
68 except LdbError, (num, msg):
69 raise CommandError("GUID not found in partition naming master DN %s : %s \n" %
70 (res[0]['fSMORoleOwner'][0], msg))
71 except LdbError, (num, msg):
72 raise CommandError("DNS partion %s not found : %s" % (role, msg))
74 if role == "domaindns":
75 master_dns_name = '%s._msdcs.%s' % (master_guid,
76 samdb.domain_dns_name())
77 new_dns_name = '%s._msdcs.%s' % (samdb.get_ntds_GUID(),
78 samdb.domain_dns_name())
79 elif role == "forestdns":
80 master_dns_name = '%s._msdcs.%s' % (master_guid,
81 samdb.forest_dns_name())
82 new_dns_name = '%s._msdcs.%s' % (samdb.get_ntds_GUID(),
83 samdb.forest_dns_name())
85 new_owner = samdb.get_dsServiceName()
87 if master_dns_name != new_dns_name:
88 lp = sambaopts.get_loadparm()
89 creds = credopts.get_credentials(lp, fallback_machine=True)
90 samdb = SamDB(url="ldap://%s" % (master_dns_name),
91 session_info=system_session(),
92 credentials=creds, lp=lp)
94 m = ldb.Message()
95 m.dn = ldb.Dn(samdb, role_object)
96 m["fSMORoleOwner"] = ldb.MessageElement(master_owner,
97 ldb.FLAG_MOD_DELETE,
98 "fSMORoleOwner")
100 try:
101 samdb.modify(m)
102 except LdbError, (num, msg):
103 raise CommandError("Failed to delete role '%s': %s" %
104 (role, msg))
106 m = ldb.Message()
107 m.dn = ldb.Dn(samdb, role_object)
108 m["fSMORoleOwner"]= ldb.MessageElement(new_owner,
109 ldb.FLAG_MOD_ADD,
110 "fSMORoleOwner")
111 try:
112 samdb.modify(m)
113 except LdbError, (num, msg):
114 raise CommandError("Failed to add role '%s': %s" % (role, msg))
116 try:
117 connection = samba.drs_utils.drsuapi_connect(samdb.host_dns_name(),
118 lp, creds)
119 except samba.drs_utils.drsException, e:
120 raise CommandError("Drsuapi Connect failed", e)
122 try:
123 drsuapi_connection = connection[0]
124 drsuapi_handle = connection[1]
125 req_options = drsuapi.DRSUAPI_DRS_WRIT_REP
126 NC = role_object[18:]
127 samba.drs_utils.sendDsReplicaSync(drsuapi_connection,
128 drsuapi_handle,
129 master_guid,
130 NC, req_options)
131 except samba.drs_utils.drsException, estr:
132 raise CommandError("Replication failed", estr)
134 outf.write("FSMO transfer of '%s' role successful\n" % role)
135 return True
136 else:
137 outf.write("This DC already has the '%s' FSMO role\n" % role)
138 return False
140 def transfer_role(outf, role, samdb):
141 """Transfer standard FSMO role. """
143 domain_dn = samdb.domain_dn()
144 rid_dn = "CN=RID Manager$,CN=System," + domain_dn
145 naming_dn = "CN=Partitions,%s" % samdb.get_config_basedn()
146 infrastructure_dn = "CN=Infrastructure," + domain_dn
147 schema_dn = str(samdb.get_schema_basedn())
148 new_owner = samdb.get_dsServiceName()
149 m = ldb.Message()
150 m.dn = ldb.Dn(samdb, "")
151 if role == "rid":
152 master_owner = get_fsmo_roleowner(samdb, rid_dn)
153 m["becomeRidMaster"]= ldb.MessageElement(
154 "1", ldb.FLAG_MOD_REPLACE,
155 "becomeRidMaster")
156 elif role == "pdc":
157 master_owner = get_fsmo_roleowner(samdb, domain_dn)
159 res = samdb.search(domain_dn,
160 scope=ldb.SCOPE_BASE, attrs=["objectSid"])
161 assert len(res) == 1
162 sid = res[0]["objectSid"][0]
163 m["becomePdc"]= ldb.MessageElement(
164 sid, ldb.FLAG_MOD_REPLACE,
165 "becomePdc")
166 elif role == "naming":
167 master_owner = get_fsmo_roleowner(samdb, naming_dn)
168 m["becomeDomainMaster"]= ldb.MessageElement(
169 "1", ldb.FLAG_MOD_REPLACE,
170 "becomeDomainMaster")
171 elif role == "infrastructure":
172 master_owner = get_fsmo_roleowner(samdb, infrastructure_dn)
173 m["becomeInfrastructureMaster"]= ldb.MessageElement(
174 "1", ldb.FLAG_MOD_REPLACE,
175 "becomeInfrastructureMaster")
176 elif role == "schema":
177 master_owner = get_fsmo_roleowner(samdb, schema_dn)
178 m["becomeSchemaMaster"]= ldb.MessageElement(
179 "1", ldb.FLAG_MOD_REPLACE,
180 "becomeSchemaMaster")
181 else:
182 raise CommandError("Invalid FSMO role.")
184 if master_owner != new_owner:
185 try:
186 samdb.modify(m)
187 except LdbError, (num, msg):
188 raise CommandError("Transfer of '%s' role failed: %s" %
189 (role, msg))
191 outf.write("FSMO transfer of '%s' role successful\n" % role)
192 return True
193 else:
194 outf.write("This DC already has the '%s' FSMO role\n" % role)
195 return False
197 class cmd_fsmo_seize(Command):
198 """Seize the role."""
200 synopsis = "%prog [options]"
202 takes_optiongroups = {
203 "sambaopts": options.SambaOptions,
204 "credopts": options.CredentialsOptions,
205 "versionopts": options.VersionOptions,
208 takes_options = [
209 Option("-H", "--URL", help="LDB URL for database or target server",
210 type=str, metavar="URL", dest="H"),
211 Option("--force",
212 help="Force seizing of the role without attempting to transfer first.",
213 action="store_true"),
214 Option("--role", type="choice", choices=["rid", "pdc", "infrastructure",
215 "schema", "naming", "domaindns", "forestdns", "all"],
216 help="""The FSMO role to seize or transfer.\n
217 rid=RidAllocationMasterRole\n
218 schema=SchemaMasterRole\n
219 pdc=PdcEmulationMasterRole\n
220 naming=DomainNamingMasterRole\n
221 infrastructure=InfrastructureMasterRole\n
222 domaindns=DomainDnsZonesMasterRole\n
223 forestdns=ForestDnsZonesMasterRole\n
224 all=all of the above\n
225 You must provide an Admin user and password."""),
228 takes_args = []
230 def seize_role(self, role, samdb, force):
231 """Seize standard fsmo role. """
233 serviceName = samdb.get_dsServiceName()
234 domain_dn = samdb.domain_dn()
235 self.infrastructure_dn = "CN=Infrastructure," + domain_dn
236 self.naming_dn = "CN=Partitions,%s" % samdb.get_config_basedn()
237 self.schema_dn = str(samdb.get_schema_basedn())
238 self.rid_dn = "CN=RID Manager$,CN=System," + domain_dn
240 m = ldb.Message()
241 if role == "rid":
242 m.dn = ldb.Dn(samdb, self.rid_dn)
243 elif role == "pdc":
244 m.dn = ldb.Dn(samdb, domain_dn)
245 elif role == "naming":
246 m.dn = ldb.Dn(samdb, self.naming_dn)
247 elif role == "infrastructure":
248 m.dn = ldb.Dn(samdb, self.infrastructure_dn)
249 elif role == "schema":
250 m.dn = ldb.Dn(samdb, self.schema_dn)
251 else:
252 raise CommandError("Invalid FSMO role.")
253 #first try to transfer to avoid problem if the owner is still active
254 seize = False
255 master_owner = get_fsmo_roleowner(samdb, m.dn)
256 if master_owner != serviceName:
257 if force is None:
258 self.message("Attempting transfer...")
259 if not transfer_role(self.outf, role, samdb):
260 #transfer failed, use the big axe...
261 seize = True
262 self.message("Transfer unsuccessful, seizing...")
263 else:
264 self.message("Not seizing role as transfer was successful")
266 if force is not None or seize == True:
267 self.message("Seizing %s FSMO role..." % role)
268 m["fSMORoleOwner"]= ldb.MessageElement(
269 serviceName, ldb.FLAG_MOD_REPLACE,
270 "fSMORoleOwner")
271 try:
272 samdb.modify(m)
273 except LdbError, (num, msg):
274 raise CommandError("Failed to seize '%s' role: %s" %
275 (role, msg))
276 self.outf.write("FSMO seize of '%s' role successful\n" % role)
277 return True
278 else:
279 self.outf.write("This DC already has the '%s' FSMO role\n" % role)
280 return False
282 def seize_dns_role(self, role, samdb, credopts, sambaopts,
283 versionopts, force):
284 """Seize DNS FSMO role. """
286 serviceName = samdb.get_dsServiceName()
287 domain_dn = samdb.domain_dn()
288 forest_dn = samba.dn_from_dns_name(samdb.forest_dns_name())
289 self.domaindns_dn = "CN=Infrastructure,DC=DomainDnsZones," + domain_dn
290 self.forestdns_dn = "CN=Infrastructure,DC=ForestDnsZones," + forest_dn
292 m = ldb.Message()
293 if role == "domaindns":
294 m.dn = ldb.Dn(samdb, self.domaindns_dn)
295 elif role == "forestdns":
296 m.dn = ldb.Dn(samdb, self.forestdns_dn)
297 else:
298 raise CommandError("Invalid FSMO role.")
299 #first try to transfer to avoid problem if the owner is still active
300 seize = False
301 master_owner = get_fsmo_roleowner(samdb, m.dn)
302 if master_owner != serviceName:
303 if force is None:
304 self.message("Attempting transfer...")
305 if not transfer_dns_role(self.outf, sambaopts, credopts, role,
306 samdb):
307 #transfer failed, use the big axe...
308 seize = True
309 self.message("Transfer unsuccessful, seizing...")
310 else:
311 self.message("Not seizing role as transfer was successful\n")
313 if force is not None or seize == True:
314 self.message("Seizing %s FSMO role..." % role)
315 m["fSMORoleOwner"]= ldb.MessageElement(
316 serviceName, ldb.FLAG_MOD_REPLACE,
317 "fSMORoleOwner")
318 try:
319 samdb.modify(m)
320 except LdbError, (num, msg):
321 raise CommandError("Failed to seize '%s' role: %s" %
322 (role, msg))
323 self.outf.write("FSMO seize of '%s' role successful\n" % role)
324 return True
325 else:
326 self.outf.write("This DC already has the '%s' FSMO role\n" % role)
327 return False
329 def run(self, force=None, H=None, role=None,
330 credopts=None, sambaopts=None, versionopts=None):
332 lp = sambaopts.get_loadparm()
333 creds = credopts.get_credentials(lp, fallback_machine=True)
335 samdb = SamDB(url=H, session_info=system_session(),
336 credentials=creds, lp=lp)
338 if role == "all":
339 self.seize_role("rid", samdb, force)
340 self.seize_role("pdc", samdb, force)
341 self.seize_role("naming", samdb, force)
342 self.seize_role("infrastructure", samdb, force)
343 self.seize_role("schema", samdb, force)
344 self.seize_dns_role("domaindns", samdb, credopts, sambaopts,
345 versionopts, force)
346 self.seize_dns_role("forestdns", samdb, credopts, sambaopts,
347 versionopts, force)
348 else:
349 if role == "domaindns" or role == "forestdns":
350 self.seize_dns_role(role, samdb, credopts, sambaopts,
351 versionopts, force)
352 else:
353 self.seize_role(role, samdb, force)
356 class cmd_fsmo_show(Command):
357 """Show the roles."""
359 synopsis = "%prog [options]"
361 takes_optiongroups = {
362 "sambaopts": options.SambaOptions,
363 "credopts": options.CredentialsOptions,
364 "versionopts": options.VersionOptions,
367 takes_options = [
368 Option("-H", "--URL", help="LDB URL for database or target server",
369 type=str, metavar="URL", dest="H"),
372 takes_args = []
374 def run(self, H=None, credopts=None, sambaopts=None, versionopts=None):
375 lp = sambaopts.get_loadparm()
376 creds = credopts.get_credentials(lp, fallback_machine=True)
378 samdb = SamDB(url=H, session_info=system_session(),
379 credentials=creds, lp=lp)
381 domain_dn = samdb.domain_dn()
382 forest_dn = samba.dn_from_dns_name(samdb.forest_dns_name())
383 infrastructure_dn = "CN=Infrastructure," + domain_dn
384 naming_dn = "CN=Partitions,%s" % samdb.get_config_basedn()
385 schema_dn = samdb.get_schema_basedn()
386 rid_dn = "CN=RID Manager$,CN=System," + domain_dn
387 domaindns_dn = "CN=Infrastructure,DC=DomainDnsZones," + domain_dn
388 forestdns_dn = "CN=Infrastructure,DC=ForestDnsZones," + forest_dn
390 infrastructureMaster = get_fsmo_roleowner(samdb, infrastructure_dn)
391 pdcEmulator = get_fsmo_roleowner(samdb, domain_dn)
392 namingMaster = get_fsmo_roleowner(samdb, naming_dn)
393 schemaMaster = get_fsmo_roleowner(samdb, schema_dn)
394 ridMaster = get_fsmo_roleowner(samdb, rid_dn)
395 domaindnszonesMaster = get_fsmo_roleowner(samdb, domaindns_dn)
396 forestdnszonesMaster = get_fsmo_roleowner(samdb, forestdns_dn)
398 self.message("SchemaMasterRole owner: " + schemaMaster)
399 self.message("InfrastructureMasterRole owner: " + infrastructureMaster)
400 self.message("RidAllocationMasterRole owner: " + ridMaster)
401 self.message("PdcEmulationMasterRole owner: " + pdcEmulator)
402 self.message("DomainNamingMasterRole owner: " + namingMaster)
403 self.message("DomainDnsZonesMasterRole owner: " + domaindnszonesMaster)
404 self.message("ForestDnsZonesMasterRole owner: " + forestdnszonesMaster)
406 class cmd_fsmo_transfer(Command):
407 """Transfer the role."""
409 synopsis = "%prog [options]"
411 takes_optiongroups = {
412 "sambaopts": options.SambaOptions,
413 "credopts": options.CredentialsOptions,
414 "versionopts": options.VersionOptions,
417 takes_options = [
418 Option("-H", "--URL", help="LDB URL for database or target server",
419 type=str, metavar="URL", dest="H"),
420 Option("--role", type="choice", choices=["rid", "pdc", "infrastructure",
421 "schema", "naming", "domaindns", "forestdns", "all"],
422 help="""The FSMO role to seize or transfer.\n
423 rid=RidAllocationMasterRole\n
424 schema=SchemaMasterRole\n
425 pdc=PdcEmulationMasterRole\n
426 naming=DomainNamingMasterRole\n
427 infrastructure=InfrastructureMasterRole\n
428 domaindns=DomainDnsZonesMasterRole\n
429 forestdns=ForestDnsZonesMasterRole\n
430 all=all of the above\n
431 You must provide an Admin user and password."""),
434 takes_args = []
436 def run(self, force=None, H=None, role=None,
437 credopts=None, sambaopts=None, versionopts=None):
439 lp = sambaopts.get_loadparm()
440 creds = credopts.get_credentials(lp, fallback_machine=True)
442 samdb = SamDB(url=H, session_info=system_session(),
443 credentials=creds, lp=lp)
445 if role == "all":
446 transfer_role(self.outf, "rid", samdb)
447 transfer_role(self.outf, "pdc", samdb)
448 transfer_role(self.outf, "naming", samdb)
449 transfer_role(self.outf, "infrastructure", samdb)
450 transfer_role(self.outf, "schema", samdb)
451 transfer_dns_role(self.outf, sambaopts, credopts, "domaindns", samdb)
452 transfer_dns_role(self.outf, sambaopts, credopts, "forestdns", samdb)
453 else:
454 if role == "domaindns" or role == "forestdns":
455 transfer_dns_role(self.outf, sambaopts, credopts, role, samdb)
456 else:
457 transfer_role(self.outf, role, samdb)
460 class cmd_fsmo(SuperCommand):
461 """Flexible Single Master Operations (FSMO) roles management."""
463 subcommands = {}
464 subcommands["seize"] = cmd_fsmo_seize()
465 subcommands["show"] = cmd_fsmo_show()
466 subcommands["transfer"] = cmd_fsmo_transfer()