3 # rodc related commands
5 # Copyright Andrew Tridgell 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 from samba
.netcmd
import Command
, CommandError
, Option
, SuperCommand
23 import samba
.getopt
as options
24 from samba
.samdb
import SamDB
25 from samba
.auth
import system_session
27 from samba
.dcerpc
import misc
, drsuapi
28 from samba
.drs_utils
import drs_Replicate
31 class cmd_rodc_preload(Command
):
32 """Preload one account for an RODC"""
34 synopsis
= "%prog (<SID>|<DN>|<accountname>) [options]"
37 Option("--server", help="DC to use", type=str),
40 takes_args
= ["account"]
42 def get_dn(self
, samdb
, account
):
43 '''work out what DN they meant'''
45 # we accept the account in SID, accountname or DN form
46 if account
[0:2] == 'S-':
47 res
= samdb
.search(base
="<SID=%s>" % account
,
48 expression
="objectclass=user",
49 scope
=ldb
.SCOPE_BASE
, attrs
=[])
50 elif account
.find('=') >= 0:
51 res
= samdb
.search(base
=account
,
52 expression
="objectclass=user",
53 scope
=ldb
.SCOPE_BASE
, attrs
=[])
55 res
= samdb
.search(expression
="(&(samAccountName=%s)(objectclass=user))" % ldb
.binary_encode(account
),
56 scope
=ldb
.SCOPE_SUBTREE
, attrs
=[])
58 raise Exception("Failed to find account '%s'" % account
)
59 return str(res
[0]["dn"])
62 def get_dsServiceName(self
, samdb
):
63 res
= samdb
.search(base
="", scope
=ldb
.SCOPE_BASE
, attrs
=["dsServiceName"])
64 return res
[0]["dsServiceName"][0]
67 def run(self
, account
, sambaopts
=None,
68 credopts
=None, versionopts
=None, server
=None):
71 raise Exception("You must supply a server")
73 lp
= sambaopts
.get_loadparm()
75 creds
= credopts
.get_credentials(lp
, fallback_machine
=True)
77 # connect to the remote and local SAMs
78 samdb
= SamDB(url
="ldap://%s" % server
,
79 session_info
=system_session(),
80 credentials
=creds
, lp
=lp
)
82 local_samdb
= SamDB(url
=None, session_info
=system_session(),
83 credentials
=creds
, lp
=lp
)
85 # work out the source and destination GUIDs
86 dc_ntds_dn
= self
.get_dsServiceName(samdb
)
87 res
= samdb
.search(base
=dc_ntds_dn
, scope
=ldb
.SCOPE_BASE
, attrs
=["invocationId"])
88 source_dsa_invocation_id
= misc
.GUID(local_samdb
.schema_format_value("objectGUID", res
[0]["invocationId"][0]))
90 dn
= self
.get_dn(samdb
, account
)
91 self
.outf
.write("Replicating DN %s\n" % dn
)
93 destination_dsa_guid
= misc
.GUID(local_samdb
.get_ntds_GUID())
95 local_samdb
.transaction_start()
96 repl
= drs_Replicate("ncacn_ip_tcp:%s[seal,print]" % server
, lp
, creds
, local_samdb
)
98 repl
.replicate(dn
, source_dsa_invocation_id
, destination_dsa_guid
,
99 exop
=drsuapi
.DRSUAPI_EXOP_REPL_SECRET
, rodc
=True)
101 raise CommandError("Error replicating DN %s" % dn
, e
)
102 local_samdb
.transaction_commit()
106 class cmd_rodc(SuperCommand
):
107 """Read-Only Domain Controller (RODC) management"""
110 subcommands
["preload"] = cmd_rodc_preload()