#
# Unix SMB/CIFS implementation.
# backend code for provisioning a Samba4 server
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
#
# Based on the original in EJS:
# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""Functions for setting up a Samba configuration."""
from base64 import b64encode
import os
import pwd
import grp
import time
import uuid, misc
import socket
import param
import registry
import samba
from auth import system_session
from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted
from samba.samdb import SamDB
from samba.idmap import IDmapDB
import security
import urllib
from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \
LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE
__docformat__ = "restructuredText"
DEFAULTSITE = "Default-First-Site-Name"
class InvalidNetbiosName(Exception):
"""A specified name was not a valid NetBIOS name."""
def __init__(self, name):
super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
class ProvisionPaths:
def __init__(self):
self.shareconf = None
self.hklm = None
self.hkcu = None
self.hkcr = None
self.hku = None
self.hkpd = None
self.hkpt = None
self.samdb = None
self.idmapdb = None
self.secrets = None
self.keytab = None
self.dns_keytab = None
self.dns = None
self.winsdb = None
self.private_dir = None
self.ldapdir = None
self.slapdconf = None
self.modulesconf = None
self.memberofconf = None
self.fedoradsinf = None
self.fedoradspartitions = None
class ProvisionNames:
def __init__(self):
self.rootdn = None
self.domaindn = None
self.configdn = None
self.schemadn = None
self.ldapmanagerdn = None
self.dnsdomain = None
self.realm = None
self.netbiosname = None
self.domain = None
self.hostname = None
self.sitename = None
self.smbconf = None
class ProvisionResult:
def __init__(self):
self.paths = None
self.domaindn = None
self.lp = None
self.samdb = None
def check_install(lp, session_info, credentials):
"""Check whether the current install seems ok.
:param lp: Loadparm context
:param session_info: Session information
:param credentials: Credentials
"""
if lp.get("realm") == "":
raise Exception("Realm empty")
ldb = Ldb(lp.get("sam database"), session_info=session_info,
credentials=credentials, lp=lp)
if len(ldb.search("(cn=Administrator)")) != 1:
raise "No administrator account found"
def findnss(nssfn, names):
"""Find a user or group from a list of possibilities.
:param nssfn: NSS Function to try (should raise KeyError if not found)
:param names: Names to check.
:return: Value return by first names list.
"""
for name in names:
try:
return nssfn(name)
except KeyError:
pass
raise KeyError("Unable to find user/group %r" % names)
findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
def open_ldb(session_info, credentials, lp, dbname):
"""Open a LDB, thrashing it if it is corrupt.
:param session_info: auth session information
:param credentials: credentials
:param lp: Loadparm context
:param dbname: Path of the database to open.
:return: a Ldb object
"""
assert session_info is not None
try:
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,
lp=lp)
def read_and_sub_file(file, subst_vars):
"""Read a file and sub in variables found in it
:param file: File to be read (typically from setup directory)
param subst_vars: Optional variables to subsitute in the file.
"""
data = open(file, 'r').read()
if subst_vars is not None:
data = substitute_var(data, subst_vars)
check_all_substituted(data)
return data
def setup_add_ldif(ldb, ldif_path, subst_vars=None):
"""Setup a ldb in the private dir.
:param ldb: LDB file to import data into
:param ldif_path: Path of the LDIF file to load
:param subst_vars: Optional variables to subsitute in LDIF.
"""
assert isinstance(ldif_path, str)
data = read_and_sub_file(ldif_path, subst_vars)
ldb.add_ldif(data)
def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
"""Modify a ldb in the private dir.
:param ldb: LDB object.
:param ldif_path: LDIF file path.
:param subst_vars: Optional dictionary with substitution variables.
"""
data = read_and_sub_file(ldif_path, subst_vars)
ldb.modify_ldif(data)
def setup_ldb(ldb, ldif_path, subst_vars):
"""Import a LDIF a file into a LDB handle, optionally substituting variables.
:note: Either all LDIF data will be added or none (using transactions).
:param ldb: LDB file to import into.
:param ldif_path: Path to the LDIF file.
:param subst_vars: Dictionary with substitution variables.
"""
assert ldb is not None
ldb.transaction_start()
try:
setup_add_ldif(ldb, ldif_path, subst_vars)
except:
ldb.transaction_cancel()
raise
ldb.transaction_commit()
def setup_file(template, fname, subst_vars):
"""Setup a file in the private dir.
:param template: Path of the template file.
:param fname: Path of the file to create.
:param subst_vars: Substitution variables.
"""
f = fname
if os.path.exists(f):
os.unlink(f)
data = read_and_sub_file(template, subst_vars)
open(f, 'w').write(data)
def provision_paths_from_lp(lp, dnsdomain):
"""Set the default paths for provisioning.
:param lp: Loadparm context.
:param dnsdomain: DNS Domain name
"""
paths = ProvisionPaths()
paths.private_dir = lp.get("private dir")
paths.keytab = "secrets.keytab"
paths.dns_keytab = "dns.keytab"
paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
paths.templates = os.path.join(paths.private_dir, "templates.ldb")
paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
paths.namedconf = os.path.join(paths.private_dir, "named.conf")
paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
path
|