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