4 # Copyright (C) Matthieu Patou <mat@matws.net> 2011
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/>.
22 # Allow to run from s4 source directory (without installing samba)
23 sys
.path
.insert(0, "bin/python")
27 import samba
.getopt
as options
30 from samba
.credentials
import DONT_USE_KERBEROS
31 from samba
.auth
import system_session
32 from samba
import param
33 from samba
.provision
import find_provision_key_parameters
, secretsdb_self_join
34 from samba
.upgradehelpers
import get_ldbs
, get_paths
37 __docformat__
= "restructuredText"
39 parser
= optparse
.OptionParser("provision [options]")
40 sambaopts
= options
.SambaOptions(parser
)
41 parser
.add_option_group(sambaopts
)
42 parser
.add_option_group(options
.VersionOptions(parser
))
43 credopts
= options
.CredentialsOptions(parser
)
44 parser
.add_option_group(credopts
)
45 parser
.add_option("--oldname",
47 parser
.add_option("--newname",
50 opts
= parser
.parse_args()[0]
52 if len(sys
.argv
) == 1:
53 opts
.interactive
= True
54 lp
= sambaopts
.get_loadparm()
55 smbconf
= lp
.configfile
57 creds
= credopts
.get_credentials(lp
)
58 creds
.set_kerberos_state(DONT_USE_KERBEROS
)
61 if __name__
== '__main__':
64 # 1) First get files paths
65 paths
= get_paths(param
, smbconf
=smbconf
)
66 # Get ldbs with the system session, it is needed for searching
67 # provision parameters
68 session
= system_session()
70 ldbs
= get_ldbs(paths
, creds
, session
, lp
)
71 ldbs
.sam
.transaction_start()
72 ldbs
.secrets
.transaction_start()
74 if opts
.oldname
is None or opts
.newname
is None:
75 raise Exception("Option oldname or newname is missing")
76 res
= ldbs
.sam
.search(expression
="(&(name=%s)(serverReferenceBL=*))" % opts
.oldname
)
77 if res
is None or len(res
) != 1:
78 raise Exception("Wrong number of result returned, are you sure of the old name %s" %
81 # Ok got it then check that the new name is not used as well
82 res2
= ldbs
.sam
.search(expression
="(&(name=%s)(objectclass=computer))" % opts
.newname
)
84 raise Exception("Seems that %s is a name that already exists, pick another one" %
87 names
= find_provision_key_parameters(ldbs
.sam
, ldbs
.secrets
, ldbs
.idmap
,
90 # First rename the entry
91 # provision put the name in upper case so let's do it too !
92 newdn
= str(res
[0].dn
).replace("CN=%s" % opts
.oldname
, "CN=%s" % opts
.newname
.upper())
93 dnobj
= ldb
.Dn(ldbs
.sam
, newdn
)
94 ldbs
.sam
.rename(res
[0].dn
, dnobj
)
96 # Then change password and samaccountname and dnshostname
97 msg
= ldb
.Message(dnobj
)
98 machinepass
= samba
.generate_random_password(128, 255)
99 mputf16
= machinepass
.encode('utf-16-le')
101 account
= "%s$" % opts
.newname
.upper()
102 msg
["clearTextPassword"] = ldb
.MessageElement(mputf16
,
103 ldb
.FLAG_MOD_REPLACE
,
106 msg
["sAMAccountName"] = ldb
.MessageElement(account
,
107 ldb
.FLAG_MOD_REPLACE
,
110 msg
["dNSHostName"] = ldb
.MessageElement("%s.%s" % (opts
.newname
,
112 ldb
.FLAG_MOD_REPLACE
,
116 # Do a self join one more time to resync the secrets file
117 res
= ldbs
.sam
.search(expression
=("distinguishedName=%s" % newdn
),
118 attrs
=["msDs-keyVersionNumber", "serverReferenceBL"])
119 assert(len(res
) == 1)
120 kvno
= int(str(res
[0]["msDs-keyVersionNumber"]))
121 serverbldn
= ldb
.Dn(ldbs
.sam
, str(res
[0]["serverReferenceBL"]))
123 secrets_msg
= ldbs
.secrets
.search(expression
="sAMAccountName=%s$" %
124 opts
.oldname
.upper(),
125 attrs
=["secureChannelType"])
127 secChanType
= int(secrets_msg
[0]["secureChannelType"][0])
129 secretsdb_self_join(ldbs
.secrets
, domain
=names
.domain
,
131 domainsid
=names
.domainsid
,
132 dnsdomain
=names
.dnsdomain
,
133 netbiosname
=opts
.newname
.upper(),
134 machinepass
=machinepass
,
135 key_version_number
=kvno
,
136 secure_channel_type
=secChanType
)
138 # Update RID set reference as there is no back link for the moment.
140 res
= ldbs
.sam
.search(expression
="(objectClass=rIDSet)", base
=newdn
, attrs
=[])
141 assert(len(res
) == 1)
142 newridset
= str(res
[0].dn
)
143 msg
= ldb
.Message(dnobj
)
145 msg
["rIDSetReferences"] = ldb
.MessageElement(newridset
,
146 ldb
.FLAG_MOD_REPLACE
,
150 # Update the server's sites configuration
152 # Desactivated for the moment we have a couple of issues with site
153 # renaming first one is that it's currently forbidden
154 # second one is that a lot of links are not backlinked
155 # and so won't be updated when the DN change (ie. fmsowner ...)
156 serverbl
= str(serverbldn
)
157 dnparts
= serverbl
.split(",")
158 dnparts
[0] = "CN=%s" % opts
.newname
.upper()
159 newserverref
= ",".join(dnparts
)
161 newserverrefdn
= ldb
.Dn(ldbs
.sam
, newserverref
)
163 ldbs
.sam
.rename(serverbldn
, newserverrefdn
)
165 msg
= ldb
.Message(newserverrefdn
)
166 msg
["dNSHostName"] = ldb
.MessageElement("%s.%s" % (opts
.newname
,
168 ldb
.FLAG_MOD_REPLACE
,
173 ldbs
.sam
.transaction_prepare_commit()
174 ldbs
.secrets
.transaction_prepare_commit()
177 ldbs
.secrets
.rollback()
181 ldbs
.sam
.transaction_commit()
182 ldbs
.secrets
.transaction_commit()
185 ldbs
.secrets
.rollback()
188 #print lp.get("private dir")
189 cf
= open(lp
.configfile
)
190 ncfname
= "%s.new" % lp
.configfile
191 newconf
= open(ncfname
, 'w')
192 for l
in cf
.readlines():
193 if l
.find("netbios name") > 0:
194 newconf
.write("\tnetbios name = %s\n" % opts
.newname
.upper())
199 os
.rename(ncfname
, lp
.configfile
)