import pwd
import grp
import time
-import uuid, sid, misc
+import uuid, misc
from socket import gethostname, gethostbyname
import param
import registry
+import samba
from samba import Ldb, substitute_var, valid_netbios_name
+from samba.samdb import SamDB
+import security
from ldb import Dn, SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \
LDB_ERR_NO_SUCH_OBJECT, timestring
self.schemedn_ldb = None
self.s4_ldapi_path = None
self.policyguid = None
+ self.extensibleobject = None
def subst_vars(self):
return {"SCHEMADN": self.schemadn,
"SCHEMADN_MOD": "schema_fsmo",
"SCHEMADN_MOD2": ",objectguid",
"CONFIGDN": self.configdn,
- "TDB_MODULES_LIST": ","+",".join(self.tdb_modules_list)
- "MODULES_LIST2": ",".join(self.modules_list2)
+ "TDB_MODULES_LIST": ","+",".join(self.tdb_modules_list),
+ "MODULES_LIST2": ",".join(self.modules_list2),
"CONFIGDN_LDB": self.configdn_ldb,
"DOMAINDN": self.domaindn,
"DOMAINDN_LDB": self.domaindn_ldb,
"DOMAINDN_MOD": "pdc_fsmo,password_hash",
"DOMAINDN_MOD2": ",objectguid",
- "DOMAINSID": self.domainsid,
+ "DOMAINSID": str(self.domainsid),
"MODULES_LIST": ",".join(self.modules_list),
"CONFIGDN_MOD": "naming_fsmo",
"CONFIGDN_MOD2": ",objectguid",
"NETBIOSNAME": self.netbiosname,
"DNSNAME": self.dnsname,
"ROOTDN": self.rootdn,
+ "DOMAIN": self.domain,
"DNSDOMAIN": self.dnsdomain,
"REALM": self.realm,
"DEFAULTSITE": self.defaultsite,
"POLICYGUID": self.policyguid,
"RDN_DC": self.rdn_dc,
"DOMAINGUID_MOD": self.domainguid_mod,
+ "VERSION": samba.version(),
+ "ACI": "# no aci for local ldb",
+ "EXTENSIBLEOBJECT": self.extensibleobject,
}
def fix(self, paths):
if lp.get("realm") == "":
return False
ldb = Ldb(lp.get("sam database"), session_info=session_info,
- credentials=credentials)
+ credentials=credentials, lp=lp)
if len(ldb.search("(cn=Administrator)")) != 1:
return False
return True
pass
raise Exception("Unable to find user/group for %s" % arguments[1])
-def add_foreign(ldb, subobj, sid, desc):
- """Add a foreign security principle."""
- add = """
-dn: CN=%s,CN=ForeignSecurityPrincipals,%s
-objectClass: top
-objectClass: foreignSecurityPrincipal
-description: %s
-""" % (sid, subobj.domaindn, desc)
- # deliberately ignore errors from this, as the records may
- # already exist
- for msg in ldb.parse_ldif(add):
- ldb.add(msg[1])
-
-def setup_name_mapping(subobj, ldb, sid, unixname):
- """Setup a mapping between a sam name and a unix name."""
- res = ldb.search(Dn(ldb, subobj.domaindn), SCOPE_SUBTREE,
- "objectSid=%s" % sid, ["dn"])
- assert len(res) == 1, "Failed to find record for objectSid %s" % sid
-
- mod = """
-dn: %s
-changetype: modify
-replace: unixName
-unixName: %s
-""" % (res[0].dn, unixname)
- ldb.modify(ldb.parse_ldif(mod).next()[1])
-
def hostip():
"""return first host IP."""
ldb.connect(ldb.filename)
-def ldb_erase(ldb):
- """Erase an ldb, removing all records."""
- # delete the specials
- for attr in ["@INDEXLIST", "@ATTRIBUTES", "@SUBCLASSES", "@MODULES",
- "@OPTIONS", "@PARTITION", "@KLUDGEACL"]:
- try:
- ldb.delete(Dn(ldb, attr))
- except LdbError, (LDB_ERR_NO_SUCH_OBJECT, _):
- # Ignore missing dn errors
- pass
-
- basedn = Dn(ldb, "")
- # and the rest
- for msg in ldb.search(basedn, SCOPE_SUBTREE,
- "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))",
- ["dn"]):
- ldb.delete(msg.dn)
-
- res = ldb.search(basedn, SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"])
- assert len(res) == 0
-
-
-def ldb_erase_partitions(subobj, message, ldb, ldapbackend):
- """Erase an ldb, removing all records."""
- assert ldb is not None
- res = ldb.search(Dn(ldb, ""), SCOPE_BASE, "(objectClass=*)",
- ["namingContexts"])
- assert len(res) == 1
- if not "namingContexts" in res[0]:
- return
- for basedn in res[0]["namingContexts"]:
- anything = "(|(objectclass=*)(dn=*))"
- previous_remaining = 1
- current_remaining = 0
-
- if ldapbackend and (basedn == subobj.domaindn):
- # Only delete objects that were created by provision
- anything = "(objectcategory=*)"
-
- k = 0
- while ++k < 10 and (previous_remaining != current_remaining):
- # and the rest
- res2 = ldb.search(Dn(ldb, basedn), SCOPE_SUBTREE, anything, ["dn"])
- previous_remaining = current_remaining
- current_remaining = len(res2)
- for msg in res2:
- try:
- ldb.delete(msg.dn)
- except LdbError, (_, text):
- message("Unable to delete %s: %s" % (msg.dn, text))
-
-
-def open_ldb(session_info, credentials, dbname):
+def open_ldb(session_info, credentials, lp, dbname):
assert session_info is not None
try:
- return Ldb(dbname, session_info=session_info, credentials=credentials)
+ return Ldb(dbname, session_info=session_info, credentials=credentials,
+ lp=lp)
except LdbError, e:
print e
os.unlink(dbname)
- return Ldb(dbname, session_info=session_info, credentials=credentials)
+ return Ldb(dbname, session_info=session_info, credentials=credentials,
+ lp=lp)
def setup_add_ldif(setup_dir, ldif, subobj, ldb):
ldb.modify(msg)
-def setup_ldb(setup_dir, ldif, session_info, credentials, subobj, dbname,
+def setup_ldb(setup_dir, ldif, session_info, credentials, subobj, lp, dbname,
erase=True):
assert dbname is not None
- ldb = open_ldb(session_info, credentials, dbname)
+ ldb = open_ldb(session_info, credentials, lp, dbname)
assert ldb is not None
ldb.transaction_start()
try:
if erase:
- ldb_erase(ldb);
+ ldb.erase();
setup_add_ldif(setup_dir, ldif, subobj, ldb)
except:
ldb.transaction_cancel()
paths.keytab = os.path.join(private_dir, "secrets.keytab")
paths.dns = os.path.join(private_dir, subobj.dnsdomain + ".zone")
paths.winsdb = os.path.join(private_dir, "wins.ldb")
- paths.ldap_basedn_ldif = os.path.join(private_dir, subobj.dnsdomain + ".ldif")
- paths.ldap_config_basedn_ldif = os.path.join(private_dir, subobj.dnsdomain + "-config.ldif")
- paths.ldap_schema_basedn_ldif = os.path.join(private_dir, subobj.dnsdomain + "-schema.ldif")
+ paths.ldap_basedn_ldif = os.path.join(private_dir,
+ subobj.dnsdomain + ".ldif")
+ paths.ldap_config_basedn_ldif = os.path.join(private_dir,
+ subobj.dnsdomain + "-config.ldif")
+ paths.ldap_schema_basedn_ldif = os.path.join(private_dir,
+ subobj.dnsdomain + "-schema.ldif")
paths.s4_ldapi_path = os.path.join(private_dir, "ldapi")
- paths.phpldapadminconfig = os.path.join(private_dir, "phpldapadmin-config.php")
+ paths.phpldapadminconfig = os.path.join(private_dir,
+ "phpldapadmin-config.php")
paths.hklm = os.path.join(private_dir, "hklm.ldb")
return paths
["objectSid"])
assert len(res) == 1
assert "objectSid" in res[0]
- sid = list(res[0]["objectSid"])[0]
+ sid = str(list(res[0]["objectSid"])[0])
# add some foreign sids if they are not present already
- add_foreign(ldb, subobj, "S-1-5-7", "Anonymous")
- add_foreign(ldb, subobj, "S-1-1-0", "World")
- add_foreign(ldb, subobj, "S-1-5-2", "Network")
- add_foreign(ldb, subobj, "S-1-5-18", "System")
- add_foreign(ldb, subobj, "S-1-5-11", "Authenticated Users")
+ ldb.add_foreign(subobj.domaindn, "S-1-5-7", "Anonymous")
+ ldb.add_foreign(subobj.domaindn, "S-1-1-0", "World")
+ ldb.add_foreign(subobj.domaindn, "S-1-5-2", "Network")
+ ldb.add_foreign(subobj.domaindn, "S-1-5-18", "System")
+ ldb.add_foreign(subobj.domaindn, "S-1-5-11", "Authenticated Users")
# some well known sids
- setup_name_mapping(subobj, ldb, "S-1-5-7", subobj.nobody)
- setup_name_mapping(subobj, ldb, "S-1-1-0", subobj.nogroup)
- setup_name_mapping(subobj, ldb, "S-1-5-2", subobj.nogroup)
- setup_name_mapping(subobj, ldb, "S-1-5-18", subobj.root)
- setup_name_mapping(subobj, ldb, "S-1-5-11", subobj.users)
- setup_name_mapping(subobj, ldb, "S-1-5-32-544", subobj.wheel)
- setup_name_mapping(subobj, ldb, "S-1-5-32-545", subobj.users)
- setup_name_mapping(subobj, ldb, "S-1-5-32-546", subobj.nogroup)
- setup_name_mapping(subobj, ldb, "S-1-5-32-551", subobj.backup)
+ ldb.setup_name_mapping(subobj.domaindn, "S-1-5-7", subobj.nobody)
+ ldb.setup_name_mapping(subobj.domaindn, "S-1-1-0", subobj.nogroup)
+ ldb.setup_name_mapping(subobj.domaindn, "S-1-5-2", subobj.nogroup)
+ ldb.setup_name_mapping(subobj.domaindn, "S-1-5-18", subobj.root)
+ ldb.setup_name_mapping(subobj.domaindn, "S-1-5-11", subobj.users)
+ ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-544", subobj.wheel)
+ ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-545", subobj.users)
+ ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-546", subobj.nogroup)
+ ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-551", subobj.backup)
# and some well known domain rids
- setup_name_mapping(subobj, ldb, sid + "-500", subobj.root)
- setup_name_mapping(subobj, ldb, sid + "-518", subobj.wheel)
- setup_name_mapping(subobj, ldb, sid + "-519", subobj.wheel)
- setup_name_mapping(subobj, ldb, sid + "-512", subobj.wheel)
- setup_name_mapping(subobj, ldb, sid + "-513", subobj.users)
- setup_name_mapping(subobj, ldb, sid + "-520", subobj.wheel)
+ ldb.setup_name_mapping(subobj.domaindn, sid + "-500", subobj.root)
+ ldb.setup_name_mapping(subobj.domaindn, sid + "-518", subobj.wheel)
+ ldb.setup_name_mapping(subobj.domaindn, sid + "-519", subobj.wheel)
+ ldb.setup_name_mapping(subobj.domaindn, sid + "-512", subobj.wheel)
+ ldb.setup_name_mapping(subobj.domaindn, sid + "-513", subobj.users)
+ ldb.setup_name_mapping(subobj.domaindn, sid + "-520", subobj.wheel)
-def provision_become_dc(setup_dir, subobj, message, paths, session_info,
+def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info,
credentials):
assert session_info is not None
subobj.fix(paths)
message("Setting up templates into %s" % paths.templates)
setup_ldb(setup_dir, "provision_templates.ldif", session_info,
- credentials, subobj, paths.templates)
+ credentials, subobj, lp, paths.templates)
# Also wipes the database
message("Setting up %s partitions" % paths.samdb)
setup_ldb(setup_dir, "provision_partitions.ldif", session_info,
- credentials, subobj, paths.samdb)
+ credentials, subobj, lp, paths.samdb)
- samdb = open_ldb(session_info, credentials, paths.samdb)
+ samdb = SamDB(paths.samdb, session_info=session_info,
+ credentials=credentials, lp=lp)
ldb.transaction_start()
try:
message("Setting up %s attributes" % paths.samdb)
setup_add_ldif(setup_dir, "provision_rootdse_add.ldif", subobj, samdb)
message("Erasing data from partitions")
- ldb_erase_partitions(subobj, message, samdb, undefined)
+ ldb_erase_partitions(subobj, message, samdb, None)
message("Setting up %s indexes" % paths.samdb)
setup_add_ldif(setup_dir, "provision_index.ldif", subobj, samdb)
message("Setting up %s" % paths.secrets)
setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials,
- subobj, paths.secrets)
+ subobj, lp, paths.secrets)
setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj,
- paths.secrets, False)
+ lp, paths.secrets, False)
def provision(lp, setup_dir, subobj, message, blank, paths, session_info,
# only install a new smb.conf if there isn't one there already
if not os.path.exists(paths.smbconf):
message("Setting up smb.conf")
- setup_file(setup_dir, "provision.smb.conf", message, paths.smbconf, subobj)
+ setup_file(setup_dir, "provision.smb.conf", message, paths.smbconf,
+ subobj)
lp.reload()
# only install a new shares config db if there is none
if not os.path.exists(paths.shareconf):
message("Setting up share.ldb")
- setup_ldb(setup_dir, "share.ldif", session_info, credentials, subobj, paths.shareconf)
+ setup_ldb(setup_dir, "share.ldif", session_info, credentials, subobj,
+ lp, paths.shareconf)
message("Setting up %s" % paths.secrets)
- setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials, subobj, paths.secrets)
- setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, paths.secrets, False)
+ setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials,
+ subobj, lp, paths.secrets)
+ setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj,
+ lp, paths.secrets, False)
message("Setting up registry")
reg = registry.Registry()
- # FIXME: Still fails for some reason:
- #reg.mount(paths.hklm, registry.HKEY_LOCAL_MACHINE, [])
- #reg.apply_patchfile(os.path.join(setup_dir, "provision.reg"))
+ #hive = registry.Hive(paths.hklm, session_info=session_info,
+ # credentials=credentials, lp_ctx=lp)
+ #reg.mount_hive(hive, "HKEY_LOCAL_MACHINE")
+ provision_reg = os.path.join(setup_dir, "provision.reg")
+ assert os.path.exists(provision_reg)
+ #reg.apply_patchfile(provision_reg)
message("Setting up templates into %s" % paths.templates)
- setup_ldb(setup_dir, "provision_templates.ldif", session_info, credentials, subobj, paths.templates)
+ setup_ldb(setup_dir, "provision_templates.ldif", session_info,
+ credentials, subobj, lp, paths.templates)
message("Setting up sam.ldb partitions")
setup_ldb(setup_dir, "provision_partitions.ldif", session_info,
- credentials, subobj, paths.samdb)
+ credentials, subobj, lp, paths.samdb)
- samdb = open_ldb(session_info, credentials, paths.samdb)
+ samdb = SamDB(paths.samdb, session_info=session_info,
+ credentials=credentials, lp=lp)
samdb.transaction_start()
try:
message("Setting up sam.ldb attributes")
message("Pre-loading the Samba 4 and AD schema")
- samdb = open_ldb(session_info, credentials, paths.samdb)
-
+ samdb = SamDB(paths.samdb, session_info=session_info,
+ credentials=credentials, lp=lp)
samdb.set_domain_sid(subobj.domainsid)
-
load_schema(setup_dir, subobj, samdb)
samdb.transaction_start()
"""Write out a DNS zone file, from the info in the current database."""
message("Setting up DNS zone: %s" % subobj.dnsdomain)
# connect to the sam
- ldb = Ldb(paths.samdb, session_info=session_info, credentials=credentials)
+ ldb = SamDB(paths.samdb, session_info=session_info, credentials=credentials,
+ lp=lp)
# These values may have changed, due to an incoming SamSync,
# or may not have been specified, so fetch them from the database
assert(res[0]["objectGUID"] is not None)
subobj.domainguid = res[0]["objectGUID"]
- subobj.host_guid = searchone(ldb, subobj.domaindn,
+ subobj.host_guid = ldb.searchone(subobj.domaindn,
"(&(objectClass=computer)(cn=%s))" % subobj.netbiosname, "objectGUID")
assert subobj.host_guid is not None
assert subobj.domain is not None
assert subobj.hostname is not None
- subobj.domainsid = sid.random()
+ subobj.domainsid = security.random_sid()
subobj.invocationid = uuid.random()
subobj.policyguid = uuid.random()
subobj.krbtgtpass = misc.random_password(12)
return subobj
-def searchone(ldb, basedn, expression, attribute):
- """search for one attribute as a string."""
- res = ldb.search(basedn, SCOPE_SUBTREE, expression, [attribute])
- if len(res) != 1 or res[0][attribute] is None:
- return None
- return res[0][attribute]
-
-
def load_schema(setup_dir, subobj, samdb):
"""Load schema."""
src = os.path.join(setup_dir, "schema.ldif")
-
schema_data = open(src, 'r').read()
-
src = os.path.join(setup_dir, "schema_samba4.ldif")
-
schema_data += open(src, 'r').read()
-
schema_data = substitute_var(schema_data, subobj.subst_vars())
-
src = os.path.join(setup_dir, "provision_schema_basedn_modify.ldif")
-
head_data = open(src, 'r').read()
-
head_data = substitute_var(head_data, subobj.subst_vars())
-
- samdb.attach_dsdb_schema_from_ldif(head_data, schema_data)
-
-
-def enable_account(ldb, user_dn):
- """enable the account."""
- res = ldb.search(user_dn, SCOPE_ONELEVEL, None, ["userAccountControl"])
- assert len(res) == 1
- userAccountControl = res[0].userAccountControl
- userAccountControl = userAccountControl - 2 # remove disabled bit
- mod = """
-dn: %s
-changetype: modify
-replace: userAccountControl
-userAccountControl: %u
-""" % (user_dn, userAccountControl)
- ldb.modify(mod)
-
-
-def newuser(sam, username, unixname, password, message, session_info,
- credentials):
- """add a new user record"""
- # connect to the sam
- ldb.transaction_start()
-
- # find the DNs for the domain and the domain users group
- res = ldb.search("", SCOPE_BASE, "defaultNamingContext=*",
- ["defaultNamingContext"])
- assert(len(res) == 1 and res[0].defaultNamingContext is not None)
- domain_dn = res[0].defaultNamingContext
- assert(domain_dn is not None)
- dom_users = searchone(ldb, domain_dn, "name=Domain Users", "dn")
- assert(dom_users is not None)
-
- user_dn = "CN=%s,CN=Users,%s" % (username, domain_dn)
-
- #
- # the new user record. note the reliance on the samdb module to fill
- # in a sid, guid etc
- #
- ldif = """
-dn: %s
-sAMAccountName: %s
-unixName: %s
-sambaPassword: %s
-objectClass: user
-""" % (user_dn, username, unixname, password)
- # add the user to the users group as well
- modgroup = """
-dn: %s
-changetype: modify
-add: member
-member: %s
-""" % (dom_users, user_dn)
-
-
- # now the real work
- message("Adding user %s" % user_dn)
- ldb.add(ldif)
-
- message("Modifying group %s" % dom_users)
- ldb.modify(modgroup)
-
- # modify the userAccountControl to remove the disabled bit
- enable_account(ldb, user_dn)
- ldb.transaction_commit()
+ samdb.attach_schema_from_ldif(head_data, schema_data)
def join_domain(domain, netbios_name, join_type, creds, message):
vampire_ctx.session_info = session_info
if not ctx.SamSyncLdb(vampire_ctx):
raise Exception("Migration of remote domain to Samba failed: %s " % vampire_ctx.error_string)
+
+
+def ldb_erase_partitions(subobj, message, ldb, ldapbackend):
+ """Erase an ldb, removing all records."""
+ assert ldb is not None
+ res = ldb.search(Dn(ldb, ""), SCOPE_BASE, "(objectClass=*)",
+ ["namingContexts"])
+ assert len(res) == 1
+ if not "namingContexts" in res[0]:
+ return
+ for basedn in res[0]["namingContexts"]:
+ anything = "(|(objectclass=*)(dn=*))"
+ previous_remaining = 1
+ current_remaining = 0
+
+ if ldapbackend and (basedn == subobj.domaindn):
+ # Only delete objects that were created by provision
+ anything = "(objectcategory=*)"
+
+ k = 0
+ while ++k < 10 and (previous_remaining != current_remaining):
+ # and the rest
+ res2 = ldb.search(Dn(ldb, basedn), SCOPE_SUBTREE, anything, ["dn"])
+ previous_remaining = current_remaining
+ current_remaining = len(res2)
+ for msg in res2:
+ try:
+ ldb.delete(msg.dn)
+ except LdbError, (_, text):
+ message("Unable to delete %s: %s" % (msg.dn, text))
+
+