mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-26 17:01:14 -06:00
357 lines
13 KiB
Python
357 lines
13 KiB
Python
#! /usr/bin/python -E
|
|
# Authors: Simo Sorce <ssorce@redhat.com>
|
|
# Karl MacMillan <kmacmillan@mentalrootkit.com>
|
|
#
|
|
# Copyright (C) 2007 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/>.
|
|
#
|
|
|
|
VERSION = "%prog .1"
|
|
|
|
import sys
|
|
import os
|
|
import string
|
|
import shutil
|
|
import socket
|
|
from ipapython.ipa_log_manager import *
|
|
from optparse import OptionParser
|
|
import ipachangeconf
|
|
import ldap
|
|
from ldap import LDAPError
|
|
from ipapython.dn import DN
|
|
|
|
class ipaserver:
|
|
|
|
def __init__(self, server):
|
|
self.server = server
|
|
self.realm = None
|
|
self.domain = None
|
|
self.basedn = None
|
|
|
|
def getServerName(self):
|
|
return str(self.server)
|
|
|
|
def getDomainName(self):
|
|
return str(self.domain)
|
|
|
|
def getRealmName(self):
|
|
return str(self.realm)
|
|
|
|
def getBaseDN(self):
|
|
return str(self.basedn)
|
|
|
|
def check(self):
|
|
|
|
lret = []
|
|
lres = []
|
|
lattr = ""
|
|
linfo = ""
|
|
lrealms = []
|
|
|
|
i = 0
|
|
|
|
#now verify the server is really an IPA server
|
|
try:
|
|
root_logger.debug("Init ldap with: ldap://"+self.server+":389")
|
|
lh = ldap.initialize("ldap://"+self.server+":389")
|
|
lh.simple_bind_s("","")
|
|
|
|
root_logger.debug("Search rootdse")
|
|
lret = lh.search_s("", ldap.SCOPE_BASE, "(objectClass=*)")
|
|
for lattr in lret[0][1]:
|
|
if lattr.lower() == "namingcontexts":
|
|
self.basedn = lret[0][1][lattr][0]
|
|
|
|
root_logger.debug("Search for (info=*) in "+self.basedn+"(base)")
|
|
lret = lh.search_s(self.basedn, ldap.SCOPE_BASE, "(info=IPA*)")
|
|
if not lret:
|
|
return False
|
|
root_logger.debug("Found: "+str(lret))
|
|
|
|
for lattr in lret[0][1]:
|
|
if lattr.lower() == "info":
|
|
linfo = lret[0][1][lattr][0].lower()
|
|
break
|
|
|
|
if not linfo:
|
|
return False
|
|
|
|
#search and return known realms
|
|
root_logger.debug("Search for (objectClass=krbRealmContainer) in "+self.basedn+"(sub)")
|
|
lret = lh.search_s(str(DN(('cn', 'kerberos'), self.basedn)),
|
|
ldap.SCOPE_SUBTREE, "(objectClass=krbRealmContainer)")
|
|
if not lret:
|
|
#something very wrong
|
|
return False
|
|
root_logger.debug("Found: "+str(lret))
|
|
|
|
for lres in lret:
|
|
for lattr in lres[1]:
|
|
if lattr.lower() == "cn":
|
|
lrealms.append(lres[1][lattr][0])
|
|
|
|
|
|
if len(lrealms) != 1:
|
|
#which one? we can't attach to a multi-realm server without DNS working
|
|
return False
|
|
else:
|
|
self.realm = lrealms[0]
|
|
self.domain = lrealms[0].lower()
|
|
return True
|
|
|
|
except LDAPError, err:
|
|
#no good
|
|
root_logger.error("Ldap Error: "+str(err))
|
|
return False
|
|
|
|
ntp_conf = """# Permit time synchronization with our time source, but do not
|
|
# permit the source to query or modify the service on this system.
|
|
restrict default kod nomodify notrap nopeer noquery
|
|
restrict -6 default kod nomodify notrap nopeer noquery
|
|
|
|
# Permit all access over the loopback interface. This could
|
|
# be tightened as well, but to do so would effect some of
|
|
# the administrative functions.
|
|
restrict 127.0.0.1
|
|
restrict -6 ::1
|
|
|
|
# Hosts on local network are less restricted.
|
|
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
|
|
|
|
# Use public servers from the pool.ntp.org project.
|
|
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
|
|
server $SERVER
|
|
|
|
#broadcast 192.168.1.255 key 42 # broadcast server
|
|
#broadcastclient # broadcast client
|
|
#broadcast 224.0.1.1 key 42 # multicast server
|
|
#multicastclient 224.0.1.1 # multicast client
|
|
#manycastserver 239.255.254.254 # manycast server
|
|
#manycastclient 239.255.254.254 key 42 # manycast client
|
|
|
|
# Undisciplined Local Clock. This is a fake driver intended for backup
|
|
# and when no outside source of synchronized time is available.
|
|
server 127.127.1.0 # local clock
|
|
#fudge 127.127.1.0 stratum 10
|
|
|
|
# Drift file. Put this in a directory which the daemon can write to.
|
|
# No symbolic links allowed, either, since the daemon updates the file
|
|
# by creating a temporary in the same directory and then rename()'ing
|
|
# it to the file.
|
|
driftfile /var/lib/ntp/drift
|
|
|
|
# Key file containing the keys and key identifiers used when operating
|
|
# with symmetric key cryptography.
|
|
keys /etc/ntp/keys
|
|
|
|
# Specify the key identifiers which are trusted.
|
|
#trustedkey 4 8 42
|
|
|
|
# Specify the key identifier to use with the ntpdc utility.
|
|
#requestkey 8
|
|
|
|
# Specify the key identifier to use with the ntpq utility.
|
|
#controlkey 8
|
|
"""
|
|
|
|
ntp_sysconfig = """# Drop root to id 'ntp:ntp' by default.
|
|
OPTIONS="-x -u ntp:ntp -p /var/run/ntpd.pid"
|
|
|
|
# Set to 'yes' to sync hw clock after successful ntpdate
|
|
SYNC_HWCLOCK=yes
|
|
|
|
# Additional options for ntpdate
|
|
NTPDATE_OPTIONS=""
|
|
"""
|
|
|
|
def config_ntp(server_fqdn):
|
|
|
|
nc = string.replace(ntp_conf, "$SERVER", server_fqdn)
|
|
|
|
shutil.copy("/etc/ntp.conf", "/etc/ntp.conf.ipasave")
|
|
|
|
fd = open("/etc/ntp.conf", "w")
|
|
fd.write(nc)
|
|
fd.close()
|
|
|
|
shutil.copy("/etc/sysconfig/ntpd", "/etc/sysconfig/ntpd.ipasave")
|
|
|
|
fd = open("/etc/sysconfig/ntpd", "w")
|
|
fd.write(ntp_sysconfig)
|
|
fd.close()
|
|
|
|
# Set the ntpd to start on boot
|
|
os.system("/sbin/chkconfig ntpd on")
|
|
|
|
# Restart ntpd
|
|
os.system("/sbin/service ntpd restart")
|
|
|
|
def parse_options():
|
|
parser = OptionParser(version=VERSION)
|
|
parser.add_option("--server", dest="server", help="IPA server")
|
|
parser.add_option("-d", "--debug", dest="debug", action="store_true",
|
|
default=False, help="print debugging information")
|
|
parser.add_option("-U", "--unattended", dest="unattended",
|
|
action="store_true",
|
|
help="unattended installation never prompts the user")
|
|
parser.add_option("-N", "--no-ntp", action="store_false",
|
|
help="do not configure ntp", default=True, dest="conf_ntp")
|
|
|
|
options, args = parser.parse_args()
|
|
if not options.server:
|
|
parser.error("must provide an IPA server name with --server")
|
|
|
|
return options
|
|
|
|
def ask_for_confirmation(message):
|
|
yesno = raw_input(message + " [y/N]: ")
|
|
if not yesno or yesno.lower()[0] != "y":
|
|
return False
|
|
print "\n"
|
|
return True
|
|
|
|
def logging_setup(options):
|
|
standard_logging_setup('ipaclient-install.log', debug=options.debug)
|
|
|
|
def main():
|
|
options = parse_options()
|
|
logging_setup(options)
|
|
dnsok = True
|
|
|
|
ipasrv = ipaserver(options.server)
|
|
|
|
ret = ipasrv.check()
|
|
if ret == False:
|
|
print "Failed to verify that ["+options.server+"] is an IPA Server, aborting!"
|
|
return -1
|
|
|
|
print "IPA Server verified."
|
|
print "Realm: "+ipasrv.getRealmName()
|
|
print "DNS Domain: "+ipasrv.getDomainName()
|
|
print "IPA Server: "+ipasrv.getServerName()
|
|
print "BaseDN: "+ipasrv.getBaseDN()
|
|
|
|
print "\n"
|
|
if not options.unattended and not ask_for_confirmation("Continue to configure the system with these values?"):
|
|
return 1
|
|
|
|
# Configure ipa.conf
|
|
ipaconf = ipachangeconf.IPAChangeConf("IPA Installer")
|
|
ipaconf.setOptionAssignment(" = ")
|
|
ipaconf.setSectionNameDelimiters(("[","]"))
|
|
|
|
opts = [{'name':'comment', 'type':'comment', 'value':'File modified by ipa-client-install'},
|
|
{'name':'empty', 'type':'empty'}]
|
|
|
|
#[global]
|
|
defopts = [{'name':'xmlrpc_uri', 'type':'option', 'value':'https://%s/ipa/xml' % ipasrv.getServerName()},
|
|
{'name':'realm', 'type':'option', 'value':ipasrv.getRealmName()}]
|
|
|
|
opts.append({'name':'global', 'type':'section', 'value':defopts})
|
|
opts.append({'name':'empty', 'type':'empty'})
|
|
|
|
ipaconf.newConf("/etc/ipa/default.conf", opts)
|
|
|
|
# Configure ldap.conf
|
|
ldapconf = ipachangeconf.IPAChangeConf("IPA Installer")
|
|
ldapconf.setOptionAssignment(" ")
|
|
|
|
opts = [{'name':'comment', 'type':'comment', 'value':'File modified by ipa-client-install'},
|
|
{'name':'empty', 'type':'empty'},
|
|
{'name':'ldap_version', 'type':'option', 'value':'3'},
|
|
{'name':'base', 'type':'option', 'value':ipasrv.getBaseDN()},
|
|
{'name':'empty', 'type':'empty'},
|
|
{'name':'nss_base_passwd', 'type':'option', 'value':str(DN(('cn', 'users'), ('cn', 'accounts'), ipasrv.getBaseDN()))+'?sub'},
|
|
{'name':'nss_base_group', 'type':'option', 'value':str(DN(('cn', 'users'), ('cn', 'accounts'), ipasrv.getBaseDN()))+'?sub'},
|
|
{'name':'nss_schema', 'type':'option', 'value':'rfc2307bis'},
|
|
{'name':'nss_map_attribute', 'type':'option', 'value':'uniqueMember member'},
|
|
{'name':'nss_initgroups_ignoreusers', 'type':'option', 'value':'root,dirsrv'},
|
|
{'name':'empty', 'type':'empty'},
|
|
{'name':'nss_reconnect_maxsleeptime', 'type':'option', 'value':'8'},
|
|
{'name':'nss_reconnect_sleeptime', 'type':'option', 'value':'1'},
|
|
{'name':'bind_timelimit', 'type':'option', 'value':'5'},
|
|
{'name':'timelimit', 'type':'option', 'value':'15'},
|
|
{'name':'empty', 'type':'empty'},
|
|
{'name':'uri', 'type':'option', 'value':'ldap://'+ipasrv.getServerName()},
|
|
{'name':'empty', 'type':'empty'}]
|
|
try:
|
|
ldapconf.newConf("/etc/ldap.conf", opts)
|
|
except Exception, e:
|
|
print "Configuration failed: " + str(e)
|
|
return 1
|
|
|
|
if not "" == ipasrv.getRealmName():
|
|
#Configure krb5.conf
|
|
krbconf = ipachangeconf.IPAChangeConf("IPA Installer")
|
|
krbconf.setOptionAssignment(" = ")
|
|
krbconf.setSectionNameDelimiters(("[","]"))
|
|
krbconf.setSubSectionDelimiters(("{","}"))
|
|
krbconf.setIndent((""," "," "))
|
|
|
|
opts = [{'name':'comment', 'type':'comment', 'value':'File modified by ipa-client-install'},
|
|
{'name':'empty', 'type':'empty'}]
|
|
|
|
#[libdefaults]
|
|
libopts = [{'name':'default_realm', 'type':'option', 'value':ipasrv.getRealmName()}]
|
|
libopts.append({'name':'dns_lookup_realm', 'type':'option', 'value':'false'})
|
|
libopts.append({'name':'dns_lookup_kdc', 'type':'option', 'value':'true'})
|
|
libopts.append({'name':'ticket_lifetime', 'type':'option', 'value':'24h'})
|
|
libopts.append({'name':'forwardable', 'type':'option', 'value':'yes'})
|
|
|
|
opts.append({'name':'libdefaults', 'type':'section', 'value':libopts})
|
|
opts.append({'name':'empty', 'type':'empty'})
|
|
|
|
#[realms]
|
|
kropts =[{'name':'kdc', 'type':'option', 'value':ipasrv.getServerName()+':88'},
|
|
{'name':'master_kdc', 'type':'option', 'value':ipasrv.getServerName()+':88'},
|
|
{'name':'admin_server', 'type':'option', 'value':ipasrv.getServerName()+':749'},
|
|
{'name':'default_domain', 'type':'option', 'value':ipasrv.getDomainName()}]
|
|
ropts = [{'name':ipasrv.getRealmName(), 'type':'subsection', 'value':kropts}]
|
|
opts.append({'name':'realms', 'type':'section', 'value':ropts})
|
|
opts.append({'name':'empty', 'type':'empty'})
|
|
|
|
#[domain_realm]
|
|
dropts = [{'name':'.'+ipasrv.getDomainName(), 'type':'option', 'value':ipasrv.getRealmName()},
|
|
{'name':ipasrv.getDomainName(), 'type':'option', 'value':ipasrv.getRealmName()}]
|
|
opts.append({'name':'domain_realm', 'type':'section', 'value':dropts})
|
|
opts.append({'name':'empty', 'type':'empty'})
|
|
|
|
#[appdefaults]
|
|
pamopts = [{'name':'debug', 'type':'option', 'value':'false'},
|
|
{'name':'ticket_lifetime', 'type':'option', 'value':'36000'},
|
|
{'name':'renew_lifetime', 'type':'option', 'value':'36000'},
|
|
{'name':'forwardable', 'type':'option', 'value':'true'},
|
|
{'name':'krb4_convert', 'type':'option', 'value':'false'}]
|
|
appopts = [{'name':'pam', 'type':'subsection', 'value':pamopts}]
|
|
opts.append({'name':'appdefaults', 'type':'section', 'value':appopts})
|
|
|
|
krbconf.newConf("/etc/krb5.conf", opts);
|
|
|
|
#Modify nsswitch to add nss_ldap
|
|
os.system("/usr/sbin/authconfig --enableldap --kickstart")
|
|
|
|
#Modify pam to add pam_krb5
|
|
os.system("/usr/sbin/authconfig --enablekrb5 --kickstart")
|
|
|
|
if options.conf_ntp:
|
|
config_ntp(ipasrv.getServerName())
|
|
|
|
print "Client configuration complete."
|
|
|
|
return 0
|
|
|
|
sys.exit(main())
|