mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Add ipa-adtrust-install utility
https://fedorahosted.org/freeipa/ticket/1619
This commit is contained in:
@@ -401,6 +401,7 @@ fi
|
|||||||
%doc COPYING README Contributors.txt
|
%doc COPYING README Contributors.txt
|
||||||
%{_sbindir}/ipa-ca-install
|
%{_sbindir}/ipa-ca-install
|
||||||
%{_sbindir}/ipa-dns-install
|
%{_sbindir}/ipa-dns-install
|
||||||
|
%{_sbindir}/ipa-adtrust-install
|
||||||
%{_sbindir}/ipa-server-install
|
%{_sbindir}/ipa-server-install
|
||||||
%{_sbindir}/ipa-replica-conncheck
|
%{_sbindir}/ipa-replica-conncheck
|
||||||
%{_sbindir}/ipa-replica-install
|
%{_sbindir}/ipa-replica-install
|
||||||
@@ -482,6 +483,7 @@ fi
|
|||||||
%{_mandir}/man1/ipa-server-certinstall.1.gz
|
%{_mandir}/man1/ipa-server-certinstall.1.gz
|
||||||
%{_mandir}/man1/ipa-server-install.1.gz
|
%{_mandir}/man1/ipa-server-install.1.gz
|
||||||
%{_mandir}/man1/ipa-dns-install.1.gz
|
%{_mandir}/man1/ipa-dns-install.1.gz
|
||||||
|
%{_mandir}/man1/ipa-adtrust-install.1.gz
|
||||||
%{_mandir}/man1/ipa-ca-install.1.gz
|
%{_mandir}/man1/ipa-ca-install.1.gz
|
||||||
%{_mandir}/man1/ipa-compat-manage.1.gz
|
%{_mandir}/man1/ipa-compat-manage.1.gz
|
||||||
%{_mandir}/man1/ipa-nis-manage.1.gz
|
%{_mandir}/man1/ipa-nis-manage.1.gz
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ PY_EXPLICIT_FILES = \
|
|||||||
install/tools/ipa-server-install \
|
install/tools/ipa-server-install \
|
||||||
install/tools/ipa-ldap-updater \
|
install/tools/ipa-ldap-updater \
|
||||||
install/tools/ipa-dns-install \
|
install/tools/ipa-dns-install \
|
||||||
|
install/tools/ipa-adtrust-install \
|
||||||
install/tools/ipa-ca-install \
|
install/tools/ipa-ca-install \
|
||||||
ipa-client/ipa-install/ipa-client-install
|
ipa-client/ipa-install/ipa-client-install
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ app_DATA = \
|
|||||||
krb.con.template \
|
krb.con.template \
|
||||||
krbrealm.con.template \
|
krbrealm.con.template \
|
||||||
preferences.html.template \
|
preferences.html.template \
|
||||||
|
smb.conf.template \
|
||||||
referint-conf.ldif \
|
referint-conf.ldif \
|
||||||
dna.ldif \
|
dna.ldif \
|
||||||
master-entry.ldif \
|
master-entry.ldif \
|
||||||
|
|||||||
28
install/share/smb.conf.template
Normal file
28
install/share/smb.conf.template
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
[global]
|
||||||
|
workgroup = $NETBIOS_NAME
|
||||||
|
realm = $REALM
|
||||||
|
kerberos method = system keytab
|
||||||
|
create krb5 conf = no
|
||||||
|
security = user
|
||||||
|
domain master = yes
|
||||||
|
domain logons = yes
|
||||||
|
log level = 1
|
||||||
|
max log size = 100000
|
||||||
|
log file = /var/log/samba/log.%m
|
||||||
|
passdb backend = IPA_ldapsam:ldapi://$LDAPI_SOCKET
|
||||||
|
ldapsam:trusted=yes
|
||||||
|
ldap ssl = off
|
||||||
|
ldap admin dn = $SMB_DN
|
||||||
|
ldap suffix = $SUFFIX
|
||||||
|
ldap user suffix = cn=users,cn=accounts
|
||||||
|
ldap group suffix = cn=groups,cn=accounts
|
||||||
|
ldap machine suffix = cn=computers,cn=accounts
|
||||||
|
rpc_server:epmapper = external
|
||||||
|
rpc_server:lsarpc = external
|
||||||
|
rpc_server:lsass = external
|
||||||
|
rpc_server:lsasd = external
|
||||||
|
rpc_server:samr = external
|
||||||
|
rpc_server:netlogon = external
|
||||||
|
rpc_server:tcpip = yes
|
||||||
|
rpc_daemon:epmd = fork
|
||||||
|
rpc_daemon:lsasd = fork
|
||||||
@@ -8,6 +8,7 @@ sbin_SCRIPTS = \
|
|||||||
ipa-ca-install \
|
ipa-ca-install \
|
||||||
ipa-dns-install \
|
ipa-dns-install \
|
||||||
ipa-server-install \
|
ipa-server-install \
|
||||||
|
ipa-adtrust-install \
|
||||||
ipa-replica-conncheck \
|
ipa-replica-conncheck \
|
||||||
ipa-replica-install \
|
ipa-replica-install \
|
||||||
ipa-replica-prepare \
|
ipa-replica-prepare \
|
||||||
|
|||||||
249
install/tools/ipa-adtrust-install
Executable file
249
install/tools/ipa-adtrust-install
Executable file
@@ -0,0 +1,249 @@
|
|||||||
|
#! /usr/bin/python
|
||||||
|
#
|
||||||
|
# Authors: Sumit Bose <sbose@redhat.com>
|
||||||
|
# Based on ipa-server-install by Karl MacMillan <kmacmillan@mentalrootkit.com>
|
||||||
|
# and ipa-dns-install by Martin Nagy
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011 Red Hat
|
||||||
|
# see file 'COPYING' for use and warranty information
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ipaserver.plugins.ldap2 import ldap2
|
||||||
|
from ipaserver.install import adtrustinstance
|
||||||
|
from ipaserver.install.installutils import *
|
||||||
|
from ipaserver.install import installutils
|
||||||
|
from ipapython import version
|
||||||
|
from ipapython import ipautil, sysrestore
|
||||||
|
from ipalib import api, errors, util
|
||||||
|
from ipapython.config import IPAOptionParser
|
||||||
|
import krbV
|
||||||
|
import ldap
|
||||||
|
|
||||||
|
def parse_options():
|
||||||
|
parser = IPAOptionParser(version=version.VERSION)
|
||||||
|
parser.add_option("-p", "--ds-password", dest="dm_password",
|
||||||
|
sensitive=True, help="directory manager password")
|
||||||
|
parser.add_option("-d", "--debug", dest="debug", action="store_true",
|
||||||
|
default=False, help="print debugging information")
|
||||||
|
parser.add_option("--ip-address", dest="ip_address",
|
||||||
|
type="ip", ip_local=True, help="Master Server IP Address")
|
||||||
|
parser.add_option("--netbios-name", dest="netbios_name",
|
||||||
|
help="NetBIOS name of the IPA domain")
|
||||||
|
parser.add_option("-U", "--unattended", dest="unattended", action="store_true",
|
||||||
|
default=False, help="unattended installation never prompts the user")
|
||||||
|
|
||||||
|
options, args = parser.parse_args()
|
||||||
|
safe_options = parser.get_safe_opts(options)
|
||||||
|
|
||||||
|
return safe_options, options
|
||||||
|
|
||||||
|
def netbios_name_error(name):
|
||||||
|
print "Illegal NetBIOS name [%s].\n" % name
|
||||||
|
print "Up to 15 characters and only uppercase ASCII letter and digits are allowed."
|
||||||
|
|
||||||
|
def read_netbios_name(netbios_default):
|
||||||
|
netbios_name = ""
|
||||||
|
|
||||||
|
print "Enter the NetBIOS name for the IPA domain."
|
||||||
|
print "Only up to 15 uppercase ASCII letters and digits are allowed."
|
||||||
|
print "Example: EXAMPLE."
|
||||||
|
print ""
|
||||||
|
print ""
|
||||||
|
if not netbios_default:
|
||||||
|
netbios_default = "EXAMPLE"
|
||||||
|
while True:
|
||||||
|
netbios_name = ipautil.user_input("NetBIOS domain name", netbios_default, allow_empty = False)
|
||||||
|
print ""
|
||||||
|
if adtrustinstance.check_netbios_name(netbios_name):
|
||||||
|
break
|
||||||
|
|
||||||
|
netbios_name_error(netbios_name)
|
||||||
|
|
||||||
|
return netbios_name
|
||||||
|
|
||||||
|
def main():
|
||||||
|
safe_options, options = parse_options()
|
||||||
|
|
||||||
|
if os.getegid() != 0:
|
||||||
|
sys.exit("Must be root to setup AD trusts on server")
|
||||||
|
|
||||||
|
standard_logging_setup("/var/log/ipaserver-install.log", options.debug, filemode='a')
|
||||||
|
print "\nThe log file for this installation can be found in /var/log/ipaserver-install.log"
|
||||||
|
|
||||||
|
logging.debug('%s was invoked with options: %s' % (sys.argv[0], safe_options))
|
||||||
|
logging.debug("missing options might be asked for interactively later\n")
|
||||||
|
|
||||||
|
installutils.check_server_configuration()
|
||||||
|
|
||||||
|
global fstore
|
||||||
|
fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
|
||||||
|
|
||||||
|
print "=============================================================================="
|
||||||
|
print "This program will setup components needed to establish trust to AD domains for"
|
||||||
|
print "the FreeIPA Server."
|
||||||
|
print ""
|
||||||
|
print "This includes:"
|
||||||
|
print " * Configure Samba"
|
||||||
|
print " * Add trust related objects to FreeIPA LDAP server"
|
||||||
|
#TODO:
|
||||||
|
#print " * Add a SID to all users and Posix groups"
|
||||||
|
print ""
|
||||||
|
print "To accept the default shown in brackets, press the Enter key."
|
||||||
|
print ""
|
||||||
|
|
||||||
|
# Check if samba packages are installed
|
||||||
|
if not adtrustinstance.check_inst(options.unattended):
|
||||||
|
sys.exit("Aborting installation.")
|
||||||
|
|
||||||
|
# Initialize the ipalib api
|
||||||
|
cfg = dict(
|
||||||
|
in_server=True,
|
||||||
|
debug=options.debug,
|
||||||
|
)
|
||||||
|
api.bootstrap(**cfg)
|
||||||
|
api.finalize()
|
||||||
|
|
||||||
|
if adtrustinstance.ipa_smb_conf_exists():
|
||||||
|
if not options.unattended:
|
||||||
|
while True:
|
||||||
|
print "IPA generated smb.conf detected."
|
||||||
|
if not ipautil.user_input("Overwrite smb.conf?", default = False, allow_empty = False):
|
||||||
|
sys.exit("Aborting installation.")
|
||||||
|
break
|
||||||
|
|
||||||
|
# Check we have a public IP that is associated with the hostname
|
||||||
|
try:
|
||||||
|
if options.ip_address:
|
||||||
|
ip = ipautil.CheckedIPAddress(options.ip_address, match_local=True)
|
||||||
|
else:
|
||||||
|
hostaddr = resolve_host(api.env.host)
|
||||||
|
ip = hostaddr and ipautil.CheckedIPAddress(hostaddr, match_local=True)
|
||||||
|
except Exception, e:
|
||||||
|
print "Error: Invalid IP Address %s: %s" % (ip, e)
|
||||||
|
ip = None
|
||||||
|
|
||||||
|
if not ip:
|
||||||
|
if options.unattended:
|
||||||
|
sys.exit("Unable to resolve IP address for host name")
|
||||||
|
else:
|
||||||
|
read_ip = read_ip_address(api.env.host, fstore)
|
||||||
|
try:
|
||||||
|
ip = ipautil.CheckedIPAddress(read_ip, match_local=True)
|
||||||
|
except Exception, e:
|
||||||
|
print "Error: Invalid IP Address %s: %s" % (ip, e)
|
||||||
|
sys.exit("Aborting installation.")
|
||||||
|
|
||||||
|
ip_address = str(ip)
|
||||||
|
logging.debug("will use ip_address: %s\n", ip_address)
|
||||||
|
|
||||||
|
if not options.unattended:
|
||||||
|
print ""
|
||||||
|
print "The following operations may take some minutes to complete."
|
||||||
|
print "Please wait until the prompt is returned."
|
||||||
|
print ""
|
||||||
|
|
||||||
|
# Create a Adtrust instance
|
||||||
|
if options.unattended and not options.dm_password:
|
||||||
|
sys.exit("\nIn unattended mode you need to provide at least the -p option")
|
||||||
|
|
||||||
|
netbios_name = options.netbios_name
|
||||||
|
if not netbios_name:
|
||||||
|
netbios_name = adtrustinstance.make_netbios_name(api.env.domain)
|
||||||
|
|
||||||
|
if not adtrustinstance.check_netbios_name(netbios_name):
|
||||||
|
if options.unattended:
|
||||||
|
netbios_name_error(netbios_name)
|
||||||
|
sys.exit("Aborting installation.")
|
||||||
|
else:
|
||||||
|
netbios_name = None
|
||||||
|
if options.netbios_name:
|
||||||
|
netbios_name_error(options.netbios_name)
|
||||||
|
|
||||||
|
if not options.unattended and ( not netbios_name or not options.netbios_name):
|
||||||
|
netbios_name = read_netbios_name(netbios_name)
|
||||||
|
|
||||||
|
dm_password = options.dm_password or read_password("Directory Manager",
|
||||||
|
confirm=False, validate=False)
|
||||||
|
smb = adtrustinstance.ADTRUSTInstance(fstore, dm_password)
|
||||||
|
|
||||||
|
# try the connection
|
||||||
|
try:
|
||||||
|
smb.ldap_connect()
|
||||||
|
smb.ldap_disconnect()
|
||||||
|
except ldap.INVALID_CREDENTIALS, e:
|
||||||
|
sys.exit("Password is not valid!")
|
||||||
|
|
||||||
|
if smb.dm_password:
|
||||||
|
api.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=smb.dm_password)
|
||||||
|
else:
|
||||||
|
# See if our LDAP server is up and we can talk to it over GSSAPI
|
||||||
|
ccache = krbV.default_context().default_ccache().name
|
||||||
|
api.Backend.ldap2.connect(ccache)
|
||||||
|
|
||||||
|
smb.setup(api.env.host, ip_address, api.env.realm, api.env.domain,
|
||||||
|
netbios_name)
|
||||||
|
smb.create_instance()
|
||||||
|
|
||||||
|
print "=============================================================================="
|
||||||
|
print "Setup complete"
|
||||||
|
print ""
|
||||||
|
print "\tYou must make sure these network ports are open:"
|
||||||
|
print "\t\tTCP Ports:"
|
||||||
|
print "\t\t * 138: netbios-dgm"
|
||||||
|
print "\t\t * 139: netbios-ssn"
|
||||||
|
print "\t\t * 445: microsoft-ds"
|
||||||
|
print "\t\tUDP Ports:"
|
||||||
|
print "\t\t * 138: netbios-dgm"
|
||||||
|
print "\t\t * 139: netbios-ssn"
|
||||||
|
print "\t\t * 445: microsoft-ds"
|
||||||
|
print ""
|
||||||
|
print "\tAdditionally you have to make sure the FreeIPA LDAP server cannot reached"
|
||||||
|
print "\tby any domain controller in the Active Directory domain by closing the"
|
||||||
|
print "\tfollowing ports for these servers:"
|
||||||
|
print "\t\tTCP Ports:"
|
||||||
|
print "\t\t * 389, 636: LDAP/LDAPS"
|
||||||
|
print "\t\tUDP Ports:"
|
||||||
|
print "\t\t * 389: (C)LDAP"
|
||||||
|
print "\tYou may want to choose to REJECT the network packets instead of DROPing them"
|
||||||
|
print "\tto avoid timeouts on the AD domain controllers."
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
sys.exit(main())
|
||||||
|
except SystemExit, e:
|
||||||
|
sys.exit(e)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print "Installation cancelled."
|
||||||
|
except RuntimeError, e:
|
||||||
|
print str(e)
|
||||||
|
except HostnameLocalhost:
|
||||||
|
print "The hostname resolves to the localhost address (127.0.0.1/::1)"
|
||||||
|
print "Please change your /etc/hosts file so that the hostname"
|
||||||
|
print "resolves to the ip address of your network interface."
|
||||||
|
print "The KDC service does not listen on localhost"
|
||||||
|
print ""
|
||||||
|
print "Please fix your /etc/hosts file and restart the setup program"
|
||||||
|
except Exception, e:
|
||||||
|
message = "Unexpected error - see ipaserver-install.log for details:\n %s" % str(e)
|
||||||
|
print message
|
||||||
|
message = str(e)
|
||||||
|
for str in traceback.format_tb(sys.exc_info()[2]):
|
||||||
|
message = message + "\n" + str
|
||||||
|
logging.debug(message)
|
||||||
|
sys.exit(1)
|
||||||
@@ -13,6 +13,7 @@ man1_MANS = \
|
|||||||
ipa-server-certinstall.1 \
|
ipa-server-certinstall.1 \
|
||||||
ipa-server-install.1 \
|
ipa-server-install.1 \
|
||||||
ipa-dns-install.1 \
|
ipa-dns-install.1 \
|
||||||
|
ipa-adtrust-install.1 \
|
||||||
ipa-ca-install.1 \
|
ipa-ca-install.1 \
|
||||||
ipa-ldap-updater.1 \
|
ipa-ldap-updater.1 \
|
||||||
ipa-compat-manage.1 \
|
ipa-compat-manage.1 \
|
||||||
|
|||||||
47
install/tools/man/ipa-adtrust-install.1
Normal file
47
install/tools/man/ipa-adtrust-install.1
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
.\" A man page for ipa-adtrust-install
|
||||||
|
.\" Copyright (C) 2011 Red Hat, Inc.
|
||||||
|
.\"
|
||||||
|
.\" 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/>.
|
||||||
|
.\"
|
||||||
|
.\" Author: Sumit Bose <sbose@redhat.com>
|
||||||
|
.\"
|
||||||
|
.TH "ipa-adtrust-install" "1" "Aug 23 2011" "FreeIPA" "FreeIPA Manual Pages"
|
||||||
|
.SH "NAME"
|
||||||
|
ipa\-adtrust\-install \- Prepare an IPA server to be able to establish trust relationships with AD domains
|
||||||
|
.SH "SYNOPSIS"
|
||||||
|
ipa\-adtrust\-install [\fIOPTION\fR]...
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
Adds all necesary objects and configuration to allow an IPA server to create a
|
||||||
|
trust to an Active Directory domain. This requires that the IPA server is
|
||||||
|
already installed and configured.
|
||||||
|
.SH "OPTIONS"
|
||||||
|
.TP
|
||||||
|
\fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-ds\-password\fR=\fIDM_PASSWORD\fR
|
||||||
|
The password to be used by the Directory Server for the Directory Manager user
|
||||||
|
.TP
|
||||||
|
\fB\-d\fR, \fB\-\-debug\fR
|
||||||
|
Enable debug logging when more verbose output is needed
|
||||||
|
.TP
|
||||||
|
\fB\-\-ip\-address\fR=\fIIP_ADDRESS\fR
|
||||||
|
The IP address of the IPA server. If not provided then this is determined based on the hostname of the server.
|
||||||
|
.TP
|
||||||
|
\fB\-\-netbios\-name\fR=\fINETBIOS_NAME\fR
|
||||||
|
The NetBIOS name for the IPA domain. If not provided then this is determined based on the leading component of the DNS domain name.
|
||||||
|
.TP
|
||||||
|
\fB\-U\fR, \fB\-\-unattended\fR
|
||||||
|
An unattended installation that will never prompt for user input
|
||||||
|
.SH "EXIT STATUS"
|
||||||
|
0 if the installation was successful
|
||||||
|
|
||||||
|
1 if an error occurred
|
||||||
@@ -10,6 +10,7 @@ app_PYTHON = \
|
|||||||
krbinstance.py \
|
krbinstance.py \
|
||||||
httpinstance.py \
|
httpinstance.py \
|
||||||
ntpinstance.py \
|
ntpinstance.py \
|
||||||
|
adtrustinstance.py \
|
||||||
service.py \
|
service.py \
|
||||||
installutils.py \
|
installutils.py \
|
||||||
replication.py \
|
replication.py \
|
||||||
|
|||||||
281
ipaserver/install/adtrustinstance.py
Normal file
281
ipaserver/install/adtrustinstance.py
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
# Authors: Sumit Bose <sbose@redhat.com>
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011 Red Hat
|
||||||
|
# see file 'COPYING' for use and warranty information
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import os
|
||||||
|
import errno
|
||||||
|
import ldap
|
||||||
|
import service
|
||||||
|
import tempfile
|
||||||
|
import installutils
|
||||||
|
from ipaserver import ipaldap
|
||||||
|
from ipaserver.install.dsinstance import realm_to_serverid
|
||||||
|
from ipalib import errors
|
||||||
|
from ipapython import sysrestore
|
||||||
|
from ipapython import ipautil
|
||||||
|
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
import struct
|
||||||
|
|
||||||
|
allowed_netbios_chars = string.ascii_uppercase + string.digits
|
||||||
|
|
||||||
|
def check_inst(unattended):
|
||||||
|
for f in ['/usr/sbin/smbd', '/usr/bin/net', '/usr/bin/smbpasswd']:
|
||||||
|
if not os.path.exists(f):
|
||||||
|
print "%s was not found on this system" % f
|
||||||
|
print "Please install the 'samba' packages and start the installation again"
|
||||||
|
return False
|
||||||
|
|
||||||
|
#TODO: Add check for needed samba4 libraries
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def ipa_smb_conf_exists():
|
||||||
|
try:
|
||||||
|
fd = open('/etc/samba/smb.conf', 'r')
|
||||||
|
except IOError, e:
|
||||||
|
if e.errno == errno.ENOENT:
|
||||||
|
return False
|
||||||
|
|
||||||
|
lines = fd.readlines()
|
||||||
|
fd.close()
|
||||||
|
for line in lines:
|
||||||
|
if line.startswith('### Added by IPA Installer ###'):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def check_netbios_name(s):
|
||||||
|
# NetBIOS names may not be longer than 15 allowed characters
|
||||||
|
if not s or len(s) > 15 or ''.join([c for c in s if c not in allowed_netbios_chars]):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def make_netbios_name(s):
|
||||||
|
return ''.join([c for c in s.split('.')[0].upper() if c in allowed_netbios_chars])[:15]
|
||||||
|
|
||||||
|
class ADTRUSTInstance(service.Service):
|
||||||
|
def __init__(self, fstore=None, dm_password=None):
|
||||||
|
service.Service.__init__(self, "smb", dm_password=dm_password)
|
||||||
|
|
||||||
|
if fstore:
|
||||||
|
self.fstore = fstore
|
||||||
|
else:
|
||||||
|
self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
|
||||||
|
|
||||||
|
def __create_samba_user(self):
|
||||||
|
print "The user for Samba is %s" % self.smb_dn
|
||||||
|
try:
|
||||||
|
self.admin_conn.getEntry(self.smb_dn, ldap.SCOPE_BASE)
|
||||||
|
print "Samba user entry exists, resetting password"
|
||||||
|
|
||||||
|
self.admin_conn.modify_s(self.smb_dn, [(ldap.MOD_REPLACE, "userPassword", self.smb_dn_pwd)])
|
||||||
|
return
|
||||||
|
|
||||||
|
except errors.NotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# The user doesn't exist, add it
|
||||||
|
entry = ipaldap.Entry(self.smb_dn)
|
||||||
|
entry.setValues("objectclass", ["account", "simplesecurityobject"])
|
||||||
|
entry.setValues("uid", "samba")
|
||||||
|
entry.setValues("userPassword", self.smb_dn_pwd)
|
||||||
|
self.admin_conn.add_s(entry)
|
||||||
|
|
||||||
|
# And finally grant it permission to read NT passwords, we do not want
|
||||||
|
# to support LM passwords so there is no need to allow access to them
|
||||||
|
mod = [(ldap.MOD_ADD, 'aci',
|
||||||
|
str(['(targetattr = "sambaNTPassword")(version 3.0; acl "Samba user can read NT passwords"; allow (read) userdn="ldap:///%s";)' % self.smb_dn]))]
|
||||||
|
try:
|
||||||
|
self.admin_conn.modify_s(self.suffix, mod)
|
||||||
|
except ldap.TYPE_OR_VALUE_EXISTS:
|
||||||
|
logging.debug("samba user aci already exists in suffix %s on %s" % (self.suffix, self.admin_conn.host))
|
||||||
|
|
||||||
|
def __gen_sid_string(self):
|
||||||
|
sub_ids = struct.unpack("<LLL", os.urandom(12))
|
||||||
|
return "S-1-5-21-%d-%d-%d" % (sub_ids[0], sub_ids[1], sub_ids[2])
|
||||||
|
|
||||||
|
def __create_samba_domain_object(self):
|
||||||
|
trust_dn = "cn=trusts,%s" % self.suffix
|
||||||
|
smb_dom_dn = "cn=ad,%s" % trust_dn
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.admin_conn.getEntry(smb_dom_dn, ldap.SCOPE_BASE)
|
||||||
|
print "Samba domain object already exists"
|
||||||
|
return
|
||||||
|
except errors.NotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.admin_conn.getEntry(trust_dn, ldap.SCOPE_BASE)
|
||||||
|
except errors.NotFound:
|
||||||
|
entry = ipaldap.Entry(trust_dn)
|
||||||
|
entry.setValues("objectclass", ["nsContainer"])
|
||||||
|
entry.setValues("cn", "trusts")
|
||||||
|
self.admin_conn.add_s(entry)
|
||||||
|
|
||||||
|
entry = ipaldap.Entry(smb_dom_dn)
|
||||||
|
entry.setValues("objectclass", ["sambaDomain", "nsContainer"])
|
||||||
|
entry.setValues("cn", "ad")
|
||||||
|
entry.setValues("sambaDomainName", self.netbios_name)
|
||||||
|
entry.setValues("sambaSID", self.__gen_sid_string())
|
||||||
|
#TODO: which MAY attributes do we want to set ?
|
||||||
|
self.admin_conn.add_s(entry)
|
||||||
|
|
||||||
|
def __write_smb_conf(self):
|
||||||
|
self.fstore.backup_file(self.smb_conf)
|
||||||
|
|
||||||
|
fd = open(self.smb_conf, "w")
|
||||||
|
fd.write('### Added by IPA Installer ###\n')
|
||||||
|
fd.write('[global]\n')
|
||||||
|
fd.write('config backend = registry\n')
|
||||||
|
fd.close()
|
||||||
|
|
||||||
|
def __write_smb_registry(self):
|
||||||
|
template = os.path.join(ipautil.SHARE_DIR, "smb.conf.template")
|
||||||
|
conf = ipautil.template_file(template, self.sub_dict)
|
||||||
|
[fd, tmp_name] = tempfile.mkstemp()
|
||||||
|
os.write(fd, conf)
|
||||||
|
os.close(fd)
|
||||||
|
|
||||||
|
args = ["/usr/bin/net", "conf", "import", tmp_name]
|
||||||
|
|
||||||
|
try:
|
||||||
|
ipautil.run(args)
|
||||||
|
finally:
|
||||||
|
os.remove(tmp_name)
|
||||||
|
|
||||||
|
def __set_smb_ldap_password(self):
|
||||||
|
args = ["/usr/bin/smbpasswd", "-c", self.smb_conf, "-s", "-W" ]
|
||||||
|
|
||||||
|
ipautil.run(args, stdin = self.smb_dn_pwd + "\n" + self.smb_dn_pwd + "\n" )
|
||||||
|
|
||||||
|
def __setup_principal(self):
|
||||||
|
cifs_principal = "cifs/" + self.fqdn + "@" + self.realm_name
|
||||||
|
installutils.kadmin_addprinc(cifs_principal)
|
||||||
|
|
||||||
|
self.move_service(cifs_principal)
|
||||||
|
|
||||||
|
try:
|
||||||
|
ipautil.run(["ipa-rmkeytab", "--principal", cifs_principal,
|
||||||
|
"-k", "/etc/krb5.keytab"])
|
||||||
|
except ipautil.CalledProcessError, e:
|
||||||
|
if e.returncode != 5:
|
||||||
|
logging.critical("Failed to remove old key for %s" % cifs_principal)
|
||||||
|
|
||||||
|
try:
|
||||||
|
ipautil.run(["ipa-getkeytab", "--server", self.fqdn,
|
||||||
|
"--principal", cifs_principal,
|
||||||
|
"-k", "/etc/krb5.keytab"])
|
||||||
|
except ipautil.CalledProcessError, e:
|
||||||
|
logging.critical("Failed to add key for %s" % cifs_principal)
|
||||||
|
|
||||||
|
def __start(self):
|
||||||
|
try:
|
||||||
|
self.start()
|
||||||
|
except:
|
||||||
|
logging.critical("smbd service failed to start")
|
||||||
|
|
||||||
|
def __stop(self):
|
||||||
|
self.backup_state("running", self.is_running())
|
||||||
|
try:
|
||||||
|
self.stop()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __enable(self):
|
||||||
|
self.backup_state("enabled", self.is_enabled())
|
||||||
|
# We do not let the system start IPA components on its own,
|
||||||
|
# Instead we reply on the IPA init script to start only enabled
|
||||||
|
# components as found in our LDAP configuration tree
|
||||||
|
try:
|
||||||
|
self.ldap_enable('ADTRUST', self.fqdn, self.dm_password, self.suffix)
|
||||||
|
except ldap.ALREADY_EXISTS:
|
||||||
|
logging.critical("ADTRUST Service startup entry already exists.")
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __setup_sub_dict(self):
|
||||||
|
self.sub_dict = dict(REALM = self.realm_name,
|
||||||
|
SUFFIX = self.suffix,
|
||||||
|
NETBIOS_NAME = self.netbios_name,
|
||||||
|
SMB_DN = self.smb_dn,
|
||||||
|
LDAPI_SOCKET = self.ldapi_socket)
|
||||||
|
|
||||||
|
def setup(self, fqdn, ip_address, realm_name, domain_name, netbios_name,
|
||||||
|
smbd_user="samba"):
|
||||||
|
self.fqdn =fqdn
|
||||||
|
self.ip_address = ip_address
|
||||||
|
self.realm_name = realm_name
|
||||||
|
self.domain_name = domain_name
|
||||||
|
self.netbios_name = netbios_name
|
||||||
|
self.smbd_user = smbd_user
|
||||||
|
self.suffix = ipautil.realm_to_suffix(self.realm_name)
|
||||||
|
self.ldapi_socket = "%%2fvar%%2frun%%2fslapd-%s.socket" % realm_to_serverid(self.realm_name)
|
||||||
|
|
||||||
|
self.smb_conf = "/etc/samba/smb.conf"
|
||||||
|
|
||||||
|
self.smb_dn = "uid=samba,cn=sysaccounts,cn=etc,%s" % self.suffix
|
||||||
|
self.smb_dn_pwd = ipautil.ipa_generate_password()
|
||||||
|
|
||||||
|
self.__setup_sub_dict()
|
||||||
|
|
||||||
|
|
||||||
|
def create_instance(self):
|
||||||
|
|
||||||
|
self.ldap_connect()
|
||||||
|
|
||||||
|
self.step("stopping smbd", self.__stop)
|
||||||
|
self.step("create samba user", self.__create_samba_user)
|
||||||
|
self.step("create samba domain object", self.__create_samba_domain_object)
|
||||||
|
self.step("create samba config registry", self.__write_smb_registry)
|
||||||
|
self.step("writing samba config file", self.__write_smb_conf)
|
||||||
|
self.step("setting password for the samba user", self.__set_smb_ldap_password)
|
||||||
|
self.step("Adding cifs Kerberos principal", self.__setup_principal)
|
||||||
|
self.step("configuring smbd to start on boot", self.__enable)
|
||||||
|
self.step("starting smbd", self.__start)
|
||||||
|
|
||||||
|
self.start_creation("Configuring smbd:")
|
||||||
|
|
||||||
|
def uninstall(self):
|
||||||
|
if self.is_configured():
|
||||||
|
self.print_msg("Unconfiguring %s" % self.service_name)
|
||||||
|
|
||||||
|
running = self.restore_state("running")
|
||||||
|
enabled = self.restore_state("enabled")
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.stop()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for f in [self.smb_conf]:
|
||||||
|
try:
|
||||||
|
self.fstore.restore_file(f)
|
||||||
|
except ValueError, error:
|
||||||
|
logging.debug(error)
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not enabled is None and not enabled:
|
||||||
|
self.disable()
|
||||||
|
|
||||||
|
if not running is None and running:
|
||||||
|
self.start()
|
||||||
@@ -38,7 +38,8 @@ SERVICE_LIST = {
|
|||||||
'KPASSWD':('kadmin', 20),
|
'KPASSWD':('kadmin', 20),
|
||||||
'DNS':('named', 30),
|
'DNS':('named', 30),
|
||||||
'HTTP':('httpd', 40),
|
'HTTP':('httpd', 40),
|
||||||
'CA':('pki-cad', 50)
|
'CA':('pki-cad', 50),
|
||||||
|
'ADTRUST':('smb', 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
def print_msg(message, output_fd=sys.stdout):
|
def print_msg(message, output_fd=sys.stdout):
|
||||||
|
|||||||
59
tests/test_ipaserver/install/test_adtrustinstance.py
Executable file
59
tests/test_ipaserver/install/test_adtrustinstance.py
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
# Authors:
|
||||||
|
# Sumit Bose <sbose@redhat.com>
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011 Red Hat
|
||||||
|
# see file 'COPYING' for use and warranty information
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
"""
|
||||||
|
Test `adtrustinstance`
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import nose
|
||||||
|
|
||||||
|
from ipaserver.install import adtrustinstance
|
||||||
|
|
||||||
|
class test_adtrustinstance:
|
||||||
|
"""
|
||||||
|
Test `adtrustinstance`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_make_netbios_name(self):
|
||||||
|
s = adtrustinstance.make_netbios_name("ABCDEF")
|
||||||
|
assert s == 'ABCDEF' and isinstance(s, str)
|
||||||
|
s = adtrustinstance.make_netbios_name(U"ABCDEF")
|
||||||
|
assert s == 'ABCDEF' and isinstance(s, unicode)
|
||||||
|
s = adtrustinstance.make_netbios_name("abcdef")
|
||||||
|
assert s == 'ABCDEF'
|
||||||
|
s = adtrustinstance.make_netbios_name("abc.def")
|
||||||
|
assert s == 'ABC'
|
||||||
|
s = adtrustinstance.make_netbios_name("abcdefghijklmnopqr.def")
|
||||||
|
assert s == 'ABCDEFGHIJKLMNO'
|
||||||
|
s = adtrustinstance.make_netbios_name("A!$%B&/()C=?+*D")
|
||||||
|
assert s == 'ABCD'
|
||||||
|
s = adtrustinstance.make_netbios_name("!$%&/()=?+*")
|
||||||
|
assert not s
|
||||||
|
|
||||||
|
def test_check_netbios_name(self):
|
||||||
|
assert adtrustinstance.check_netbios_name("ABCDEF")
|
||||||
|
assert not adtrustinstance.check_netbios_name("abcdef")
|
||||||
|
assert adtrustinstance.check_netbios_name("ABCDE12345ABCDE")
|
||||||
|
assert not adtrustinstance.check_netbios_name("ABCDE12345ABCDE1")
|
||||||
|
assert not adtrustinstance.check_netbios_name("")
|
||||||
|
|
||||||
|
assert adtrustinstance.check_netbios_name(U"ABCDEF")
|
||||||
|
assert not adtrustinstance.check_netbios_name(U"abcdef")
|
||||||
|
assert adtrustinstance.check_netbios_name(U"ABCDE12345ABCDE")
|
||||||
|
assert not adtrustinstance.check_netbios_name(U"ABCDE12345ABCDE1")
|
||||||
Reference in New Issue
Block a user