s4 provision: DNS backend should be set by caller
[Samba/gebeck_regimport.git] / source4 / scripting / python / samba / upgrade.py
blob07cb720f88953946a658c00db8603a8995ee1d7c
1 # backend code for upgrading from Samba3
2 # Copyright Jelmer Vernooij 2005-2007
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """Support code for upgrading from Samba 3 to Samba 4."""
20 __docformat__ = "restructuredText"
22 import ldb
23 import time
24 import pwd
26 from samba import Ldb, registry
27 from samba.param import LoadParm
28 from samba.provision import provision, FILL_FULL, ProvisioningError
29 from samba.samba3 import passdb
30 from samba.samba3 import param as s3param
31 from samba.dcerpc import lsa, samr, security
32 from samba.dcerpc.security import dom_sid
33 from samba import dsdb
34 from samba.ndr import ndr_pack
35 from samba import unix2nttime
38 def import_sam_policy(samdb, policy, logger):
39 """Import a Samba 3 policy.
41 :param samdb: Samba4 SAM database
42 :param policy: Samba3 account policy
43 :param logger: Logger object
44 """
46 # Following entries are used -
47 # min password length, password history, minimum password age,
48 # maximum password age, lockout duration
50 # Following entries are not used -
51 # reset count minutes, user must logon to change password,
52 # bad lockout minutes, disconnect time
54 m = ldb.Message()
55 m.dn = samdb.get_default_basedn()
56 m['a01'] = ldb.MessageElement(str(policy['min password length']),
57 ldb.FLAG_MOD_REPLACE, 'minPwdLength')
58 m['a02'] = ldb.MessageElement(str(policy['password history']),
59 ldb.FLAG_MOD_REPLACE, 'pwdHistoryLength')
61 min_pw_age_unix = policy['minimum password age']
62 min_pw_age_nt = 0 - unix2nttime(min_pw_age_unix)
63 m['a03'] = ldb.MessageElement(str(min_pw_age_nt), ldb.FLAG_MOD_REPLACE,
64 'minPwdAge')
66 max_pw_age_unix = policy['maximum password age']
67 if (max_pw_age_unix == 0xFFFFFFFF):
68 max_pw_age_nt = 0
69 else:
70 max_pw_age_nt = unix2nttime(max_pw_age_unix)
72 m['a04'] = ldb.MessageElement(str(max_pw_age_nt), ldb.FLAG_MOD_REPLACE,
73 'maxPwdAge')
75 lockout_duration_mins = policy['lockout duration']
76 lockout_duration_nt = unix2nttime(lockout_duration_mins * 60)
78 m['a05'] = ldb.MessageElement(str(lockout_duration_nt),
79 ldb.FLAG_MOD_REPLACE, 'lockoutDuration')
81 try:
82 samdb.modify(m)
83 except ldb.LdbError, e:
84 logger.warn("Could not set account policy, (%s)", str(e))
87 def add_idmap_entry(idmapdb, sid, xid, xid_type, logger):
88 """Create idmap entry
90 :param idmapdb: Samba4 IDMAP database
91 :param sid: user/group sid
92 :param xid: user/group id
93 :param xid_type: type of id (UID/GID)
94 :param logger: Logger object
95 """
97 # First try to see if we already have this entry
98 found = False
99 msg = idmapdb.search(expression='objectSid=%s' % str(sid))
100 if msg.count == 1:
101 found = True
103 if found:
104 try:
105 m = ldb.Message()
106 m.dn = msg[0]['dn']
107 m['xidNumber'] = ldb.MessageElement(
108 str(xid), ldb.FLAG_MOD_REPLACE, 'xidNumber')
109 m['type'] = ldb.MessageElement(
110 xid_type, ldb.FLAG_MOD_REPLACE, 'type')
111 idmapdb.modify(m)
112 except ldb.LdbError, e:
113 logger.warn(
114 'Could not modify idmap entry for sid=%s, id=%s, type=%s (%s)',
115 str(sid), str(xid), xid_type, str(e))
116 else:
117 try:
118 idmapdb.add({"dn": "CN=%s" % str(sid),
119 "cn": str(sid),
120 "objectClass": "sidMap",
121 "objectSid": ndr_pack(sid),
122 "type": xid_type,
123 "xidNumber": str(xid)})
124 except ldb.LdbError, e:
125 logger.warn(
126 'Could not add idmap entry for sid=%s, id=%s, type=%s (%s)',
127 str(sid), str(xid), xid_type, str(e))
130 def import_idmap(idmapdb, samba3, logger):
131 """Import idmap data.
133 :param idmapdb: Samba4 IDMAP database
134 :param samba3_idmap: Samba3 IDMAP database to import from
135 :param logger: Logger object
138 try:
139 samba3_idmap = samba3.get_idmap_db()
140 except IOError, e:
141 logger.warn('Cannot open idmap database, Ignoring: %s', str(e))
142 return
144 currentxid = max(samba3_idmap.get_user_hwm(), samba3_idmap.get_group_hwm())
145 lowerbound = currentxid
146 # FIXME: upperbound
148 m = ldb.Message()
149 m.dn = ldb.Dn(idmapdb, 'CN=CONFIG')
150 m['lowerbound'] = ldb.MessageElement(
151 str(lowerbound), ldb.FLAG_MOD_REPLACE, 'lowerBound')
152 m['xidNumber'] = ldb.MessageElement(
153 str(currentxid), ldb.FLAG_MOD_REPLACE, 'xidNumber')
154 idmapdb.modify(m)
156 for id_type, xid in samba3_idmap.ids():
157 if id_type == 'UID':
158 xid_type = 'ID_TYPE_UID'
159 elif id_type == 'GID':
160 xid_type = 'ID_TYPE_GID'
161 else:
162 logger.warn('Wrong type of entry in idmap (%s), Ignoring', id_type)
163 continue
165 sid = samba3_idmap.get_sid(xid, id_type)
166 add_idmap_entry(idmapdb, dom_sid(sid), xid, xid_type, logger)
169 def add_group_from_mapping_entry(samdb, groupmap, logger):
170 """Add or modify group from group mapping entry
172 param samdb: Samba4 SAM database
173 param groupmap: Groupmap entry
174 param logger: Logger object
177 # First try to see if we already have this entry
178 try:
179 msg = samdb.search(
180 base='<SID=%s>' % str(groupmap.sid), scope=ldb.SCOPE_BASE)
181 found = True
182 except ldb.LdbError, (ecode, emsg):
183 if ecode == ldb.ERR_NO_SUCH_OBJECT:
184 found = False
185 else:
186 raise ldb.LdbError(ecode, emsg)
188 if found:
189 logger.warn('Group already exists sid=%s, groupname=%s existing_groupname=%s, Ignoring.',
190 str(groupmap.sid), groupmap.nt_name, msg[0]['sAMAccountName'][0])
191 else:
192 if groupmap.sid_name_use == lsa.SID_NAME_WKN_GRP:
193 # In a lot of Samba3 databases, aliases are marked as well known groups
194 (group_dom_sid, rid) = groupmap.sid.split()
195 if (group_dom_sid != security.dom_sid(security.SID_BUILTIN)):
196 return
198 m = ldb.Message()
199 m.dn = ldb.Dn(samdb, "CN=%s,CN=Users,%s" % (groupmap.nt_name, samdb.get_default_basedn()))
200 m['a01'] = ldb.MessageElement(groupmap.nt_name, ldb.FLAG_MOD_ADD, 'cn')
201 m['a02'] = ldb.MessageElement('group', ldb.FLAG_MOD_ADD, 'objectClass')
202 m['a03'] = ldb.MessageElement(ndr_pack(groupmap.sid), ldb.FLAG_MOD_ADD, 'objectSid')
203 m['a04'] = ldb.MessageElement(groupmap.comment, ldb.FLAG_MOD_ADD, 'description')
204 m['a05'] = ldb.MessageElement(groupmap.nt_name, ldb.FLAG_MOD_ADD, 'sAMAccountName')
206 # Fix up incorrect 'well known' groups that are actually builtin (per test above) to be aliases
207 if groupmap.sid_name_use == lsa.SID_NAME_ALIAS or groupmap.sid_name_use == lsa.SID_NAME_WKN_GRP:
208 m['a06'] = ldb.MessageElement(str(dsdb.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP), ldb.FLAG_MOD_ADD, 'groupType')
210 try:
211 samdb.add(m, controls=["relax:0"])
212 except ldb.LdbError, e:
213 logger.warn('Could not add group name=%s (%s)', groupmap.nt_name, str(e))
216 def add_users_to_group(samdb, group, members, logger):
217 """Add user/member to group/alias
219 param samdb: Samba4 SAM database
220 param group: Groupmap object
221 param members: List of member SIDs
222 param logger: Logger object
224 for member_sid in members:
225 m = ldb.Message()
226 m.dn = ldb.Dn(samdb, "<SID=%s>" % str(group.sid))
227 m['a01'] = ldb.MessageElement("<SID=%s>" % str(member_sid), ldb.FLAG_MOD_ADD, 'member')
229 try:
230 samdb.modify(m)
231 except ldb.LdbError, (ecode, emsg):
232 if ecode == ldb.ERR_ENTRY_ALREADY_EXISTS:
233 logger.info("skipped re-adding member '%s' to group '%s': %s", member_sid, group.sid, emsg)
234 elif ecode == ldb.ERR_NO_SUCH_OBJECT:
235 raise ProvisioningError("Could not add member '%s' to group '%s' as either group or user record doesn't exist: %s" % (member_sid, group.sid, emsg))
236 else:
237 raise ProvisioningError("Could not add member '%s' to group '%s': %s" % (member_sid, group.sid, emsg))
240 def import_wins(samba4_winsdb, samba3_winsdb):
241 """Import settings from a Samba3 WINS database.
243 :param samba4_winsdb: WINS database to import to
244 :param samba3_winsdb: WINS database to import from
246 version_id = 0
248 for (name, (ttl, ips, nb_flags)) in samba3_winsdb.items():
249 version_id += 1
251 type = int(name.split("#", 1)[1], 16)
253 if type == 0x1C:
254 rType = 0x2
255 elif type & 0x80:
256 if len(ips) > 1:
257 rType = 0x2
258 else:
259 rType = 0x1
260 else:
261 if len(ips) > 1:
262 rType = 0x3
263 else:
264 rType = 0x0
266 if ttl > time.time():
267 rState = 0x0 # active
268 else:
269 rState = 0x1 # released
271 nType = ((nb_flags & 0x60) >> 5)
273 samba4_winsdb.add({"dn": "name=%s,type=0x%s" % tuple(name.split("#")),
274 "type": name.split("#")[1],
275 "name": name.split("#")[0],
276 "objectClass": "winsRecord",
277 "recordType": str(rType),
278 "recordState": str(rState),
279 "nodeType": str(nType),
280 "expireTime": ldb.timestring(ttl),
281 "isStatic": "0",
282 "versionID": str(version_id),
283 "address": ips})
285 samba4_winsdb.add({"dn": "cn=VERSION",
286 "cn": "VERSION",
287 "objectClass": "winsMaxVersion",
288 "maxVersion": str(version_id)})
291 def enable_samba3sam(samdb, ldapurl):
292 """Enable Samba 3 LDAP URL database.
294 :param samdb: SAM Database.
295 :param ldapurl: Samba 3 LDAP URL
297 samdb.modify_ldif("""
298 dn: @MODULES
299 changetype: modify
300 replace: @LIST
301 @LIST: samldb,operational,objectguid,rdn_name,samba3sam
302 """)
304 samdb.add({"dn": "@MAP=samba3sam", "@MAP_URL": ldapurl})
307 smbconf_keep = [
308 "dos charset",
309 "unix charset",
310 "display charset",
311 "comment",
312 "path",
313 "directory",
314 "workgroup",
315 "realm",
316 "netbios name",
317 "netbios aliases",
318 "netbios scope",
319 "server string",
320 "interfaces",
321 "bind interfaces only",
322 "security",
323 "auth methods",
324 "encrypt passwords",
325 "null passwords",
326 "obey pam restrictions",
327 "password server",
328 "smb passwd file",
329 "private dir",
330 "passwd chat",
331 "password level",
332 "lanman auth",
333 "ntlm auth",
334 "client NTLMv2 auth",
335 "client lanman auth",
336 "client plaintext auth",
337 "read only",
338 "hosts allow",
339 "hosts deny",
340 "log level",
341 "debuglevel",
342 "log file",
343 "smb ports",
344 "large readwrite",
345 "max protocol",
346 "min protocol",
347 "unicode",
348 "read raw",
349 "write raw",
350 "disable netbios",
351 "nt status support",
352 "max mux",
353 "max xmit",
354 "name resolve order",
355 "max wins ttl",
356 "min wins ttl",
357 "time server",
358 "unix extensions",
359 "use spnego",
360 "server signing",
361 "client signing",
362 "max connections",
363 "paranoid server security",
364 "socket options",
365 "strict sync",
366 "max print jobs",
367 "printable",
368 "print ok",
369 "printer name",
370 "printer",
371 "map system",
372 "map hidden",
373 "map archive",
374 "preferred master",
375 "prefered master",
376 "local master",
377 "browseable",
378 "browsable",
379 "wins server",
380 "wins support",
381 "csc policy",
382 "strict locking",
383 "preload",
384 "auto services",
385 "lock dir",
386 "lock directory",
387 "pid directory",
388 "socket address",
389 "copy",
390 "include",
391 "available",
392 "volume",
393 "fstype",
394 "panic action",
395 "msdfs root",
396 "host msdfs",
397 "winbind separator"]
400 def upgrade_smbconf(oldconf, mark):
401 """Remove configuration variables not present in Samba4
403 :param oldconf: Old configuration structure
404 :param mark: Whether removed configuration variables should be
405 kept in the new configuration as "samba3:<name>"
407 data = oldconf.data()
408 newconf = LoadParm()
410 for s in data:
411 for p in data[s]:
412 keep = False
413 for k in smbconf_keep:
414 if smbconf_keep[k] == p:
415 keep = True
416 break
418 if keep:
419 newconf.set(s, p, oldconf.get(s, p))
420 elif mark:
421 newconf.set(s, "samba3:" + p, oldconf.get(s, p))
423 return newconf
425 SAMBA3_PREDEF_NAMES = {
426 'HKLM': registry.HKEY_LOCAL_MACHINE,
430 def import_registry(samba4_registry, samba3_regdb):
431 """Import a Samba 3 registry database into the Samba 4 registry.
433 :param samba4_registry: Samba 4 registry handle.
434 :param samba3_regdb: Samba 3 registry database handle.
436 def ensure_key_exists(keypath):
437 (predef_name, keypath) = keypath.split("/", 1)
438 predef_id = SAMBA3_PREDEF_NAMES[predef_name]
439 keypath = keypath.replace("/", "\\")
440 return samba4_registry.create_key(predef_id, keypath)
442 for key in samba3_regdb.keys():
443 key_handle = ensure_key_exists(key)
444 for subkey in samba3_regdb.subkeys(key):
445 ensure_key_exists(subkey)
446 for (value_name, (value_type, value_data)) in samba3_regdb.values(key).items():
447 key_handle.set_value(value_name, value_type, value_data)
450 def upgrade_from_samba3(samba3, logger, targetdir, session_info=None, useeadb=False):
451 """Upgrade from samba3 database to samba4 AD database
453 :param samba3: samba3 object
454 :param logger: Logger object
455 :param targetdir: samba4 database directory
456 :param session_info: Session information
459 if samba3.lp.get("domain logons"):
460 serverrole = "domain controller"
461 else:
462 if samba3.lp.get("security") == "user":
463 serverrole = "standalone"
464 else:
465 serverrole = "member server"
467 domainname = samba3.lp.get("workgroup")
468 realm = samba3.lp.get("realm")
469 netbiosname = samba3.lp.get("netbios name")
471 # secrets db
472 secrets_db = samba3.get_secrets_db()
474 if not domainname:
475 domainname = secrets_db.domains()[0]
476 logger.warning("No workgroup specified in smb.conf file, assuming '%s'",
477 domainname)
479 if not realm:
480 if serverrole == "domain controller":
481 raise ProvisioningError("No realm specified in smb.conf file and being a DC. That upgrade path doesn't work! Please add a 'realm' directive to your old smb.conf to let us know which one you want to use (it is the DNS name of the AD domain you wish to create.")
482 else:
483 realm = domainname.upper()
484 logger.warning("No realm specified in smb.conf file, assuming '%s'",
485 realm)
487 # Find machine account and password
488 next_rid = 1000
490 try:
491 machinepass = secrets_db.get_machine_password(netbiosname)
492 except KeyError:
493 machinepass = None
495 # We must close the direct pytdb database before the C code loads it
496 secrets_db.close()
498 # Connect to old password backend
499 passdb.set_secrets_dir(samba3.lp.get("private dir"))
500 s3db = samba3.get_sam_db()
502 # Get domain sid
503 try:
504 domainsid = passdb.get_global_sam_sid()
505 except passdb.error:
506 raise Exception("Can't find domain sid for '%s', Exiting." % domainname)
508 # Get machine account, sid, rid
509 try:
510 machineacct = s3db.getsampwnam('%s$' % netbiosname)
511 except passdb.error:
512 machinerid = None
513 machinesid = None
514 else:
515 machinesid, machinerid = machineacct.user_sid.split()
517 # Export account policy
518 logger.info("Exporting account policy")
519 policy = s3db.get_account_policy()
521 # Export groups from old passdb backend
522 logger.info("Exporting groups")
523 grouplist = s3db.enum_group_mapping()
524 groupmembers = {}
525 for group in grouplist:
526 sid, rid = group.sid.split()
527 if sid == domainsid:
528 if rid >= next_rid:
529 next_rid = rid + 1
531 # Get members for each group/alias
532 if group.sid_name_use == lsa.SID_NAME_ALIAS:
533 members = s3db.enum_aliasmem(group.sid)
534 elif group.sid_name_use == lsa.SID_NAME_DOM_GRP:
535 try:
536 members = s3db.enum_group_members(group.sid)
537 except passdb.error:
538 continue
539 groupmembers[group.nt_name] = members
540 elif group.sid_name_use == lsa.SID_NAME_WKN_GRP:
541 (group_dom_sid, rid) = group.sid.split()
542 if (group_dom_sid != security.dom_sid(security.SID_BUILTIN)):
543 logger.warn("Ignoring 'well known' group '%s' (should already be in AD, and have no members)",
544 group.nt_name)
545 continue
546 # A number of buggy databases mix up well known groups and aliases.
547 members = s3db.enum_aliasmem(group.sid)
548 else:
549 logger.warn("Ignoring group '%s' with sid_name_use=%d",
550 group.nt_name, group.sid_name_use)
551 continue
553 # Export users from old passdb backend
554 logger.info("Exporting users")
555 userlist = s3db.search_users(0)
556 userdata = {}
557 uids = {}
558 admin_user = None
559 for entry in userlist:
560 if machinerid and machinerid == entry['rid']:
561 continue
562 username = entry['account_name']
563 if entry['rid'] < 1000:
564 logger.info(" Skipping wellknown rid=%d (for username=%s)", entry['rid'], username)
565 continue
566 if entry['rid'] >= next_rid:
567 next_rid = entry['rid'] + 1
569 user = s3db.getsampwnam(username)
570 acct_type = (user.acct_ctrl & (samr.ACB_NORMAL|samr.ACB_WSTRUST|samr.ACB_SVRTRUST|samr.ACB_DOMTRUST))
571 if (acct_type == samr.ACB_NORMAL or acct_type == samr.ACB_WSTRUST or acct_type == samr.ACB_SVRTRUST):
572 pass
573 elif acct_type == samr.ACB_DOMTRUST:
574 logger.warn(" Skipping inter-domain trust from domain %s, this trust must be re-created as an AD trust" % username[:-1])
575 continue
576 elif acct_type == (samr.ACB_NORMAL|samr.ACB_WSTRUST) and username[-1] == '$':
577 logger.warn(" Fixing account %s which had both ACB_NORMAL (U) and ACB_WSTRUST (W) set. Account will be marked as ACB_WSTRUST (W), i.e. as a domain member" % username)
578 user.acct_ctrl = (user.acct_ctrl & ~samr.ACB_NORMAL)
579 else:
580 raise ProvisioningError("""Failed to upgrade due to invalid account %s, account control flags 0x%08X must have exactly one of
581 ACB_NORMAL (N, 0x%08X), ACB_WSTRUST (W 0x%08X), ACB_SVRTRUST (S 0x%08X) or ACB_DOMTRUST (D 0x%08X).
583 Please fix this account before attempting to upgrade again
585 % (user.acct_flags, username,
586 samr.ACB_NORMAL, samr.ACB_WSTRUST, samr.ACB_SVRTRUST, samr.ACB_DOMTRUST))
588 userdata[username] = user
589 try:
590 uids[username] = s3db.sid_to_id(user.user_sid)[0]
591 except passdb.error:
592 try:
593 uids[username] = pwd.getpwnam(username).pw_uid
594 except KeyError:
595 pass
597 if not admin_user and username.lower() == 'root':
598 admin_user = username
599 if username.lower() == 'administrator':
600 admin_user = username
602 logger.info("Next rid = %d", next_rid)
604 # Check for same username/groupname
605 group_names = set([g.nt_name for g in grouplist])
606 user_names = set([u['account_name'] for u in userlist])
607 common_names = group_names.intersection(user_names)
608 if common_names:
609 logger.error("Following names are both user names and group names:")
610 for name in common_names:
611 logger.error(" %s" % name)
612 raise ProvisioningError("Please remove common user/group names before upgrade.")
614 # Check for same user sid/group sid
615 group_sids = set([str(g.sid) for g in grouplist])
616 user_sids = set(["%s-%u" % (domainsid, u['rid']) for u in userlist])
617 common_sids = group_sids.intersection(user_sids)
618 if common_sids:
619 logger.error("Following sids are both user and group sids:")
620 for sid in common_sids:
621 logger.error(" %s" % str(sid))
622 raise ProvisioningError("Please remove duplicate sid entries before upgrade.")
624 if serverrole == "domain controller":
625 dns_backend = "BIND9_FLATFILE"
626 else:
627 dns_backend = "NONE"
629 # Do full provision
630 result = provision(logger, session_info, None,
631 targetdir=targetdir, realm=realm, domain=domainname,
632 domainsid=str(domainsid), next_rid=next_rid,
633 dc_rid=machinerid,
634 dom_for_fun_level=dsdb.DS_DOMAIN_FUNCTION_2003,
635 hostname=netbiosname, machinepass=machinepass,
636 serverrole=serverrole, samdb_fill=FILL_FULL,
637 useeadb=useeadb, dns_backend=dns_backend)
639 # Import WINS database
640 logger.info("Importing WINS database")
641 import_wins(Ldb(result.paths.winsdb), samba3.get_wins_db())
643 # Set Account policy
644 logger.info("Importing Account policy")
645 import_sam_policy(result.samdb, policy, logger)
647 # Migrate IDMAP database
648 logger.info("Importing idmap database")
649 import_idmap(result.idmap, samba3, logger)
651 # Set the s3 context for samba4 configuration
652 new_lp_ctx = s3param.get_context()
653 new_lp_ctx.load(result.lp.configfile)
654 new_lp_ctx.set("private dir", result.lp.get("private dir"))
655 new_lp_ctx.set("state directory", result.lp.get("state directory"))
656 new_lp_ctx.set("lock directory", result.lp.get("lock directory"))
658 # Connect to samba4 backend
659 s4_passdb = passdb.PDB(new_lp_ctx.get("passdb backend"))
661 # Export groups to samba4 backend
662 logger.info("Importing groups")
663 for g in grouplist:
664 # Ignore uninitialized groups (gid = -1)
665 if g.gid != 0xffffffff:
666 add_idmap_entry(result.idmap, g.sid, g.gid, "GID", logger)
667 add_group_from_mapping_entry(result.samdb, g, logger)
669 # Export users to samba4 backend
670 logger.info("Importing users")
671 for username in userdata:
672 if username.lower() == 'administrator' or username.lower() == 'root':
673 continue
674 s4_passdb.add_sam_account(userdata[username])
675 if username in uids:
676 add_idmap_entry(result.idmap, userdata[username].user_sid, uids[username], "UID", logger)
678 logger.info("Adding users to groups")
679 for g in grouplist:
680 if g.nt_name in groupmembers:
681 add_users_to_group(result.samdb, g, groupmembers[g.nt_name], logger)
683 # Set password for administrator
684 if admin_user:
685 logger.info("Setting password for administrator")
686 admin_userdata = s4_passdb.getsampwnam("administrator")
687 admin_userdata.nt_passwd = userdata[admin_user].nt_passwd
688 if userdata[admin_user].lanman_passwd:
689 admin_userdata.lanman_passwd = userdata[admin_user].lanman_passwd
690 admin_userdata.pass_last_set_time = userdata[admin_user].pass_last_set_time
691 if userdata[admin_user].pw_history:
692 admin_userdata.pw_history = userdata[admin_user].pw_history
693 s4_passdb.update_sam_account(admin_userdata)
694 logger.info("Administrator password has been set to password of user '%s'", admin_user)
696 # FIXME: import_registry(registry.Registry(), samba3.get_registry())
697 # FIXME: shares