3 # Helpers for provision stuff
4 # Copyright (C) Matthieu Patou <mat@matws.net> 2009-2010
6 # Based on provision a Samba4 server by
7 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
8 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 """Helpers used for upgrading between different database formats."""
31 from samba import Ldb, version, ntacls
32 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE
34 from samba.provision import (provision_paths_from_lp,
35 getpolicypath, set_gpos_acl, create_gpo_struct,
36 FILL_FULL, provision, ProvisioningError,
37 setsysvolacl, secretsdb_self_join)
38 from samba.dcerpc import xattr
39 from samba.dcerpc.misc import SEC_CHAN_BDC
40 from samba.samdb import SamDB
42 # All the ldb related to registry are commented because the path for them is
43 # relative in the provisionPath object
44 # And so opening them create a file in the current directory which is not what
46 # I still keep them commented because I plan soon to make more cleaner
55 hashAttrNotCopied = set(["dn", "whenCreated", "whenChanged", "objectGUID",
56 "uSNCreated", "replPropertyMetaData", "uSNChanged", "parentGUID",
57 "objectCategory", "distinguishedName", "nTMixedDomain",
58 "showInAdvancedViewOnly", "instanceType", "msDS-Behavior-Version",
59 "nextRid", "cn", "versionNumber", "lmPwdHistory", "pwdLastSet",
60 "ntPwdHistory", "unicodePwd","dBCSPwd", "supplementalCredentials",
61 "gPCUserExtensionNames", "gPCMachineExtensionNames","maxPwdAge", "secret",
62 "possibleInferiors", "privilege", "sAMAccountType"])
65 class ProvisionLDB(object):
77 def startTransactions(self):
78 self.sam.transaction_start()
79 self.secrets.transaction_start()
80 self.idmap.transaction_start()
81 self.privilege.transaction_start()
83 # self.hkcr.transaction_start()
84 # self.hkcu.transaction_start()
85 # self.hku.transaction_start()
86 # self.hklm.transaction_start()
88 def groupedRollback(self):
91 self.sam.transaction_cancel()
96 self.secrets.transaction_cancel()
101 self.idmap.transaction_cancel()
106 self.privilege.transaction_cancel()
112 # self.hkcr.transaction_cancel()
113 # self.hkcu.transaction_cancel()
114 # self.hku.transaction_cancel()
115 # self.hklm.transaction_cancel()
117 def groupedCommit(self):
119 self.sam.transaction_prepare_commit()
120 self.secrets.transaction_prepare_commit()
121 self.idmap.transaction_prepare_commit()
122 self.privilege.transaction_prepare_commit()
124 return self.groupedRollback()
126 # self.hkcr.transaction_prepare_commit()
127 # self.hkcu.transaction_prepare_commit()
128 # self.hku.transaction_prepare_commit()
129 # self.hklm.transaction_prepare_commit()
131 self.sam.transaction_commit()
132 self.secrets.transaction_commit()
133 self.idmap.transaction_commit()
134 self.privilege.transaction_commit()
136 return self.groupedRollback()
139 # self.hkcr.transaction_commit()
140 # self.hkcu.transaction_commit()
141 # self.hku.transaction_commit()
142 # self.hklm.transaction_commit()
145 def get_ldbs(paths, creds, session, lp):
146 """Return LDB object mapped on most important databases
148 :param paths: An object holding the different importants paths for provision object
149 :param creds: Credential used for openning LDB files
150 :param session: Session to use for openning LDB files
151 :param lp: A loadparam object
152 :return: A ProvisionLDB object that contains LDB object for the different LDB files of the provision"""
154 ldbs = ProvisionLDB()
156 ldbs.sam = SamDB(paths.samdb, session_info=session, credentials=creds, lp=lp, options=["modules:samba_dsdb"])
157 ldbs.secrets = Ldb(paths.secrets, session_info=session, credentials=creds, lp=lp)
158 ldbs.idmap = Ldb(paths.idmapdb, session_info=session, credentials=creds, lp=lp)
159 ldbs.privilege = Ldb(paths.privilege, session_info=session, credentials=creds, lp=lp)
160 # ldbs.hkcr = Ldb(paths.hkcr, session_info=session, credentials=creds, lp=lp)
161 # ldbs.hkcu = Ldb(paths.hkcu, session_info=session, credentials=creds, lp=lp)
162 # ldbs.hku = Ldb(paths.hku, session_info=session, credentials=creds, lp=lp)
163 # ldbs.hklm = Ldb(paths.hklm, session_info=session, credentials=creds, lp=lp)
168 def usn_in_range(usn, range):
169 """Check if the usn is in one of the range provided.
170 To do so, the value is checked to be between the lower bound and
171 higher bound of a range
173 :param usn: A integer value corresponding to the usn that we want to update
174 :param range: A list of integer representing ranges, lower bounds are in
175 the even indices, higher in odd indices
176 :return: True if the usn is in one of the range, False otherwise
183 if idx == len(range):
186 if usn < int(range[idx]):
190 if usn == int(range[idx]):
197 def get_paths(param, targetdir=None, smbconf=None):
198 """Get paths to important provision objects (smb.conf, ldb files, ...)
200 :param param: Param object
201 :param targetdir: Directory where the provision is (or will be) stored
202 :param smbconf: Path to the smb.conf file
203 :return: A list with the path of important provision objects"""
204 if targetdir is not None:
205 etcdir = os.path.join(targetdir, "etc")
206 if not os.path.exists(etcdir):
208 smbconf = os.path.join(etcdir, "smb.conf")
210 smbconf = param.default_path()
212 if not os.path.exists(smbconf):
213 raise ProvisioningError("Unable to find smb.conf")
215 lp = param.LoadParm()
217 paths = provision_paths_from_lp(lp, lp.get("realm"))
220 def update_policyids(names, samdb):
221 """Update policy ids that could have changed after sam update
223 :param names: List of key provision parameters
224 :param samdb: An Ldb object conntected with the sam DB
227 res = samdb.search(expression="(displayName=Default Domain Policy)",
228 base="CN=Policies,CN=System," + str(names.rootdn),
229 scope=SCOPE_ONELEVEL, attrs=["cn","displayName"])
230 names.policyid = str(res[0]["cn"]).replace("{","").replace("}","")
232 res2 = samdb.search(expression="(displayName=Default Domain Controllers"
234 base="CN=Policies,CN=System," + str(names.rootdn),
235 scope=SCOPE_ONELEVEL, attrs=["cn","displayName"])
237 names.policyid_dc = str(res2[0]["cn"]).replace("{","").replace("}","")
239 names.policyid_dc = None
242 def newprovision(names, creds, session, smbconf, provdir, logger):
243 """Create a new provision.
245 This provision will be the reference for knowing what has changed in the
246 since the latest upgrade in the current provision
248 :param names: List of provision parameters
249 :param creds: Credentials for the authentification
250 :param session: Session object
251 :param smbconf: Path to the smb.conf file
252 :param provdir: Directory where the provision will be stored
253 :param logger: A Logger
255 if os.path.isdir(provdir):
256 shutil.rmtree(provdir)
258 logger.info("Provision stored in %s", provdir)
259 provision(logger, session, creds, smbconf=smbconf,
260 targetdir=provdir, samdb_fill=FILL_FULL, realm=names.realm,
261 domain=names.domain, domainguid=names.domainguid,
262 domainsid=str(names.domainsid), ntdsguid=names.ntdsguid,
263 policyguid=names.policyid, policyguid_dc=names.policyid_dc,
264 hostname=names.netbiosname.lower(), hostip=None, hostip6=None,
265 invocationid=names.invocation, adminpass=names.adminpass,
266 krbtgtpass=None, machinepass=None, dnspass=None, root=None,
267 nobody=None, wheel=None, users=None,
268 serverrole="domain controller", ldap_backend_extra_port=None,
269 backend_type=None, ldapadminpass=None, ol_mmr_urls=None,
270 slapd_path=None, setup_ds_path=None, nosync=None,
271 dom_for_fun_level=names.domainlevel,
272 ldap_dryrun_mode=None, useeadb=True)
276 """Sorts two DNs in the lexicographical order it and put higher level DN
279 So given the dns cn=bar,cn=foo and cn=foo the later will be return as
282 :param x: First object to compare
283 :param y: Second object to compare
285 p = re.compile(r'(?<!\\), ?')
286 tab1 = p.split(str(x))
287 tab2 = p.split(str(y))
288 minimum = min(len(tab1), len(tab2))
291 # Note: python range go up to upper limit but do not include it
292 for i in range(0, minimum):
293 ret = cmp(tab1[len1-i], tab2[len2-i])
298 assert len1!=len2,"PB PB PB" + " ".join(tab1)+" / " + " ".join(tab2)
306 def identic_rename(ldbobj, dn):
307 """Perform a back and forth rename to trigger renaming on attribute that
308 can't be directly modified.
310 :param lbdobj: An Ldb Object
311 :param dn: DN of the object to manipulate
313 (before, after) = str(dn).split('=', 1)
314 # we need to use relax to avoid the subtree_rename constraints
315 ldbobj.rename(dn, ldb.Dn(ldbobj, "%s=foo%s" % (before, after)), ["relax:0"])
316 ldbobj.rename(ldb.Dn(ldbobj, "%s=foo%s" % (before, after)), dn, ["relax:0"])
320 """Return separate ACE of an ACL
322 :param acl: A string representing the ACL
323 :return: A hash with different parts
326 p = re.compile(r'(\w+)?(\(.*?\))')
334 hash["aces"].append(e[1])
339 def chunck_sddl(sddl):
340 """ Return separate parts of the SDDL (owner, group, ...)
342 :param sddl: An string containing the SDDL to chunk
343 :return: A hash with the different chunk
346 p = re.compile(r'([OGDS]:)(.*?)(?=(?:[GDS]:|$))')
347 tab = p.findall(sddl)
363 def get_diff_sddls(refsddl, cursddl, checkSacl = True):
364 """Get the difference between 2 sddl
366 This function split the textual representation of ACL into smaller
367 chunck in order to not to report a simple permutation as a difference
369 :param refsddl: First sddl to compare
370 :param cursddl: Second sddl to compare
371 :param checkSacl: If false we skip the sacl checks
372 :return: A string that explain difference between sddls
376 hash_cur = chunck_sddl(cursddl)
377 hash_ref = chunck_sddl(refsddl)
379 if not hash_cur.has_key("owner"):
380 txt = "\tNo owner in current SD"
381 elif hash_cur["owner"] != hash_ref["owner"]:
382 txt = "\tOwner mismatch: %s (in ref) %s" \
383 "(in current)\n" % (hash_ref["owner"], hash_cur["owner"])
385 if not hash_cur.has_key("group"):
386 txt = "%s\tNo group in current SD" % txt
387 elif hash_cur["group"] != hash_ref["group"]:
388 txt = "%s\tGroup mismatch: %s (in ref) %s" \
389 "(in current)\n" % (txt, hash_ref["group"], hash_cur["group"])
395 if hash_cur.has_key(part) and hash_ref.has_key(part):
397 # both are present, check if they contain the same ACE
400 c_cur = chunck_acl(hash_cur[part])
401 c_ref = chunck_acl(hash_ref[part])
403 for elem in c_cur["aces"]:
406 for elem in c_ref["aces"]:
414 if len(h_cur) + len(h_ref) > 0:
415 txt = "%s\tPart %s is different between reference" \
416 " and current here is the detail:\n" % (txt, part)
419 txt = "%s\t\t%s ACE is not present in the" \
420 " reference\n" % (txt, item)
423 txt = "%s\t\t%s ACE is not present in the" \
424 " current\n" % (txt, item)
426 elif hash_cur.has_key(part) and not hash_ref.has_key(part):
427 txt = "%s\tReference ACL hasn't a %s part\n" % (txt, part)
428 elif not hash_cur.has_key(part) and hash_ref.has_key(part):
429 txt = "%s\tCurrent ACL hasn't a %s part\n" % (txt, part)
434 def update_secrets(newsecrets_ldb, secrets_ldb, messagefunc):
435 """Update secrets.ldb
437 :param newsecrets_ldb: An LDB object that is connected to the secrets.ldb
438 of the reference provision
439 :param secrets_ldb: An LDB object that is connected to the secrets.ldb
440 of the updated provision
443 messagefunc(SIMPLE, "Update of secrets.ldb")
444 reference = newsecrets_ldb.search(base="@MODULES", scope=SCOPE_BASE)
445 current = secrets_ldb.search(base="@MODULES", scope=SCOPE_BASE)
446 assert reference, "Reference modules list can not be empty"
447 if len(current) == 0:
449 delta = secrets_ldb.msg_diff(ldb.Message(), reference[0])
450 delta.dn = reference[0].dn
451 secrets_ldb.add(reference[0])
453 delta = secrets_ldb.msg_diff(current[0], reference[0])
454 delta.dn = current[0].dn
455 secrets_ldb.modify(delta)
457 reference = newsecrets_ldb.search(expression="objectClass=top", base="",
458 scope=SCOPE_SUBTREE, attrs=["dn"])
459 current = secrets_ldb.search(expression="objectClass=top", base="",
460 scope=SCOPE_SUBTREE, attrs=["dn"])
466 empty = ldb.Message()
467 for i in range(0, len(reference)):
468 hash_new[str(reference[i]["dn"]).lower()] = reference[i]["dn"]
470 # Create a hash for speeding the search of existing object in the
472 for i in range(0, len(current)):
473 hash[str(current[i]["dn"]).lower()] = current[i]["dn"]
475 for k in hash_new.keys():
476 if not hash.has_key(k):
477 listMissing.append(hash_new[k])
479 listPresent.append(hash_new[k])
481 for entry in listMissing:
482 reference = newsecrets_ldb.search(expression="dn=%s" % entry,
483 base="", scope=SCOPE_SUBTREE)
484 current = secrets_ldb.search(expression="dn=%s" % entry,
485 base="", scope=SCOPE_SUBTREE)
486 delta = secrets_ldb.msg_diff(empty, reference[0])
487 for att in hashAttrNotCopied:
489 messagefunc(CHANGE, "Entry %s is missing from secrets.ldb" %
492 messagefunc(CHANGE, " Adding attribute %s" % att)
493 delta.dn = reference[0].dn
494 secrets_ldb.add(delta)
496 for entry in listPresent:
497 reference = newsecrets_ldb.search(expression="dn=%s" % entry,
498 base="", scope=SCOPE_SUBTREE)
499 current = secrets_ldb.search(expression="dn=%s" % entry, base="",
501 delta = secrets_ldb.msg_diff(current[0], reference[0])
502 for att in hashAttrNotCopied:
506 messagefunc(CHANGE, "Found attribute name on %s,"
507 " must rename the DN" % (current[0].dn))
508 identic_rename(secrets_ldb, reference[0].dn)
512 for entry in listPresent:
513 reference = newsecrets_ldb.search(expression="dn=%s" % entry, base="",
515 current = secrets_ldb.search(expression="dn=%s" % entry, base="",
517 delta = secrets_ldb.msg_diff(current[0], reference[0])
518 for att in hashAttrNotCopied:
521 if att == "msDS-KeyVersionNumber":
525 "Adding/Changing attribute %s to %s" %
526 (att, current[0].dn))
528 delta.dn = current[0].dn
529 secrets_ldb.modify(delta)
531 res2 = secrets_ldb.search(expression="(samaccountname=dns)",
532 scope=SCOPE_SUBTREE, attrs=["dn"])
535 messagefunc(SIMPLE, "Remove old dns account")
536 secrets_ldb.delete(res2[0]["dn"])
539 def getOEMInfo(samdb, rootdn):
540 """Return OEM Information on the top level Samba4 use to store version
543 :param samdb: An LDB object connect to sam.ldb
544 :param rootdn: Root DN of the domain
545 :return: The content of the field oEMInformation (if any)
547 res = samdb.search(expression="(objectClass=*)", base=str(rootdn),
548 scope=SCOPE_BASE, attrs=["dn", "oEMInformation"])
549 if len(res) > 0 and res[0].get("oEMInformation"):
550 info = res[0]["oEMInformation"]
556 def updateOEMInfo(samdb, rootdn):
557 """Update the OEMinfo field to add information about upgrade
559 :param samdb: an LDB object connected to the sam DB
560 :param rootdn: The string representation of the root DN of
561 the provision (ie. DC=...,DC=...)
563 res = samdb.search(expression="(objectClass=*)", base=rootdn,
564 scope=SCOPE_BASE, attrs=["dn", "oEMInformation"])
566 if res[0].get("oEMInformation"):
567 info = str(res[0]["oEMInformation"])
570 info = "%s, upgrade to %s" % (info, version)
571 delta = ldb.Message()
572 delta.dn = ldb.Dn(samdb, str(res[0]["dn"]))
573 delta["oEMInformation"] = ldb.MessageElement(info, ldb.FLAG_MOD_REPLACE,
577 def update_gpo(paths, samdb, names, lp, message, force=0):
578 """Create missing GPO file object if needed
580 Set ACL correctly also.
581 Check ACLs for sysvol/netlogon dirs also
585 ntacls.checkset_backend(lp, None, None)
586 eadbname = lp.get("posix:eadb")
587 if eadbname is not None and eadbname != "":
589 attribute = samba.xattr_tdb.wrap_getxattr(eadbname,
590 paths.sysvol, xattr.XATTR_NTACL_NAME)
592 attribute = samba.xattr_native.wrap_getxattr(paths.sysvol,
593 xattr.XATTR_NTACL_NAME)
595 attribute = samba.xattr_native.wrap_getxattr(paths.sysvol,
596 xattr.XATTR_NTACL_NAME)
603 dir = getpolicypath(paths.sysvol, names.dnsdomain, names.policyid)
604 if not os.path.isdir(dir):
605 create_gpo_struct(dir)
607 if names.policyid_dc is None:
608 raise ProvisioningError("Policy ID for Domain controller is missing")
609 dir = getpolicypath(paths.sysvol, names.dnsdomain, names.policyid_dc)
610 if not os.path.isdir(dir):
611 create_gpo_struct(dir)
614 if os.geteuid() == 0:
615 message(ERROR, "Unable to set ACLs on policies related objects: %s" % e)
617 message(ERROR, "Unable to set ACLs on policies related objects. "
618 "ACLs must be set as root if file system ACLs "
619 "(rather than posix:eadb) are used.")
621 # We always reinforce acls on GPO folder because they have to be in sync
624 set_gpos_acl(paths.sysvol, names.dnsdomain, names.domainsid,
625 names.domaindn, samdb, lp)
631 setsysvolacl(samdb, paths.netlogon, paths.sysvol, names.wheel_gid,
632 names.domainsid, names.dnsdomain, names.domaindn, lp)
637 def increment_calculated_keyversion_number(samdb, rootdn, hashDns):
638 """For a given hash associating dn and a number, this function will
639 update the replPropertyMetaData of each dn in the hash, so that the
640 calculated value of the msDs-KeyVersionNumber is equal or superior to the
641 one associated to the given dn.
643 :param samdb: An SamDB object pointing to the sam
644 :param rootdn: The base DN where we want to start
645 :param hashDns: A hash with dn as key and number representing the
646 minimum value of msDs-KeyVersionNumber that we want to
649 entry = samdb.search(expression='(objectClass=user)',
650 base=ldb.Dn(samdb,str(rootdn)),
651 scope=SCOPE_SUBTREE, attrs=["msDs-KeyVersionNumber"],
652 controls=["search_options:1:2"])
656 raise ProvisioningError("Unable to find msDs-KeyVersionNumber")
659 if hashDns.has_key(str(e.dn).lower()):
660 val = e.get("msDs-KeyVersionNumber")
663 version = int(str(hashDns[str(e.dn).lower()]))
664 if int(str(val)) < version:
666 samdb.set_attribute_replmetadata_version(str(e.dn),
669 def delta_update_basesamdb(refsampath, sampath, creds, session, lp, message):
670 """Update the provision container db: sam.ldb
671 This function is aimed for alpha9 and newer;
673 :param refsampath: Path to the samdb in the reference provision
674 :param sampath: Path to the samdb in the upgraded provision
675 :param creds: Credential used for openning LDB files
676 :param session: Session to use for openning LDB files
677 :param lp: A loadparam object
678 :return: A msg_diff object with the difference between the @ATTRIBUTES
679 of the current provision and the reference provision
683 "Update base samdb by searching difference with reference one")
684 refsam = Ldb(refsampath, session_info=session, credentials=creds,
685 lp=lp, options=["modules:"])
686 sam = Ldb(sampath, session_info=session, credentials=creds, lp=lp,
687 options=["modules:"])
689 empty = ldb.Message()
691 reference = refsam.search(expression="")
693 for refentry in reference:
694 entry = sam.search(expression="dn=%s" % refentry["dn"],
697 delta = sam.msg_diff(empty, refentry)
698 message(CHANGE, "Adding %s to sam db" % str(refentry.dn))
699 if str(refentry.dn) == "@PROVISION" and\
700 delta.get(samba.provision.LAST_PROVISION_USN_ATTRIBUTE):
701 delta.remove(samba.provision.LAST_PROVISION_USN_ATTRIBUTE)
702 delta.dn = refentry.dn
705 delta = sam.msg_diff(entry[0], refentry)
706 if str(refentry.dn) == "@ATTRIBUTES":
707 deltaattr = sam.msg_diff(refentry, entry[0])
708 if str(refentry.dn) == "@PROVISION" and\
709 delta.get(samba.provision.LAST_PROVISION_USN_ATTRIBUTE):
710 delta.remove(samba.provision.LAST_PROVISION_USN_ATTRIBUTE)
711 if len(delta.items()) > 1:
712 delta.dn = refentry.dn
718 def construct_existor_expr(attrs):
719 """Construct a exists or LDAP search expression.
721 :param attrs: List of attribute on which we want to create the search
723 :return: A string representing the expression, if attrs is empty an
724 empty string is returned
730 expr = "%s(%s=*)"%(expr,att)
734 def update_machine_account_password(samdb, secrets_ldb, names):
735 """Update (change) the password of the current DC both in the SAM db and in
738 :param samdb: An LDB object related to the sam.ldb file of a given provision
739 :param secrets_ldb: An LDB object related to the secrets.ldb file of a given
741 :param names: List of key provision parameters"""
743 expression = "samAccountName=%s$" % names.netbiosname
744 secrets_msg = secrets_ldb.search(expression=expression,
745 attrs=["secureChannelType"])
746 if int(secrets_msg[0]["secureChannelType"][0]) == SEC_CHAN_BDC:
747 res = samdb.search(expression=expression, attrs=[])
748 assert(len(res) == 1)
750 msg = ldb.Message(res[0].dn)
751 machinepass = samba.generate_random_password(128, 255)
752 mputf16 = machinepass.encode('utf-16-le')
753 msg["clearTextPassword"] = ldb.MessageElement(mputf16,
754 ldb.FLAG_MOD_REPLACE,
758 res = samdb.search(expression=("samAccountName=%s$" % names.netbiosname),
759 attrs=["msDs-keyVersionNumber"])
760 assert(len(res) == 1)
761 kvno = int(str(res[0]["msDs-keyVersionNumber"]))
762 secChanType = int(secrets_msg[0]["secureChannelType"][0])
764 secretsdb_self_join(secrets_ldb, domain=names.domain,
766 domainsid=names.domainsid,
767 dnsdomain=names.dnsdomain,
768 netbiosname=names.netbiosname,
769 machinepass=machinepass,
770 key_version_number=kvno,
771 secure_channel_type=secChanType)
773 raise ProvisioningError("Unable to find a Secure Channel"
774 "of type SEC_CHAN_BDC")
776 def update_dns_account_password(samdb, secrets_ldb, names):
777 """Update (change) the password of the dns both in the SAM db and in
780 :param samdb: An LDB object related to the sam.ldb file of a given provision
781 :param secrets_ldb: An LDB object related to the secrets.ldb file of a given
783 :param names: List of key provision parameters"""
785 expression = "samAccountName=dns-%s" % names.netbiosname
786 secrets_msg = secrets_ldb.search(expression=expression)
787 if len(secrets_msg) == 1:
788 res = samdb.search(expression=expression, attrs=[])
789 assert(len(res) == 1)
791 msg = ldb.Message(res[0].dn)
792 machinepass = samba.generate_random_password(128, 255)
793 mputf16 = machinepass.encode('utf-16-le')
794 msg["clearTextPassword"] = ldb.MessageElement(mputf16,
795 ldb.FLAG_MOD_REPLACE,
800 res = samdb.search(expression=expression,
801 attrs=["msDs-keyVersionNumber"])
802 assert(len(res) == 1)
803 kvno = str(res[0]["msDs-keyVersionNumber"])
805 msg = ldb.Message(secrets_msg[0].dn)
806 msg["secret"] = ldb.MessageElement(machinepass,
807 ldb.FLAG_MOD_REPLACE,
809 msg["msDS-KeyVersionNumber"] = ldb.MessageElement(kvno,
810 ldb.FLAG_MOD_REPLACE,
811 "msDS-KeyVersionNumber")
813 secrets_ldb.modify(msg)
815 raise ProvisioningError("Unable to find an object"
816 " with %s" % expression )
818 def search_constructed_attrs_stored(samdb, rootdn, attrs):
819 """Search a given sam DB for calculated attributes that are
820 still stored in the db.
822 :param samdb: An LDB object pointing to the sam
823 :param rootdn: The base DN where the search should start
824 :param attrs: A list of attributes to be searched
825 :return: A hash with attributes as key and an array of
826 array. Each array contains the dn and the associated
827 values for this attribute as they are stored in the
831 expr = construct_existor_expr(attrs)
834 entry = samdb.search(expression=expr, base=ldb.Dn(samdb, str(rootdn)),
835 scope=SCOPE_SUBTREE, attrs=attrs,
836 controls=["search_options:1:2","bypassoperational:0"])
844 if hashAtt.has_key(att):
845 hashAtt[att][str(ent.dn).lower()] = str(ent[att])
848 hashAtt[att][str(ent.dn).lower()] = str(ent[att])
852 def int64range2str(value):
853 """Display the int64 range stored in value as xxx-yyy
855 :param value: The int64 range
856 :return: A string of the representation of the range
860 str = "%d-%d" % (lvalue&0xFFFFFFFF, lvalue>>32)