a6105882bb52e797ff7867547d39e12d13a4f2bc
[samba.git] / source4 / scripting / python / samba / netcmd / fsmo.py
1 # Changes a FSMO role owner
2 #
3 # Copyright Nadezhda Ivanova 2009
4 # Copyright Jelmer Vernooij 2009
5 #
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.
10 #
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.
15 #
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/>.
18 #
19
20 import samba.getopt as options
21 import ldb
22 from ldb import LdbError
23
24 from samba.auth import system_session
25 from samba.netcmd import (
26     Command,
27     CommandError,
28     SuperCommand,
29     Option,
30     )
31 from samba.samdb import SamDB
32
33 def transfer_role(outf, role, samdb):
34     m = ldb.Message()
35     m.dn = ldb.Dn(samdb, "")
36     if role == "rid":
37         m["becomeRidMaster"]= ldb.MessageElement(
38             "1", ldb.FLAG_MOD_REPLACE,
39             "becomeRidMaster")
40     elif role == "pdc":
41         domain_dn = samdb.domain_dn()
42         res = samdb.search(domain_dn,
43                            scope=ldb.SCOPE_BASE, attrs=["objectSid"])
44         assert len(res) == 1
45         sid = res[0]["objectSid"][0]
46         m["becomePdc"]= ldb.MessageElement(
47             sid, ldb.FLAG_MOD_REPLACE,
48             "becomePdc")
49     elif role == "naming":
50         m["becomeDomainMaster"]= ldb.MessageElement(
51             "1", ldb.FLAG_MOD_REPLACE,
52             "becomeDomainMaster")
53         samdb.modify(m)
54     elif role == "infrastructure":
55         m["becomeInfrastructureMaster"]= ldb.MessageElement(
56             "1", ldb.FLAG_MOD_REPLACE,
57             "becomeInfrastructureMaster")
58     elif role == "schema":
59         m["becomeSchemaMaster"]= ldb.MessageElement(
60             "1", ldb.FLAG_MOD_REPLACE,
61             "becomeSchemaMaster")
62     else:
63         raise CommandError("Invalid FSMO role.")
64     try:
65         samdb.modify(m)
66     except LdbError, (num, msg):
67         raise CommandError("Failed to initiate transfer of '%s' role: %s" % (role, msg))
68     outf.write("FSMO transfer of '%s' role successful\n" % role)
69
70
71 class cmd_fsmo_seize(Command):
72     """Seize the role"""
73
74     synopsis = "%prog [options]"
75
76     takes_optiongroups = {
77         "sambaopts": options.SambaOptions,
78         "credopts": options.CredentialsOptions,
79         "versionopts": options.VersionOptions,
80         }
81
82     takes_options = [
83         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
84                metavar="URL", dest="H"),
85         Option("--force", help="Force seizing of the role without attempting to transfer first.", action="store_true"),
86         Option("--role", type="choice", choices=["rid", "pdc", "infrastructure","schema","naming","all"],
87                help="""The FSMO role to seize or transfer.\n
88 rid=RidAllocationMasterRole\n
89 schema=SchemaMasterRole\n
90 pdc=PdcEmulationMasterRole\n
91 naming=DomainNamingMasterRole\n
92 infrastructure=InfrastructureMasterRole\n
93 all=all of the above"""),
94         ]
95
96     takes_args = []
97
98     def seize_role(self, role, samdb, force):
99         res = samdb.search("",
100                            scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
101         assert len(res) == 1
102         serviceName = res[0]["dsServiceName"][0]
103         domain_dn = samdb.domain_dn()
104         self.infrastructure_dn = "CN=Infrastructure," + domain_dn
105         self.naming_dn = "CN=Partitions,%s" % samdb.get_config_basedn()
106         self.schema_dn = samdb.get_schema_basedn()
107         self.rid_dn = "CN=RID Manager$,CN=System," + domain_dn
108
109         m = ldb.Message()
110         if role == "rid":
111             m.dn = ldb.Dn(samdb, self.rid_dn)
112         elif role == "pdc":
113             m.dn = ldb.Dn(samdb, domain_dn)
114         elif role == "naming":
115             m.dn = ldb.Dn(samdb, self.naming_dn)
116         elif role == "infrastructure":
117             m.dn = ldb.Dn(samdb, self.infrastructure_dn)
118         elif role == "schema":
119             m.dn = ldb.Dn(samdb, self.schema_dn)
120         else:
121             raise CommandError("Invalid FSMO role.")
122         #first try to transfer to avoid problem if the owner is still active
123         if force is None:
124             self.message("Attempting transfer...")
125             try:
126                 transfer_role(self.outf, role, samdb)
127             except CommandError:
128             #transfer failed, use the big axe...
129                 self.message("Transfer unsuccessful, seizing...")
130                 m["fSMORoleOwner"]= ldb.MessageElement(
131                     serviceName, ldb.FLAG_MOD_REPLACE,
132                     "fSMORoleOwner")
133         else:
134             self.message("Will not attempt transfer, seizing...")
135             m["fSMORoleOwner"]= ldb.MessageElement(
136                 serviceName, ldb.FLAG_MOD_REPLACE,
137                 "fSMORoleOwner")
138         try:
139             samdb.modify(m)
140         except LdbError, (num, msg):
141             raise CommandError("Failed to initiate role seize of '%s' role: %s" % (role, msg))
142         self.outf.write("FSMO transfer of '%s' role successful\n" % role)
143
144     def run(self, force=None, H=None, role=None,
145             credopts=None, sambaopts=None, versionopts=None):
146
147         lp = sambaopts.get_loadparm()
148         creds = credopts.get_credentials(lp, fallback_machine=True)
149
150         samdb = SamDB(url=H, session_info=system_session(),
151                       credentials=creds, lp=lp)
152
153         if role == "all":
154             self.seize_role("rid", samdb, force)
155             self.seize_role("pdc", samdb, force)
156             self.seize_role("naming", samdb, force)
157             self.seize_role("infrastructure", samdb, force)
158             self.seize_role("schema", samdb, force)
159         else:
160             self.seize_role(role, samdb, force)
161
162
163 class cmd_fsmo_show(Command):
164     """Show the roles"""
165
166     synopsis = "%prog [options]"
167
168     takes_optiongroups = {
169         "sambaopts": options.SambaOptions,
170         "credopts": options.CredentialsOptions,
171         "versionopts": options.VersionOptions,
172         }
173
174     takes_options = [
175         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
176                metavar="URL", dest="H"),
177         ]
178
179     takes_args = []
180
181     def run(self, H=None, credopts=None, sambaopts=None, versionopts=None):
182         lp = sambaopts.get_loadparm()
183         creds = credopts.get_credentials(lp, fallback_machine=True)
184
185         samdb = SamDB(url=H, session_info=system_session(),
186             credentials=creds, lp=lp)
187
188         domain_dn = samdb.domain_dn()
189         self.infrastructure_dn = "CN=Infrastructure," + domain_dn
190         self.naming_dn = "CN=Partitions,%s" % samdb.get_config_basedn()
191         self.schema_dn = samdb.get_schema_basedn()
192         self.rid_dn = "CN=RID Manager$,CN=System," + domain_dn
193
194         res = samdb.search(self.infrastructure_dn,
195                            scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
196         assert len(res) == 1
197         self.infrastructureMaster = res[0]["fSMORoleOwner"][0]
198
199         res = samdb.search(domain_dn,
200                            scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
201         assert len(res) == 1
202         self.pdcEmulator = res[0]["fSMORoleOwner"][0]
203
204         res = samdb.search(self.naming_dn,
205                            scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
206         assert len(res) == 1
207         self.namingMaster = res[0]["fSMORoleOwner"][0]
208
209         res = samdb.search(self.schema_dn,
210                            scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
211         assert len(res) == 1
212         self.schemaMaster = res[0]["fSMORoleOwner"][0]
213
214         res = samdb.search(self.rid_dn,
215                            scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
216         assert len(res) == 1
217         self.ridMaster = res[0]["fSMORoleOwner"][0]
218
219         self.message("InfrastructureMasterRole owner: " + self.infrastructureMaster)
220         self.message("RidAllocationMasterRole owner: " + self.ridMaster)
221         self.message("PdcEmulationMasterRole owner: " + self.pdcEmulator)
222         self.message("DomainNamingMasterRole owner: " + self.namingMaster)
223         self.message("SchemaMasterRole owner: " + self.schemaMaster)
224
225
226 class cmd_fsmo_transfer(Command):
227     """Transfer the role"""
228
229     synopsis = "%prog [options]"
230
231     takes_optiongroups = {
232         "sambaopts": options.SambaOptions,
233         "credopts": options.CredentialsOptions,
234         "versionopts": options.VersionOptions,
235         }
236
237     takes_options = [
238         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
239                metavar="URL", dest="H"),
240         Option("--role", type="choice", choices=["rid", "pdc", "infrastructure","schema","naming","all"],
241                help="""The FSMO role to seize or transfer.\n
242 rid=RidAllocationMasterRole\n
243 schema=SchemaMasterRole\n
244 pdc=PdcEmulationMasterRole\n
245 naming=DomainNamingMasterRole\n
246 infrastructure=InfrastructureMasterRole\n
247 all=all of the above"""),
248         ]
249
250     takes_args = []
251
252     def run(self, force=None, H=None, role=None,
253             credopts=None, sambaopts=None, versionopts=None):
254
255         lp = sambaopts.get_loadparm()
256         creds = credopts.get_credentials(lp, fallback_machine=True)
257
258         samdb = SamDB(url=H, session_info=system_session(),
259                       credentials=creds, lp=lp)
260
261         if role == "all":
262             transfer_role(self.outf, "rid", samdb)
263             transfer_role(self.outf, "pdc", samdb)
264             transfer_role(self.outf, "naming", samdb)
265             transfer_role(self.outf, "infrastructure", samdb)
266             transfer_role(self.outf, "schema", samdb)
267         else:
268             transfer_role(self.outf, role, samdb)
269
270
271 class cmd_fsmo(SuperCommand):
272     """Flexible Single Master Operations (FSMO) roles management"""
273
274     subcommands = {}
275     subcommands["seize"] = cmd_fsmo_seize()
276     subcommands["show"] = cmd_fsmo_show()
277     subcommands["transfer"] = cmd_fsmo_transfer()