2007-08-16 18:00:16 -04:00
#! /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
#
2010-12-09 13:59:11 +01:00
# 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.
2007-08-16 18:00:16 -04:00
#
# 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
2010-12-09 13:59:11 +01:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2007-08-16 18:00:16 -04:00
#
2008-05-30 14:21:45 -04:00
try:
import sys
import os
2010-09-17 17:20:23 -04:00
import time
2008-05-30 14:21:45 -04:00
import socket
2012-05-11 14:38:09 +02:00
2011-11-15 14:39:31 -05:00
from ipapython.ipa_log_manager import *
2009-11-19 14:14:42 -05:00
import tempfile
import getpass
2011-12-07 03:40:51 -05:00
from base64 import b64decode
2011-07-06 10:30:24 -04:00
from ipaclient import ipadiscovery
2008-05-30 14:21:45 -04:00
import ipaclient.ipachangeconf
import ipaclient.ntpconf
2011-10-11 17:30:33 -04:00
from ipapython.ipautil import run, user_input, CalledProcessError, file_exists, realm_to_suffix
2011-09-13 00:11:24 +03:00
import ipapython.services as ipaservices
2011-02-17 08:30:36 -05:00
from ipapython import ipautil
2009-02-05 15:03:08 -05:00
from ipapython import sysrestore
from ipapython import version
2010-08-31 17:21:25 -04:00
from ipapython import certmonger
2010-10-29 20:24:31 +02:00
from ipapython.config import IPAOptionParser
2011-12-07 03:15:45 -05:00
from ipalib import api, errors
2010-02-03 15:41:02 -05:00
import SSSDConfig
2010-06-01 14:24:37 -04:00
from ConfigParser import RawConfigParser
2011-09-05 11:04:17 +02:00
from optparse import SUPPRESS_HELP, OptionGroup
2008-05-30 14:21:45 -04:00
except ImportError:
print >> sys.stderr, """\
There was a problem importing one of the required Python modules. The
error was:
%s
""" % sys.exc_value
sys.exit(1)
2011-08-29 17:44:02 -04:00
CLIENT_INSTALL_ERROR = 1
CLIENT_NOT_CONFIGURED = 2
CLIENT_ALREADY_CONFIGURED = 3
CLIENT_UNINSTALL_ERROR = 4 # error after restoring files/state
2011-03-04 17:53:42 -05:00
client_nss_nickname_format = 'IPA Machine Certificate - %s'
2007-08-16 18:00:16 -04:00
def parse_options():
2010-10-29 20:24:31 +02:00
parser = IPAOptionParser(version=version.VERSION)
2011-09-05 11:04:17 +02:00
basic_group = OptionGroup(parser, "basic options")
basic_group.add_option("--domain", dest="domain", help="domain name")
basic_group.add_option("--server", dest="server", help="IPA server")
basic_group.add_option("--realm", dest="realm_name", help="realm name")
2012-06-11 15:43:04 -04:00
basic_group.add_option("--fixed-primary", dest="primary", action="store_true",
default=False, help="Configure sssd to use fixed server as primary IPA server")
2011-09-05 11:04:17 +02:00
basic_group.add_option("-p", "--principal", dest="principal",
help="principal to use to join the IPA realm"),
basic_group.add_option("-w", "--password", dest="password", sensitive=True,
2010-05-05 14:52:39 -04:00
help="password to join the IPA realm (assumes bulk password unless principal is also set)"),
2011-09-05 11:04:17 +02:00
basic_group.add_option("-W", dest="prompt_password", action="store_true",
2009-11-19 14:14:42 -05:00
default=False,
help="Prompt for a password to join the IPA realm"),
2011-09-05 11:04:17 +02:00
basic_group.add_option("--mkhomedir", dest="mkhomedir",
action="store_true", default=False,
help="create home directories for users on their first login")
basic_group.add_option("", "--hostname", dest="hostname",
2012-04-19 19:50:57 +02:00
help="The hostname of this machine (FQDN). If specified, the hostname will be set and "
2011-07-19 15:33:53 +03:00
"the system configuration will be updated to persist over reboot. "
"By default a nodename result from uname(2) is used.")
2011-09-05 11:04:17 +02:00
basic_group.add_option("--ntp-server", dest="ntp_server", help="ntp server to use")
basic_group.add_option("-N", "--no-ntp", action="store_false",
help="do not configure ntp", default=True, dest="conf_ntp")
2011-12-07 03:49:09 -05:00
basic_group.add_option("--ssh-trust-dns", dest="trust_sshfp", default=False, action="store_true",
help="configure OpenSSH client to trust DNS SSHFP records")
basic_group.add_option("--no-sshd", dest="conf_sshd", default=True, action="store_false",
help="do not configure OpenSSH server")
2011-12-07 03:40:51 -05:00
basic_group.add_option("--no-dns-sshfp", dest="create_sshfp", default=True, action="store_false",
help="do not automatically create DNS SSHFP records")
2012-02-23 17:24:46 +01:00
basic_group.add_option("--noac", dest="no_ac", default=False, action="store_true",
help="do not use Authconfig to modify the nsswitch.conf and PAM configuration")
2011-09-05 11:04:17 +02:00
basic_group.add_option("-f", "--force", dest="force", action="store_true",
default=False, help="force setting of LDAP/Kerberos conf")
basic_group.add_option("-d", "--debug", dest="debug", action="store_true",
default=False, help="print debugging information")
basic_group.add_option("-U", "--unattended", dest="unattended",
action="store_true",
help="unattended (un)installation never prompts the user")
# --on-master is used in ipa-server-install and ipa-replica-install
# only, it isn't meant to be used on clients.
basic_group.add_option("--on-master", dest="on_master", action="store_true",
help=SUPPRESS_HELP, default=False)
parser.add_option_group(basic_group)
sssd_group = OptionGroup(parser, "SSSD options")
sssd_group.add_option("--permit", dest="permit",
action="store_true", default=False,
help="disable access rules by default, permit all access.")
sssd_group.add_option("", "--enable-dns-updates", dest="dns_updates",
action="store_true", default=False,
2011-02-17 08:30:36 -05:00
help="Configures the machine to attempt dns updates when the ip address changes.")
2011-09-05 11:04:17 +02:00
sssd_group.add_option("--no-krb5-offline-passwords", dest="krb5_offline_passwords",
action="store_false", default=True,
help="Configure SSSD not to store user password when the server is offline")
sssd_group.add_option("-S", "--no-sssd", dest="sssd",
action="store_false", default=True,
help="Do not configure the client to use SSSD for authentication")
2011-10-12 19:14:55 +03:00
sssd_group.add_option("--preserve-sssd", dest="preserve_sssd",
action="store_true", default=False,
help="Preserve old SSSD configuration if possible")
2011-09-05 11:04:17 +02:00
parser.add_option_group(sssd_group)
uninstall_group = OptionGroup(parser, "uninstall options")
uninstall_group.add_option("", "--uninstall", dest="uninstall", action="store_true",
default=False, help="uninstall an existing installation. The uninstall can " \
"be run with --unattended option")
parser.add_option_group(uninstall_group)
2007-08-16 18:00:16 -04:00
options, args = parser.parse_args()
2010-10-29 20:24:31 +02:00
safe_opts = parser.get_safe_opts(options)
2007-08-16 18:00:16 -04:00
2008-04-09 15:55:46 -04:00
if (options.server and not options.domain):
parser.error("--server cannot be used without providing --domain")
2010-10-29 20:24:31 +02:00
return safe_opts, options
2007-08-16 18:00:16 -04:00
def logging_setup(options):
2008-03-31 17:33:55 -04:00
log_file = "/var/log/ipaclient-install.log"
2012-06-08 09:36:38 -04:00
2008-03-31 17:33:55 -04:00
if options.uninstall:
log_file = "/var/log/ipaclient-uninstall.log"
2012-06-08 09:36:38 -04:00
standard_logging_setup(
filename=log_file, verbose=True, debug=options.debug,
console_format='%(message)s')
2007-08-16 18:00:16 -04:00
2011-09-13 00:11:24 +03:00
def log_service_error(name, action, error):
2012-06-08 09:36:38 -04:00
root_logger.error("%s failed to %s: %s", name, action, str(error))
2011-09-13 00:11:24 +03:00
2010-05-05 14:52:39 -04:00
def nickname_exists(nickname):
(sout, serr, returncode) = run(["/usr/bin/certutil", "-L", "-d", "/etc/pki/nssdb", "-n", nickname], raiseonerr=False)
if returncode == 0:
return True
else:
return False
2011-12-05 10:19:10 +01:00
# Checks whether nss_ldap or nss-pam-ldapd is installed. If anyone of mandatory files was found returns True and list of all files found.
def nssldap_exists():
files_to_check = [{'function':'configure_ldap_conf', 'mandatory':['/etc/ldap.conf','/etc/nss_ldap.conf','/etc/libnss-ldap.conf'], 'optional':['/etc/pam_ldap.conf']},
{'function':'configure_nslcd_conf', 'mandatory':['/etc/nslcd.conf']}]
files_found = {}
retval = False
for function in files_to_check:
files_found[function['function']]=[]
for file_type in ['mandatory','optional']:
try:
for filename in function[file_type]:
if file_exists(filename):
files_found[function['function']].append(filename)
if file_type == 'mandatory':
retval = True
except KeyError:
pass
return (retval, files_found)
2012-06-08 09:36:38 -04:00
def uninstall(options, env):
2008-03-31 17:33:55 -04:00
2011-04-27 16:09:43 +02:00
if not fstore.has_files():
2012-06-08 09:36:38 -04:00
root_logger.error("IPA client is not configured on this system.")
2011-08-29 17:44:02 -04:00
return CLIENT_NOT_CONFIGURED
2010-05-06 22:13:41 -04:00
2011-03-24 11:01:40 +01:00
server_fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
2011-04-29 16:23:05 +02:00
if server_fstore.has_files() and not options.on_master:
2012-06-08 09:36:38 -04:00
root_logger.error(
"IPA client is configured as a part of IPA server on this system.")
root_logger.info("Refer to ipa-server-install for uninstallation.")
2011-08-29 17:44:02 -04:00
return CLIENT_NOT_CONFIGURED
2011-03-24 11:01:40 +01:00
2012-05-29 14:20:38 -04:00
try:
run(["ipa-client-automount", "--uninstall", "--debug"])
except Exception, e:
root_logger.error(
"Unconfigured automount client failed: %s", str(e))
# Reload the state as automount unconfigure may have modified it
fstore._load()
statestore._load()
2011-03-04 17:53:42 -05:00
hostname = None
2011-10-12 19:14:55 +03:00
was_sssd_configured = False
try:
sssdconfig = SSSDConfig.SSSDConfig()
sssdconfig.import_config()
domains = sssdconfig.list_active_domains()
if len(domains) > 1:
# There was more than IPA domain configured
was_sssd_configured = True
for name in domains:
domain = sssdconfig.get_domain(name)
2011-03-04 17:53:42 -05:00
try:
2011-10-12 19:14:55 +03:00
provider = domain.get_option('id_provider')
2011-03-04 17:53:42 -05:00
except SSSDConfig.NoOptionError:
continue
2011-10-12 19:14:55 +03:00
if provider == "ipa":
try:
hostname = domain.get_option('ipa_hostname')
except SSSDConfig.NoOptionError:
continue
except Exception, e:
# We were unable to read existing SSSD config. This might mean few things:
# - sssd wasn't installed
# - sssd was removed after install and before uninstall
# - there are no active domains
# in both cases we cannot continue with SSSD
pass
2011-03-04 17:53:42 -05:00
if hostname is None:
hostname = socket.getfqdn()
client_nss_nickname = client_nss_nickname_format % hostname
2010-04-16 17:36:55 -04:00
# Remove our host cert and CA cert
2010-05-05 14:52:39 -04:00
if nickname_exists("IPA CA"):
try:
run(["/usr/bin/certutil", "-D", "-d", "/etc/pki/nssdb", "-n", "IPA CA"])
except Exception, e:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Failed to remove IPA CA from /etc/pki/nssdb: %s", str(e))
2011-03-04 13:09:19 -05:00
# Always start certmonger. We can't untrack something if it isn't
# running
2011-09-13 00:11:24 +03:00
messagebus = ipaservices.knownservices.messagebus
2011-08-09 12:37:56 +02:00
try:
2011-09-13 00:11:24 +03:00
messagebus.start()
2011-08-09 12:37:56 +02:00
except Exception, e:
2011-09-13 00:11:24 +03:00
log_service_error(messagebus.service_name, 'start', e)
2011-08-09 12:37:56 +02:00
2011-09-13 00:11:24 +03:00
cmonger = ipaservices.knownservices.certmonger
2011-03-04 13:09:19 -05:00
try:
2011-09-13 00:11:24 +03:00
cmonger.start()
2011-05-10 15:14:20 +02:00
except Exception, e:
2011-09-13 00:11:24 +03:00
log_service_error(cmonger.service_name, 'start', e)
2011-05-10 15:14:20 +02:00
2011-03-04 13:09:19 -05:00
try:
certmonger.stop_tracking('/etc/pki/nssdb', nickname=client_nss_nickname)
except (CalledProcessError, RuntimeError), e:
2012-06-08 09:36:38 -04:00
root_logger.error("%s failed to stop tracking certificate: %s",
cmonger.service_name, str(e))
2011-05-10 15:14:20 +02:00
2010-09-17 17:20:23 -04:00
if nickname_exists(client_nss_nickname):
2010-05-05 14:52:39 -04:00
try:
2010-09-17 17:20:23 -04:00
run(["/usr/bin/certutil", "-D", "-d", "/etc/pki/nssdb", "-n", client_nss_nickname])
2010-05-05 14:52:39 -04:00
except Exception, e:
2012-06-08 09:36:38 -04:00
root_logger.error("Failed to remove %s from /etc/pki/nssdb: %s",
client_nss_nickname, str(e))
2010-05-03 15:15:43 -04:00
2010-02-03 15:41:02 -05:00
try:
2011-09-13 00:11:24 +03:00
cmonger.stop()
2011-05-10 15:14:20 +02:00
except Exception, e:
2011-09-13 00:11:24 +03:00
log_service_error(cmonger.service_name, 'stop', e)
2010-02-03 15:41:02 -05:00
2011-03-04 17:53:42 -05:00
# Remove any special principal names we added to the IPA CA helper
certmonger.remove_principal_from_cas()
2010-02-03 15:41:02 -05:00
try:
2011-09-13 00:11:24 +03:00
cmonger.disable()
2011-05-10 15:14:20 +02:00
except Exception, e:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Failed to disable automatic startup of the %s service: %s",
cmonger.service_name, str(e))
2010-02-03 15:41:02 -05:00
2011-08-29 17:44:02 -04:00
if not options.on_master and os.path.exists('/etc/ipa/default.conf'):
2012-06-08 09:36:38 -04:00
root_logger.info("Unenrolling client from IPA server")
2011-03-04 17:53:42 -05:00
join_args = ["/usr/sbin/ipa-join", "--unenroll", "-h", hostname]
2011-10-20 11:29:26 -04:00
if options.debug:
join_args.append("-d")
env['XMLRPC_TRACE_CURL'] = 'yes'
2010-09-21 15:57:46 -04:00
(stdout, stderr, returncode) = run(join_args, raiseonerr=False, env=env)
if returncode != 0:
2012-06-08 09:36:38 -04:00
root_logger.error("Unenrolling host failed: %s", stderr)
2010-09-17 21:37:32 -04:00
2011-08-29 17:44:02 -04:00
if os.path.exists('/etc/ipa/default.conf'):
2012-06-08 09:36:38 -04:00
root_logger.info(
"Removing Kerberos service principals from /etc/krb5.keytab")
2011-08-29 17:44:02 -04:00
try:
parser = RawConfigParser()
fp = open('/etc/ipa/default.conf', 'r')
parser.readfp(fp)
fp.close()
realm = parser.get('global', 'realm')
run(["/usr/sbin/ipa-rmkeytab", "-k", "/etc/krb5.keytab", "-r", realm])
except Exception, e:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Failed to remove Kerberos service principals: %s", str(e))
2010-04-16 17:36:55 -04:00
2012-06-08 09:36:38 -04:00
root_logger.info("Disabling client Kerberos and LDAP configurations")
2011-10-12 19:14:55 +03:00
was_sssd_installed = False
2011-12-07 03:49:09 -05:00
was_sshd_configured = False
2011-10-12 19:14:55 +03:00
if fstore.has_files():
was_sssd_installed = fstore.has_file("/etc/sssd/sssd.conf")
2011-12-07 03:49:09 -05:00
sshd_config = os.path.join(ipaservices.knownservices.sshd.get_config_dir(), "sshd_config")
was_sshd_configured = fstore.has_file(sshd_config)
2008-03-31 17:33:55 -04:00
try:
2011-09-13 00:11:24 +03:00
auth_config = ipaservices.authconfig()
2011-10-12 19:14:55 +03:00
if statestore.has_state('authconfig'):
# disable only those configurations that we enabled during install
for conf in ('ldap', 'krb5', 'sssd', 'sssdauth', 'mkhomedir'):
cnf = statestore.restore_state('authconfig', conf)
if cnf:
auth_config.disable(conf)
else:
# There was no authconfig status store
# It means the code was upgraded after original install
# Fall back to old logic
auth_config.disable("ldap").\
disable("krb5")
if not(was_sssd_installed and was_sssd_configured):
# assume there was sssd.conf before install and there were more than one domain in it
# In such case restoring sssd.conf will require us to keep SSSD running
auth_config.disable("sssd").\
disable("sssdauth")
auth_config.disable("mkhomedir")
auth_config.add_option("update")
2011-09-13 00:11:24 +03:00
auth_config.execute()
2008-03-31 17:33:55 -04:00
except Exception, e:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Failed to remove krb5/LDAP configuration: %s", str(e))
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
if fstore.has_files():
2012-06-08 09:36:38 -04:00
root_logger.info("Restoring client configuration files")
2011-08-29 17:44:02 -04:00
fstore.restore_all_files()
2008-03-31 17:33:55 -04:00
2012-06-08 09:36:38 -04:00
old_hostname = statestore.restore_state('network', 'hostname')
2011-07-19 15:33:53 +03:00
if old_hostname is not None and old_hostname != hostname:
try:
ipautil.run(['/bin/hostname', old_hostname])
except CalledProcessError, e:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Failed to set this machine's hostname to %s (%s).",
old_hostname, str(e))
2010-04-16 17:36:55 -04:00
2011-09-13 00:11:24 +03:00
nscd = ipaservices.knownservices.nscd
if nscd.is_installed():
2011-05-10 15:14:20 +02:00
try:
2011-09-13 00:11:24 +03:00
nscd.restart()
2011-05-10 15:14:20 +02:00
except:
2012-06-08 09:36:38 -04:00
root_logger.warning(
"Failed to restart the %s daemon", nscd.service_name)
2011-05-18 17:06:15 +02:00
2011-05-10 15:14:20 +02:00
try:
2011-09-13 00:11:24 +03:00
nscd.enable()
2011-05-10 15:14:20 +02:00
except:
2012-06-08 09:36:38 -04:00
root_logger.warning(
"Failed to configure automatic startup of the %s daemon",
nscd.service_name)
2011-05-10 15:14:20 +02:00
else:
# this is optional service, just log
2012-06-08 09:36:38 -04:00
root_logger.info("%s daemon is not installed, skip configuration",
nscd.service_name)
2010-05-03 15:15:43 -04:00
2011-09-13 00:11:24 +03:00
nslcd = ipaservices.knownservices.nslcd
if nslcd.is_installed():
2011-05-18 17:06:15 +02:00
try:
2011-09-13 00:11:24 +03:00
nslcd.stop()
2011-05-18 17:06:15 +02:00
except:
2012-06-08 09:36:38 -04:00
root_logger.warning(
"Failed to stop the %s daemon", nslcd.service_name)
2011-05-18 17:06:15 +02:00
try:
2011-09-13 00:11:24 +03:00
nslcd.disable()
2011-05-18 17:06:15 +02:00
except:
2012-06-08 09:36:38 -04:00
root_logger.warning(
"Failed to disable automatic startup of the %s daemon",
nslcd.service_name)
2011-05-18 17:06:15 +02:00
else:
# this is optional service, just log
2012-06-08 09:36:38 -04:00
root_logger.info("%s daemon is not installed, skip configuration",
nslcd.service_name)
2011-05-18 17:06:15 +02:00
2011-10-04 13:56:12 +03:00
ntp_configured = statestore.has_state('ntp')
if ntp_configured:
ntp_enabled = statestore.restore_state('ntp', 'enabled')
ntp_step_tickers = statestore.restore_state('ntp', 'step-tickers')
2011-10-05 15:11:29 +03:00
restored = False
2011-10-04 13:56:12 +03:00
try:
# Restore might fail due to file missing in backup
# the reason for it might be that freeipa-client was updated
# to this version but not unenrolled/enrolled again
# In such case it is OK to fail
restored = fstore.restore_file("/etc/ntp.conf")
restored |= fstore.restore_file("/etc/sysconfig/ntpd")
if ntp_step_tickers:
restored |= fstore.restore_file("/etc/ntp/step-tickers")
except:
pass
if not ntp_enabled:
ipaservices.knownservices.ntpd.stop()
ipaservices.knownservices.ntpd.disable()
else:
if restored:
ipaservices.knownservices.ntpd.restart()
2011-12-07 03:49:09 -05:00
if was_sshd_configured and ipaservices.knownservices.sshd.is_running():
ipaservices.knownservices.sshd.restart()
2011-10-12 19:14:55 +03:00
if was_sssd_installed and was_sssd_configured:
# SSSD was installed before our installation, config now is restored, restart it
2012-06-08 09:36:38 -04:00
root_logger.info(
"The original configuration of SSSD included other domains than " +
"the IPA-based one.")
root_logger.info(
"Original configuration file was restored, restarting SSSD " +
"service.")
2011-10-12 19:14:55 +03:00
sssd = ipaservices.service('sssd')
sssd.restart()
2008-03-31 17:33:55 -04:00
if not options.unattended:
2012-06-08 09:36:38 -04:00
root_logger.info(
"The original nsswitch.conf configuration has been restored.")
root_logger.info(
"You may need to restart services or reboot the machine.")
2008-03-31 17:33:55 -04:00
if not options.on_master:
2008-07-21 12:25:37 +02:00
if user_input("Do you want to reboot the machine?", False):
2008-03-31 17:33:55 -04:00
try:
2012-03-02 07:18:56 -05:00
run(["/sbin/reboot"])
2008-03-31 17:33:55 -04:00
except Exception, e:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Reboot command failed to exceute: %s", str(e))
2011-08-29 17:44:02 -04:00
return CLIENT_UNINSTALL_ERROR
2008-03-31 17:33:55 -04:00
2012-05-29 14:20:38 -04:00
rv = 0
if fstore.has_files():
root_logger.error('Some files have not been restored, see /var/lib/ipa-client/sysrestore/sysrestore.index')
has_state = False
for module in statestore.modules.keys():
root_logger.error('Some installation state for %s has not been restored, see /var/lib/ipa/sysrestore/sysrestore.state' % module)
has_state = True
rv = 1
if has_state:
root_logger.warning('Some installation state has not been restored.\nThis may cause re-installation to fail.\nIt should be safe to remove /var/lib/ipa-client/sysrestore.state but it may\nmean your system hasn\'t be restored to its pre-installation state.')
2010-01-28 14:22:50 -05:00
# Remove the IPA configuration file
try:
os.remove("/etc/ipa/default.conf")
except:
pass
2012-06-08 09:36:38 -04:00
root_logger.info("Client uninstall complete.")
2012-05-29 14:20:38 -04:00
return rv
2011-08-29 17:44:02 -04:00
2009-11-19 14:14:42 -05:00
def configure_ipa_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server):
ipaconf = ipaclient.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':'basedn', 'type':'option', 'value':cli_basedn},
{'name':'realm', 'type':'option', 'value':cli_realm},
{'name':'domain', 'type':'option', 'value':cli_domain},
{'name':'server', 'type':'option', 'value':cli_server},
2011-09-30 10:09:55 +02:00
{'name':'xmlrpc_uri', 'type':'option', 'value':'https://%s/ipa/xml' % ipautil.format_netloc(cli_server)},
2010-04-16 17:36:55 -04:00
{'name':'enable_ra', 'type':'option', 'value':'True'}]
2009-11-19 14:14:42 -05:00
opts.append({'name':'global', 'type':'section', 'value':defopts})
opts.append({'name':'empty', 'type':'empty'})
2011-08-30 16:32:40 +02:00
target_fname = '/etc/ipa/default.conf'
fstore.backup_file(target_fname)
ipaconf.newConf(target_fname, opts)
os.chmod(target_fname, 0644)
2009-11-19 14:14:42 -05:00
return 0
2011-12-05 10:19:10 +01:00
def configure_ldap_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, dnsok, options, files):
2009-11-19 14:14:42 -05:00
ldapconf = ipaclient.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':cli_basedn},
{'name':'empty', 'type':'empty'},
{'name':'nss_base_passwd', 'type':'option', 'value':'cn=users,cn=accounts,'+cli_basedn+'?sub'},
{'name':'nss_base_group', 'type':'option', 'value':'cn=groups,cn=accounts,'+cli_basedn+'?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'}]
if not dnsok or options.force or options.on_master:
if options.on_master:
opts.append({'name':'uri', 'type':'option', 'value':'ldap://localhost'})
else:
2011-09-30 10:09:55 +02:00
opts.append({'name':'uri', 'type':'option', 'value':'ldap://'+ipautil.format_netloc(cli_server)})
2009-11-19 14:14:42 -05:00
else:
opts.append({'name':'nss_srv_domain', 'type':'option', 'value':cli_domain})
opts.append({'name':'empty', 'type':'empty'})
2010-08-04 10:09:35 -04:00
# Depending on the release and distribution this may exist in any
# number of different file names, update what we find
2011-12-05 10:19:10 +01:00
for filename in files:
try:
fstore.backup_file(filename)
ldapconf.newConf(filename, opts)
except Exception, e:
2012-06-08 09:36:38 -04:00
root_logger.error("Creation of %s failed: %s", filename, str(e))
2011-12-05 10:19:10 +01:00
return (1, 'LDAP', filename)
2010-08-04 10:09:35 -04:00
2011-10-14 11:29:35 -04:00
if files:
return (0, 'LDAP', ', '.join(files))
2012-06-08 09:36:38 -04:00
return 0, None, None
2010-08-04 10:09:35 -04:00
2011-12-05 10:19:10 +01:00
def configure_nslcd_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, dnsok, options, files):
2010-08-04 10:09:35 -04:00
nslcdconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer")
nslcdconf.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':cli_basedn},
{'name':'empty', 'type':'empty'},
{'name':'base passwd', 'type':'option', 'value':'cn=users,cn=accounts,'+cli_basedn},
{'name':'base group', 'type':'option', 'value':'cn=groups,cn=accounts,'+cli_basedn},
{'name':'map group', 'type':'option', 'value':'uniqueMember member'},
{'name':'timelimit', 'type':'option', 'value':'15'},
{'name':'empty', 'type':'empty'}]
if not dnsok or options.force or options.on_master:
if options.on_master:
opts.append({'name':'uri', 'type':'option', 'value':'ldap://localhost'})
else:
2011-09-30 10:09:55 +02:00
opts.append({'name':'uri', 'type':'option', 'value':'ldap://'+ipautil.format_netloc(cli_server)})
2010-08-04 10:09:35 -04:00
else:
opts.append({'name':'uri', 'type':'option', 'value':'DNS'})
opts.append({'name':'empty', 'type':'empty'})
2011-12-05 10:19:10 +01:00
for filename in files:
2010-08-04 10:09:35 -04:00
try:
2011-12-05 10:19:10 +01:00
fstore.backup_file(filename)
nslcdconf.newConf(filename, opts)
2010-08-04 10:09:35 -04:00
except Exception, e:
2012-06-08 09:36:38 -04:00
root_logger.error("Creation of %s failed: %s", filename, str(e))
2011-07-29 13:05:07 +03:00
return (1, None, None)
2009-11-19 14:14:42 -05:00
2011-09-13 00:11:24 +03:00
nslcd = ipaservices.knownservices.nslcd
if nslcd.is_installed():
2011-05-18 17:06:15 +02:00
try:
2011-09-13 00:11:24 +03:00
nslcd.restart()
2011-05-18 17:06:15 +02:00
except Exception, e:
2011-09-13 00:11:24 +03:00
log_service_error(nslcd.service_name, 'restart', e)
2011-05-18 17:06:15 +02:00
try:
2011-09-13 00:11:24 +03:00
nslcd.enable()
2011-05-18 17:06:15 +02:00
except Exception, e:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Failed to enable automatic startup of the %s daemon: %s",
nslcd.service_name, str(e))
2011-05-18 17:06:15 +02:00
else:
2012-06-08 09:36:38 -04:00
root_logger.debug("%s daemon is not installed, skip configuration",
nslcd.service_name)
2011-07-29 13:05:07 +03:00
return (0, None, None)
2011-05-18 17:06:15 +02:00
2011-12-05 10:19:10 +01:00
return (0, 'NSLCD', ', '.join(files))
2009-11-19 14:14:42 -05:00
2012-01-31 22:44:20 -05:00
def configure_openldap_conf(fstore, cli_basedn, cli_server):
ldapconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer")
ldapconf.setOptionAssignment(" ")
opts = [{'name':'comment', 'type':'comment', 'value':'File modified by ipa-client-install'},
{'name':'empty', 'type':'empty'},
{'name':'URI', 'type':'option', 'value':'ldaps://'+ cli_server},
{'name':'BASE', 'type':'option', 'value':cli_basedn},
{'name':'TLS_CACERT', 'type':'option', 'value':'/etc/ipa/ca.crt'},
{'name':'empty', 'type':'empty'}]
target_fname = '/etc/openldap/ldap.conf'
fstore.backup_file(target_fname)
ldapconf.newConf(target_fname, opts)
os.chmod(target_fname, 0644)
2009-11-19 14:14:42 -05:00
def hardcode_ldap_server(cli_server):
"""
DNS Discovery didn't return a valid IPA server, hardcode a value into
the file instead.
"""
2010-08-04 10:09:35 -04:00
if not file_exists('/etc/ldap.conf'):
return
2009-11-19 14:14:42 -05:00
ldapconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer")
ldapconf.setOptionAssignment(" ")
2011-09-30 10:09:55 +02:00
opts = [{'name':'uri', 'type':'option', 'action':'set', 'value':'ldap://'+ipautil.format_netloc(cli_server)},
2009-11-19 14:14:42 -05:00
{'name':'empty', 'type':'empty'}]
# Errors raised by this should be caught by the caller
ldapconf.changeConf("/etc/ldap.conf", opts)
2012-06-08 09:36:38 -04:00
root_logger.info("Changed configuration of /etc/ldap.conf to use " +
"hardcoded server name: %s", cli_server)
2009-11-19 14:14:42 -05:00
return
2011-10-21 11:18:26 +02:00
def configure_krb5_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, cli_kdc, dnsok, options, filename, client_domain):
2009-11-19 14:14:42 -05:00
krbconf = ipaclient.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':cli_realm}]
2011-03-21 14:50:05 +01:00
if not dnsok or not cli_kdc or options.force:
2009-11-19 14:14:42 -05:00
libopts.append({'name':'dns_lookup_realm', 'type':'option', 'value':'false'})
libopts.append({'name':'dns_lookup_kdc', 'type':'option', 'value':'false'})
else:
libopts.append({'name':'dns_lookup_realm', 'type':'option', 'value':'true'})
libopts.append({'name':'dns_lookup_kdc', 'type':'option', 'value':'true'})
2011-02-10 21:47:45 +01:00
libopts.append({'name':'rdns', 'type':'option', 'value':'false'})
2009-11-19 14:14:42 -05:00
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'})
#the following are necessary only if DNS discovery does not work
2011-03-21 14:50:05 +01:00
if not dnsok or not cli_kdc or options.force:
2009-11-19 14:14:42 -05:00
#[realms]
2011-09-30 10:09:55 +02:00
kropts =[{'name':'kdc', 'type':'option', 'value':ipautil.format_netloc(cli_server, 88)},
{'name':'admin_server', 'type':'option', 'value':ipautil.format_netloc(cli_server, 749)},
2009-11-19 14:14:42 -05:00
{'name':'default_domain', 'type':'option', 'value':cli_domain}]
2010-09-21 15:57:46 -04:00
else:
kropts = []
kropts.append({'name':'pkinit_anchors', 'type':'option', 'value':'FILE:/etc/ipa/ca.crt'})
ropts = [{'name':cli_realm, 'type':'subsection', 'value':kropts}]
opts.append({'name':'realms', 'type':'section', 'value':ropts})
opts.append({'name':'empty', 'type':'empty'})
2009-11-19 14:14:42 -05:00
#[domain_realm]
dropts = [{'name':'.'+cli_domain, 'type':'option', 'value':cli_realm},
{'name':cli_domain, 'type':'option', 'value':cli_realm}]
2011-10-21 11:18:26 +02:00
#add client domain mapping if different from server domain
if cli_domain != client_domain:
dropts.append({'name':'.'+client_domain, 'type':'option', 'value':cli_realm})
dropts.append({'name':client_domain, 'type':'option', 'value':cli_realm})
2009-11-19 14:14:42 -05:00
opts.append({'name':'domain_realm', 'type':'section', 'value':dropts})
opts.append({'name':'empty', 'type':'empty'})
2012-06-08 09:36:38 -04:00
root_logger.debug("Writing Kerberos configuration to %s:", filename)
root_logger.debug("%s", krbconf.dump(opts))
2011-03-23 14:49:48 +01:00
2011-08-30 16:32:40 +02:00
krbconf.newConf(filename, opts)
os.chmod(filename, 0644)
2009-11-19 14:14:42 -05:00
return 0
2011-03-04 17:53:42 -05:00
def configure_certmonger(fstore, subject_base, cli_realm, hostname, options):
2010-02-03 15:41:02 -05:00
started = True
2011-03-04 17:53:42 -05:00
principal = 'host/%s@%s' % (hostname, cli_realm)
2011-09-13 00:11:24 +03:00
messagebus = ipaservices.knownservices.messagebus
2011-08-09 12:37:56 +02:00
try:
2011-09-13 00:11:24 +03:00
messagebus.start()
2011-08-09 12:37:56 +02:00
except Exception, e:
2011-09-13 00:11:24 +03:00
log_service_error(messagebus.service_name, 'start', e)
2011-08-09 12:37:56 +02:00
2011-03-04 17:53:42 -05:00
# Ensure that certmonger has been started at least once to generate the
# cas files in /var/lib/certmonger/cas.
2011-09-13 00:11:24 +03:00
cmonger = ipaservices.knownservices.certmonger
2011-03-04 17:53:42 -05:00
try:
2011-09-13 00:11:24 +03:00
cmonger.restart()
2011-05-10 15:14:20 +02:00
except Exception, e:
2011-09-13 00:11:24 +03:00
log_service_error(cmonger.service_name, 'restart', e)
2011-03-04 17:53:42 -05:00
if options.hostname:
# It needs to be stopped if we touch them
try:
2011-09-13 00:11:24 +03:00
cmonger.stop()
2011-05-10 15:14:20 +02:00
except Exception, e:
2011-09-13 00:11:24 +03:00
log_service_error(cmonger.service_name, 'stop', e)
2011-03-04 17:53:42 -05:00
# If the hostname is explicitly set then we need to tell certmonger
# which principal name to use when requesting certs.
certmonger.add_principal_to_cas(principal)
2010-02-03 15:41:02 -05:00
try:
2011-09-13 00:11:24 +03:00
cmonger.restart()
2011-05-10 15:14:20 +02:00
except Exception, e:
2011-09-13 00:11:24 +03:00
log_service_error(cmonger.service_name, 'restart', e)
2012-06-08 09:36:38 -04:00
root_logger.warning(
"Automatic certificate management will not be available")
2010-02-03 15:41:02 -05:00
started = False
try:
2011-09-13 00:11:24 +03:00
cmonger.enable()
2011-05-10 15:14:20 +02:00
except Exception, e:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Failed to configure automatic startup of the %s daemon: %s",
cmonger.service_name, str(e))
root_logger.warning(
"Automatic certificate management will not be available")
2010-02-03 15:41:02 -05:00
# Request our host cert
if started:
2011-03-04 17:53:42 -05:00
client_nss_nickname = client_nss_nickname_format % hostname
subject = 'CN=%s,%s' % (hostname, subject_base)
2010-02-03 15:41:02 -05:00
try:
2010-09-17 17:20:23 -04:00
run(["ipa-getcert", "request", "-d", "/etc/pki/nssdb", "-n", client_nss_nickname, "-N", subject, "-K", principal])
2010-02-03 15:41:02 -05:00
except:
2012-06-08 09:36:38 -04:00
root_logger.error(
"%s request for host certificate failed", cmonger.service_name)
2011-08-10 15:15:01 +03:00
2012-04-12 14:19:15 +02:00
def configure_sssd_conf(fstore, cli_realm, cli_domain, cli_server, options, client_domain, client_hostname):
2011-10-12 19:14:55 +03:00
try:
sssdconfig = SSSDConfig.SSSDConfig()
sssdconfig.import_config()
except Exception, e:
if os.path.exists("/etc/sssd/sssd.conf") and options.preserve_sssd:
# SSSD config is in place but we are unable to read it
# In addition, we are instructed to preserve it
# This all means we can't use it and have to bail out
2012-06-08 09:36:38 -04:00
root_logger.error(
"SSSD config exists but cannot be parsed: %s", str(e))
root_logger.error(
"Was instructed to preserve existing SSSD config")
root_logger.info("Correct errors in /etc/sssd/sssd.conf and " +
"re-run installation")
2011-10-12 19:14:55 +03:00
return 1
# SSSD configuration does not exist or we are not asked to preserve it, create new one
# We do make new SSSDConfig instance because IPAChangeConf-derived classes have no
# means to reset their state and ParseError exception could come due to parsing
# error from older version which cannot be upgraded anymore, leaving sssdconfig
# instance practically unusable
# Note that we already backed up sssd.conf before going into this routine
2012-06-08 09:36:38 -04:00
if isinstance(e, IOError):
pass
2011-10-12 19:14:55 +03:00
else:
# It was not IOError so it must have been parsing error
2012-06-08 09:36:38 -04:00
root_logger.error("Unable to parse existing SSSD config. " +
"As option --preserve-sssd was not specified, new config " +
"will override the old one.")
root_logger.info("The old /etc/sssd/sssd.conf is backed up and " +
"will be restored during uninstall.")
2011-11-15 14:39:31 -05:00
root_logger.info("New SSSD config will be created")
2011-10-12 19:14:55 +03:00
sssdconfig = SSSDConfig.SSSDConfig()
sssdconfig.new_config()
2010-02-03 15:41:02 -05:00
2011-10-14 14:05:07 -04:00
try:
domain = sssdconfig.new_domain(cli_domain)
except SSSDConfig.DomainAlreadyExistsError:
2012-06-08 09:36:38 -04:00
root_logger.info("Domain %s is already configured in existing SSSD " +
"config, creating a new one.", cli_domain)
root_logger.info("The old /etc/sssd/sssd.conf is backed up and will " +
"be restored during uninstall.")
2011-10-14 14:05:07 -04:00
sssdconfig = SSSDConfig.SSSDConfig()
sssdconfig.new_config()
domain = sssdconfig.new_domain(cli_domain)
2012-02-16 04:21:56 -05:00
try:
sssdconfig.activate_service('ssh')
except SSSDConfig.NoServiceError:
2012-06-08 09:36:38 -04:00
root_logger.error("Unable to activate the SSH service in SSSD config.")
root_logger.info(
"Please make sure you have SSSD built with SSH support installed.")
root_logger.info(
"Configure SSH support manually in /etc/sssd/sssd.conf.")
2012-02-16 04:21:56 -05:00
2010-02-03 15:41:02 -05:00
domain.add_provider('ipa', 'id')
2011-12-21 22:32:01 +01:00
#add discovery domain if client domain different from server domain
if cli_domain != client_domain:
domain.set_option('dns_discovery_domain', cli_domain)
2011-06-20 15:39:25 -04:00
if not options.on_master:
2012-06-11 15:43:04 -04:00
if options.primary:
domain.set_option('ipa_server', '%s, _srv_' % cli_server)
else:
domain.set_option('ipa_server', '_srv_, %s' % cli_server)
2011-06-20 15:39:25 -04:00
else:
# the master should only use itself for Kerberos
domain.set_option('ipa_server', cli_server)
2010-02-03 15:41:02 -05:00
domain.set_option('ipa_domain', cli_domain)
2012-04-12 14:19:15 +02:00
domain.set_option('ipa_hostname', client_hostname)
2011-02-21 10:25:52 -05:00
if cli_domain.lower() != cli_realm.lower():
domain.set_option('krb5_realm', cli_realm)
2010-02-03 15:41:02 -05:00
# Might need this if /bin/hostname doesn't return a FQDN
#domain.set_option('ipa_hostname', 'client.example.com')
domain.add_provider('ipa', 'auth')
domain.add_provider('ipa', 'chpass')
if not options.permit:
domain.add_provider('ipa', 'access')
else:
domain.add_provider('permit', 'access')
domain.set_option('cache_credentials', True)
2011-07-19 16:07:05 +03:00
# SSSD will need TLS for checking if ipaMigrationEnabled attribute is set
# Note that SSSD will force StartTLS because the channel is later used for
# authentication as well if password migration is enabled. Thus set the option
# unconditionally.
domain.set_option('ldap_tls_cacert', '/etc/ipa/ca.crt')
2011-02-17 08:30:36 -05:00
if options.dns_updates:
domain.set_option('ipa_dyndns_update', True)
2011-06-28 14:19:51 +02:00
if options.krb5_offline_passwords:
domain.set_option('krb5_store_password_if_offline', True)
2011-02-17 08:30:36 -05:00
2010-02-03 15:41:02 -05:00
domain.set_active(True)
sssdconfig.save_domain(domain)
sssdconfig.write("/etc/sssd/sssd.conf")
return 0
2011-12-07 03:49:09 -05:00
def change_ssh_config(filename, changes, sections):
if len(changes) == 0:
return True
try:
f = open(filename, 'r')
except IOError, e:
2012-06-08 09:36:38 -04:00
root_logger.error("Failed to open '%s': %s", filename, str(e))
2011-12-07 03:49:09 -05:00
return False
lines = []
in_section = False
for line in f:
if in_section:
lines.append(line)
continue
pline = line.strip()
if len(pline) == 0 or pline.startswith('#'):
lines.append(line)
continue
parts = pline.split()
option = parts[0].lower()
for key in sections:
if key.lower() == option:
in_section = True
break
if in_section:
break
for opt in changes:
if opt.lower() == option:
line = None
break
if line is not None:
lines.append(line)
for opt in changes:
2012-02-16 04:21:56 -05:00
if changes[opt] is not None:
lines.append('%s %s\n' % (opt, changes[opt]))
2011-12-07 03:49:09 -05:00
lines.append('\n')
if in_section:
lines.append(line)
for line in f:
lines.append(line)
f.close()
try:
f = open(filename, 'w')
except IOError, e:
2012-06-08 09:36:38 -04:00
root_logger.error("Failed to open '%s': %s", filename, str(e))
2011-12-07 03:49:09 -05:00
return False
f.write(''.join(lines))
f.close()
return True
def configure_ssh(fstore, ssh_dir, options):
ssh_config = os.path.join(ssh_dir, 'ssh_config')
sshd_config = os.path.join(ssh_dir, 'sshd_config')
if file_exists(ssh_config):
fstore.backup_file(ssh_config)
2012-05-23 05:00:55 -04:00
changes = {
'PubkeyAuthentication': 'yes',
}
2011-12-07 03:49:09 -05:00
if options.trust_sshfp:
changes['VerifyHostKeyDNS'] = 'yes'
2012-05-23 05:00:55 -04:00
changes['HostKeyAlgorithms'] = 'ssh-rsa,ssh-dss'
2012-02-16 04:21:56 -05:00
elif options.sssd and file_exists('/usr/bin/sss_ssh_knownhostsproxy'):
changes['ProxyCommand'] = '/usr/bin/sss_ssh_knownhostsproxy -p %p %h'
2012-05-23 05:00:55 -04:00
changes['GlobalKnownHostsFile'] = '/var/lib/sss/pubconf/known_hosts'
2011-12-07 03:49:09 -05:00
change_ssh_config(ssh_config, changes, ['Host'])
2012-06-08 09:36:38 -04:00
root_logger.info('Configured %s', ssh_config)
2011-12-07 03:49:09 -05:00
if not options.conf_sshd:
return
sshd = ipaservices.knownservices.sshd
if not sshd.is_installed():
2012-06-08 09:36:38 -04:00
root_logger.info("%s daemon is not installed, skip configuration",
sshd.service_name)
2011-12-07 03:49:09 -05:00
return
fstore.backup_file(sshd_config)
changes = {
2012-05-23 05:00:55 -04:00
'PubkeyAuthentication': 'yes',
2012-04-30 11:58:55 -04:00
'KerberosAuthentication': 'no',
2011-12-07 03:49:09 -05:00
'GSSAPIAuthentication': 'yes',
'UsePAM': 'yes',
}
2012-02-16 04:21:56 -05:00
if options.sssd and file_exists('/usr/bin/sss_ssh_authorizedkeys'):
(stdout, stderr, retcode) = ipautil.run(['sshd', '-t', '-f', '/dev/null', '-o', 'AuthorizedKeysCommand='], raiseonerr=False)
if retcode == 0:
changes['AuthorizedKeysCommand'] = '/usr/bin/sss_ssh_authorizedkeys'
changes['AuthorizedKeysCommandRunAs'] = None
else:
(stdout, stderr, retcode) = ipautil.run(['sshd', '-t', '-f', '/dev/null', '-o', 'PubKeyAgent='], raiseonerr=False)
if retcode == 0:
changes['PubKeyAgent'] = '/usr/bin/sss_ssh_authorizedkeys %u'
changes['PubkeyAgentRunAs'] = None
else:
2012-06-08 09:36:38 -04:00
root_logger.warning("Installed OpenSSH server does not " +
"support dynamically loading authorized user keys. " +
"Public key authentication of IPA users will not be " +
"available.")
2012-02-16 04:21:56 -05:00
2011-12-07 03:49:09 -05:00
change_ssh_config(sshd_config, changes, ['Match'])
2012-06-08 09:36:38 -04:00
root_logger.info('Configured %s', sshd_config)
2011-12-07 03:49:09 -05:00
if sshd.is_running():
try:
sshd.restart()
except Exception, e:
log_service_error(sshd.service_name, 'restart', e)
2011-02-17 08:30:36 -05:00
def resolve_ipaddress(server):
2011-04-27 16:09:43 +02:00
""" Connect to the server's LDAP port in order to determine what ip
2011-02-17 08:30:36 -05:00
address this machine uses as "public" ip (relative to the server).
"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
2011-09-19 11:41:31 +02:00
try:
s.connect((server, 389))
addr, port = s.getsockname()
except socket.gaierror:
s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP)
s.connect((server, 389))
addr, port, foo, bar = s.getsockname()
2011-02-17 08:30:36 -05:00
s.close()
return addr
2011-12-07 03:36:27 -05:00
def do_nsupdate(update_txt):
2012-06-08 09:36:38 -04:00
root_logger.debug("Writing nsupdate commands to %s:", UPDATE_FILE)
root_logger.debug("%s", update_txt)
2011-12-07 03:36:27 -05:00
update_fd = file(UPDATE_FILE, "w")
update_fd.write(update_txt)
update_fd.flush()
update_fd.close()
result = False
try:
ipautil.run(['/usr/bin/nsupdate', '-g', UPDATE_FILE])
result = True
except CalledProcessError, e:
2012-06-08 09:36:38 -04:00
root_logger.debug('nsupdate failed: %s', str(e))
2011-12-07 03:36:27 -05:00
try:
os.remove(UPDATE_FILE)
except:
pass
return result
2011-02-17 08:30:36 -05:00
UPDATE_TEMPLATE_A = """
zone $ZONE.
update delete $HOSTNAME. IN A
send
update add $HOSTNAME. $TTL IN A $IPADDRESS
send
"""
UPDATE_TEMPLATE_AAAA = """
zone $ZONE.
update delete $HOSTNAME. IN AAAA
send
update add $HOSTNAME. $TTL IN AAAA $IPADDRESS
send
"""
UPDATE_FILE = "/etc/ipa/.dns_update.txt"
CCACHE_FILE = "/etc/ipa/.dns_ccache"
def update_dns(server, hostname):
ip = resolve_ipaddress(server)
sub_dict = dict(HOSTNAME=hostname,
IPADDRESS=ip,
TTL=1200,
ZONE='.'.join(hostname.split('.')[1:])
)
if len(ip.split('.')) == 4:
template = UPDATE_TEMPLATE_A
2012-06-08 09:36:38 -04:00
elif ':' in ip:
2011-02-17 08:30:36 -05:00
template = UPDATE_TEMPLATE_AAAA
2012-06-08 09:36:38 -04:00
else:
root_logger.info("Failed to determine this machine's ip address.")
root_logger.warning("Failed to update DNS A record.")
2011-02-17 08:30:36 -05:00
return
update_txt = ipautil.template_str(template, sub_dict)
2011-03-23 14:49:48 +01:00
2011-12-07 03:36:27 -05:00
if do_nsupdate(update_txt):
2012-06-08 09:36:38 -04:00
root_logger.info("DNS server record set to: %s -> %s", hostname, ip)
2011-12-07 03:36:27 -05:00
else:
2012-06-08 09:36:38 -04:00
root_logger.error("Failed to update DNS records.")
2011-02-17 08:30:36 -05:00
def client_dns(server, hostname, dns_updates=False):
2012-05-11 14:38:09 +02:00
dns_ok = ipautil.is_host_resolvable(hostname)
2011-02-17 08:30:36 -05:00
2012-05-11 14:38:09 +02:00
if not dns_ok:
2012-06-08 09:36:38 -04:00
root_logger.warning("Hostname (%s) not found in DNS", hostname)
2011-02-17 08:30:36 -05:00
if dns_updates or not dns_ok:
update_dns(server, hostname)
2011-12-07 03:40:51 -05:00
def update_ssh_keys(server, hostname, ssh_dir, create_sshfp):
pubkeys = []
for basename in os.listdir(ssh_dir):
if not basename.endswith('.pub'):
continue
filename = os.path.join(ssh_dir, basename)
try:
f = open(filename, 'r')
except IOError, e:
2012-06-08 09:36:38 -04:00
root_logger.warning("Failed to open '%s': %s", filename, str(e))
2011-12-07 03:40:51 -05:00
continue
for line in f:
line = line[:-1]
if line.startswith('#'):
continue
parts = line.split()
if len(parts) < 2:
continue
try:
pubkey = b64decode(parts[1])
except TypeError:
continue
try:
algo, data, fp = ipautil.decode_ssh_pubkey(pubkey)
except ValueError:
continue
if parts[0] != algo:
continue
2012-06-08 09:36:38 -04:00
root_logger.info("Adding SSH public key from %s", filename)
2011-12-07 03:40:51 -05:00
pubkeys.append(unicode(parts[1]))
f.close()
try:
result = api.Command['host_mod'](unicode(hostname), ipasshpubkey=pubkeys, updatedns=False)
except errors.EmptyModlist:
pass
except StandardError, e:
2012-06-08 09:36:38 -04:00
root_logger.info("host_mod: %s", str(e))
root_logger.warning("Failed to upload host SSH public keys.")
2011-12-07 03:40:51 -05:00
return
if create_sshfp:
zone = '.'.join(hostname.split('.')[1:])
ttl = 1200
update_txt = 'zone %s.\nupdate delete %s. IN SSHFP\nsend\n' % (zone, hostname)
for pubkey in pubkeys:
pubkey = b64decode(pubkey)
sshfp = ipautil.make_sshfp(pubkey)
if sshfp is not None:
update_txt += 'update add %s. %s IN SSHFP %s\n' % (hostname, ttl, sshfp)
update_txt += 'send\n'
if not do_nsupdate(update_txt):
2012-06-08 09:36:38 -04:00
root_logger.warning("Could not update DNS SSHFP records.")
2011-12-07 03:40:51 -05:00
2011-08-29 17:44:02 -04:00
def install(options, env, fstore, statestore):
2010-09-17 21:23:08 -04:00
dnsok = False
2010-05-06 16:41:59 -04:00
2008-04-09 15:55:46 -04:00
cli_domain = None
cli_server = None
2010-11-01 13:51:14 -04:00
subject_base = None
2010-04-05 16:27:46 -04:00
2012-06-13 11:44:06 -04:00
cli_domain_source = 'Unknown source'
cli_server_source = 'Unknown source'
2009-11-19 14:14:42 -05:00
if options.unattended and (options.password is None and options.principal is None and options.prompt_password is False) and not options.on_master:
2012-06-08 09:36:38 -04:00
root_logger.error("One of password and principal are required.")
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2009-11-19 14:14:42 -05:00
2011-03-17 10:22:33 -04:00
if options.hostname:
hostname = options.hostname
2012-06-13 11:44:06 -04:00
hostname_source = 'Provided as option'
2011-03-17 10:22:33 -04:00
else:
hostname = socket.getfqdn()
2012-06-13 11:44:06 -04:00
hostname_source = "Machine's FQDN"
2011-03-17 10:22:33 -04:00
if hostname != hostname.lower():
2012-06-08 09:36:38 -04:00
root_logger.error(
"Invalid hostname '%s', must be lower-case.", hostname)
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2012-01-20 13:44:48 +01:00
if (hostname == 'localhost') or (hostname == 'localhost.localdomain'):
2012-06-08 09:36:38 -04:00
root_logger.error("Invalid hostname, '%s' must not be used.", hostname)
2012-01-20 13:44:48 +01:00
return CLIENT_INSTALL_ERROR
2011-03-17 10:22:33 -04:00
2011-12-05 10:19:10 +01:00
# when installing with '--no-sssd' option, check whether nss-ldap is installed
if not options.sssd:
(nssldap_installed, nosssd_files) = nssldap_exists()
if not nssldap_installed:
2012-06-08 09:36:38 -04:00
root_logger.error("One of these packages must be installed: " +
"nss_ldap or nss-pam-ldapd")
2011-12-05 10:19:10 +01:00
return CLIENT_INSTALL_ERROR
2007-08-16 18:00:16 -04:00
# Create the discovery instance
2011-07-06 10:30:24 -04:00
ds = ipadiscovery.IPADiscovery()
2007-08-16 18:00:16 -04:00
2011-07-06 10:30:24 -04:00
ret = ds.search(domain=options.domain, server=options.server, hostname=hostname)
2011-05-18 17:06:15 +02:00
2011-07-06 10:30:24 -04:00
if ret == ipadiscovery.BAD_HOST_CONFIG:
2012-06-08 09:36:38 -04:00
root_logger.error("Can't get the fully qualified name of this host")
root_logger.info("Check that the client is properly configured")
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2011-07-06 10:30:24 -04:00
if ret == ipadiscovery.NOT_FQDN:
2012-06-08 09:36:38 -04:00
root_logger.error("%s is not a fully-qualified hostname", hostname)
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2011-10-12 10:55:08 +02:00
if ret in (ipadiscovery.NO_LDAP_SERVER, ipadiscovery.NOT_IPA_SERVER) \
2012-06-13 11:44:06 -04:00
or not ds.domain:
if ret == ipadiscovery.NO_LDAP_SERVER:
if ds.server:
root_logger.debug("%s is not an LDAP server" % ds.server)
else:
root_logger.debug("No LDAP server found")
elif ret == ipadiscovery.NOT_IPA_SERVER:
if ds.server:
root_logger.debug("%s is not an IPA server" % ds.server)
else:
root_logger.debug("No IPA server found")
else:
root_logger.debug("Domain not found")
2007-08-16 18:00:16 -04:00
if options.domain:
2008-04-09 15:55:46 -04:00
cli_domain = options.domain
2012-06-13 11:44:06 -04:00
cli_domain_source = 'Provided as option'
2007-08-16 18:00:16 -04:00
elif options.unattended:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Unable to discover domain, not provided on command line")
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2007-08-16 18:00:16 -04:00
else:
2012-06-08 09:36:38 -04:00
root_logger.info(
"DNS discovery failed to determine your DNS domain")
2011-07-29 13:05:07 +03:00
cli_domain = user_input("Provide the domain name of your IPA server (ex: example.com)", allow_empty = False)
2012-06-13 11:44:06 -04:00
cli_domain_source = 'Provided interactively'
root_logger.debug(
"will use interactively provided domain: %s", cli_domain)
2011-07-06 10:30:24 -04:00
ret = ds.search(domain=cli_domain, server=options.server, hostname=hostname)
2011-05-18 17:06:15 +02:00
2008-04-09 15:55:46 -04:00
if not cli_domain:
2012-06-13 11:44:06 -04:00
if ds.domain:
cli_domain = ds.domain
cli_domain_source = ds.domain_source
root_logger.debug("will use discovered domain: %s", cli_domain)
2008-04-09 15:55:46 -04:00
2011-10-21 11:18:26 +02:00
client_domain = hostname[hostname.find(".")+1:]
2011-10-12 10:55:08 +02:00
if ret in (ipadiscovery.NO_LDAP_SERVER, ipadiscovery.NOT_IPA_SERVER) \
2012-06-13 11:44:06 -04:00
or not ds.server:
2011-11-15 14:39:31 -05:00
root_logger.debug("IPA Server not found")
2007-08-30 19:40:54 -04:00
if options.server:
2008-04-09 15:55:46 -04:00
cli_server = options.server
2012-06-13 11:44:06 -04:00
cli_server_source = 'Provided as option'
2007-08-30 19:40:54 -04:00
elif options.unattended:
2012-06-08 09:36:38 -04:00
root_logger.error("Unable to find IPA Server to join")
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2007-08-30 19:40:54 -04:00
else:
2012-06-08 09:36:38 -04:00
root_logger.debug("DNS discovery failed to find the IPA Server")
2011-07-29 13:05:07 +03:00
cli_server = user_input("Provide your IPA server name (ex: ipa.example.com)", allow_empty = False)
2012-06-13 11:44:06 -04:00
cli_server_source = 'Provided interactively'
root_logger.debug("will use interactively provided server: %s", cli_server)
2011-07-06 10:30:24 -04:00
ret = ds.search(domain=cli_domain, server=cli_server, hostname=hostname)
2010-09-17 21:23:08 -04:00
else:
dnsok = True
2008-04-09 15:55:46 -04:00
if not cli_server:
2012-06-13 11:44:06 -04:00
if ds.server:
cli_server = ds.server
cli_server_source = ds.server_source
root_logger.debug("will use discovered server: %s", cli_server)
2008-04-09 15:55:46 -04:00
2011-07-06 10:30:24 -04:00
if ret == ipadiscovery.NOT_IPA_SERVER:
2012-06-08 09:36:38 -04:00
root_logger.error("%s is not an IPA v2 Server.", cli_server)
2012-06-13 11:44:06 -04:00
root_logger.debug("(%s: %s)", cli_server, cli_server_source)
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2011-09-28 16:31:38 -04:00
if ret == ipadiscovery.NO_ACCESS_TO_LDAP:
2012-06-08 09:36:38 -04:00
root_logger.warning("Anonymous access to the LDAP server is disabled.")
root_logger.info("Proceeding without strict verification.")
root_logger.info("Note: This is not an error if anonymous access " +
"has been explicitly restricted.")
2011-09-28 16:31:38 -04:00
ret = 0
2007-08-30 19:40:54 -04:00
if ret != 0:
2012-06-08 09:36:38 -04:00
root_logger.error("Failed to verify that %s is an IPA Server.",
cli_server)
root_logger.error("This may mean that the remote server is not up " +
"or is not reachable due to network or firewall settings.")
2012-06-13 11:44:06 -04:00
root_logger.debug("(%s: %s)", cli_server, cli_server_source)
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2007-08-30 19:40:54 -04:00
2012-06-13 11:44:06 -04:00
cli_kdc = ds.kdc
2011-03-21 14:50:05 +01:00
if dnsok and not cli_kdc:
2012-06-08 09:36:38 -04:00
root_logger.error("DNS domain '%s' is not configured for automatic " +
2012-06-13 11:44:06 -04:00
"KDC address lookup.", ds.realm.lower())
root_logger.debug("(%s: %s)", ds.realm, ds.realm_source)
2012-06-08 09:36:38 -04:00
root_logger.error("KDC address will be set to fixed value.")
2011-03-21 14:50:05 +01:00
2007-08-30 19:40:54 -04:00
if dnsok:
2012-06-08 09:36:38 -04:00
root_logger.info("Discovery was successful!")
2007-08-30 19:40:54 -04:00
elif not options.unattended:
2012-06-08 09:36:38 -04:00
root_logger.warning("The failure to use DNS to find your IPA server " +
"indicates that your resolv.conf file is not properly configured.")
root_logger.info("Autodiscovery of servers for failover cannot work " +
"with this configuration.")
root_logger.info("If you proceed with the installation, services " +
"will be configured to always access the discovered server for " +
"all operations and will not fail over to other servers in case " +
"of failure.")
2011-02-09 13:51:35 -05:00
if not user_input("Proceed with fixed values and no DNS discovery?", False):
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2007-08-30 19:40:54 -04:00
2012-06-13 11:44:06 -04:00
cli_realm = ds.realm
cli_realm_source = ds.realm_source
root_logger.debug("will use discovered realm: %s", cli_realm)
if options.realm_name and options.realm_name != cli_realm:
2012-06-08 09:36:38 -04:00
root_logger.error(
"The provided realm name [%s] does not match discovered one [%s]",
2012-06-13 11:44:06 -04:00
options.realm_name, cli_realm)
root_logger.debug("(%s: %s)", cli_realm, cli_realm_source)
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2008-02-19 15:57:53 -05:00
2012-06-13 11:44:06 -04:00
cli_basedn = ds.basedn
cli_basedn_source = ds.basedn_source
root_logger.debug("will use discovered basedn: %s", cli_basedn)
subject_base = "O=%s" % cli_realm
2008-04-09 15:55:46 -04:00
2012-06-08 09:36:38 -04:00
root_logger.info("Hostname: %s", hostname)
2012-06-13 11:44:06 -04:00
root_logger.debug("Hostname source: %s", hostname_source)
2012-06-08 09:36:38 -04:00
root_logger.info("Realm: %s", cli_realm)
2012-06-13 11:44:06 -04:00
root_logger.debug("Realm source: %s", cli_realm_source)
2012-06-08 09:36:38 -04:00
root_logger.info("DNS Domain: %s", cli_domain)
2012-06-13 11:44:06 -04:00
root_logger.debug("DNS Domain source: %s", cli_domain_source)
2012-06-08 09:36:38 -04:00
root_logger.info("IPA Server: %s", cli_server)
2012-06-13 11:44:06 -04:00
root_logger.debug("IPA Server source: %s", cli_server_source)
2012-06-08 09:36:38 -04:00
root_logger.info("BaseDN: %s", cli_basedn)
2012-06-13 11:44:06 -04:00
root_logger.debug("BaseDN source: %s", cli_basedn_source)
2007-08-30 19:40:54 -04:00
2012-06-08 09:36:38 -04:00
print
2008-07-21 12:25:37 +02:00
if not options.unattended and not user_input("Continue to configure the system with these values?", False):
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2012-06-06 10:44:06 -04:00
if not options.on_master:
# Try removing old principals from the keytab
try:
ipautil.run(['/usr/sbin/ipa-rmkeytab',
'-k', '/etc/krb5.keytab', '-r', cli_realm])
except CalledProcessError, e:
if e.returncode not in (3, 5):
# 3 - Unable to open keytab
# 5 - Principal name or realm not found in keytab
root_logger.error("Error trying to clean keytab: " +
"/usr/sbin/ipa-rmkeytab returned %s" % e.returncode)
else:
root_logger.info("Removed old keys for realm %s from %s" % (
cli_realm, '/etc/krb5.keytab'))
2011-10-13 12:16:15 +02:00
if options.hostname and not options.on_master:
2011-08-29 10:22:20 +02:00
# configure /etc/sysconfig/network to contain the hostname we set.
2011-10-13 12:16:15 +02:00
# skip this step when run by ipa-server-install as it always configures
# hostname if different from system hostname
2011-09-13 00:11:24 +03:00
ipaservices.backup_and_replace_hostname(fstore, statestore, options.hostname)
2011-08-29 10:22:20 +02:00
2009-11-19 14:14:42 -05:00
if not options.unattended:
if options.principal is None and options.password is None and options.prompt_password is False:
2011-07-18 22:46:44 -04:00
options.principal = user_input("User authorized to enroll computers", allow_empty=False)
2012-06-13 11:44:06 -04:00
root_logger.debug(
"will use principal provided as option: %s", options.principal)
2007-11-16 20:18:36 -05:00
2010-06-11 11:02:29 -04:00
# Get the CA certificate
try:
# Remove anything already there so that wget doesn't use its
# too-clever renaming feature
os.remove("/etc/ipa/ca.crt")
except:
pass
2010-11-19 23:12:42 -05:00
try:
2011-09-30 10:09:55 +02:00
run(["/usr/bin/wget", "-O", "/etc/ipa/ca.crt", "http://%s/ipa/config/ca.crt" % ipautil.format_netloc(cli_server)])
2010-11-19 23:12:42 -05:00
except CalledProcessError, e:
2012-06-08 09:36:38 -04:00
root_logger.error(
'Retrieving CA from %s failed: %s', cli_server, str(e))
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2010-06-11 11:02:29 -04:00
2009-11-19 14:14:42 -05:00
if not options.on_master:
2011-09-22 11:52:58 -04:00
nolog = tuple()
2009-11-19 14:14:42 -05:00
# First test out the kerberos configuration
try:
2011-10-05 17:25:09 +03:00
# Attempt to sync time with IPA server.
# We assume that NTP servers are discoverable through SRV records in the DNS
# If that fails, we try to sync directly with IPA server, assuming it runs NTP
2012-06-08 09:36:38 -04:00
root_logger.info('Synchronizing time with KDC...')
2012-05-11 14:38:09 +02:00
ntp_servers = ds.ipadns_search_srv(cli_domain, '_ntp._udp', None, break_on_first=False)
2011-10-05 17:25:09 +03:00
synced_ntp = False
2012-05-11 14:38:09 +02:00
if ntp_servers:
2011-10-05 17:25:09 +03:00
for s in ntp_servers:
2012-06-08 09:36:38 -04:00
synced_ntp = ipaclient.ntpconf.synconce_ntp(s, debug=True)
if synced_ntp:
break
2011-10-05 17:25:09 +03:00
if not synced_ntp:
2012-05-11 14:38:09 +02:00
synced_ntp = ipaclient.ntpconf.synconce_ntp(cli_server, debug=True)
2011-10-05 17:25:09 +03:00
if not synced_ntp:
2012-06-08 09:36:38 -04:00
root_logger.warning("Unable to sync time with IPA NTP " +
"server, assuming the time is in sync.")
2009-11-19 14:14:42 -05:00
(krb_fd, krb_name) = tempfile.mkstemp()
os.close(krb_fd)
2011-10-21 11:18:26 +02:00
if configure_krb5_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, cli_kdc, dnsok, options, krb_name, client_domain):
2012-06-08 09:36:38 -04:00
root_logger.error("Test kerberos configuration failed")
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2010-09-10 15:57:40 -04:00
env['KRB5_CONFIG'] = krb_name
2011-10-11 17:30:33 -04:00
join_args = ["/usr/sbin/ipa-join", "-s", cli_server, "-b", realm_to_suffix(cli_realm)]
2009-12-04 16:39:14 -05:00
if options.debug:
join_args.append("-d")
2011-10-20 11:29:26 -04:00
env['XMLRPC_TRACE_CURL'] = 'yes'
2011-01-24 17:32:49 -05:00
if options.hostname:
join_args.append("-h")
join_args.append(options.hostname)
2009-11-19 14:14:42 -05:00
if options.principal is not None:
2010-05-05 14:52:39 -04:00
stdin = None
2009-11-19 14:14:42 -05:00
principal = options.principal
if principal.find('@') == -1:
principal = '%s@%s' % (principal, cli_realm)
2010-05-05 14:52:39 -04:00
if options.password is not None:
stdin = options.password
else:
if not options.unattended:
2011-10-06 08:22:08 +02:00
try:
stdin = getpass.getpass("Password for %s: " % principal)
except EOFError:
stdin = None
2011-02-14 12:00:49 -08:00
if not stdin:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Password must be provided for %s.", principal)
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2010-05-05 14:52:39 -04:00
else:
if sys.stdin.isatty():
2012-06-08 09:36:38 -04:00
root_logger.error("Password must be provided in " +
"non-interactive mode.")
root_logger.info("This can be done via " +
"echo password | ipa-client-install ... " +
"or with the -w option.")
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2010-05-05 14:52:39 -04:00
else:
stdin = sys.stdin.readline()
2010-09-10 15:57:40 -04:00
(stderr, stdout, returncode) = run(["kinit", principal], raiseonerr=False, stdin=stdin, env=env)
2009-11-19 14:14:42 -05:00
if returncode != 0:
2012-06-08 09:36:38 -04:00
root_logger.error("Kerberos authentication failed")
root_logger.info("%s", stdout)
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2009-11-19 14:14:42 -05:00
elif options.password:
2011-09-22 11:52:58 -04:00
nolog = (options.password,)
2009-11-19 14:14:42 -05:00
join_args.append("-w")
join_args.append(options.password)
elif options.prompt_password:
2010-05-05 14:52:39 -04:00
if options.unattended:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Password must be provided in non-interactive mode")
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2011-10-06 08:22:08 +02:00
try:
password = getpass.getpass("Password: ")
except EOFError:
password = None
if not password:
2012-06-08 09:36:38 -04:00
root_logger.error("Password must be provided.")
2011-10-06 08:22:08 +02:00
return CLIENT_INSTALL_ERROR
2009-11-19 14:14:42 -05:00
join_args.append("-w")
join_args.append(password)
2011-09-22 11:52:58 -04:00
nolog = (password,)
2009-11-19 14:14:42 -05:00
# Now join the domain
2011-09-22 11:52:58 -04:00
(stdout, stderr, returncode) = run(join_args, raiseonerr=False, env=env, nolog=nolog)
2009-11-19 14:14:42 -05:00
if returncode != 0:
2012-06-08 09:36:38 -04:00
root_logger.error("Joining realm failed: %s", stderr)
2009-11-19 14:14:42 -05:00
if not options.force:
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2012-06-08 09:36:38 -04:00
root_logger.info("Use ipa-getkeytab to obtain a host " +
"principal for this server.")
2010-09-17 17:20:23 -04:00
else:
2012-06-08 09:36:38 -04:00
root_logger.info("Enrolled in IPA realm %s", cli_realm)
2010-04-05 16:27:46 -04:00
start = stderr.find('Certificate subject base is: ')
if start >= 0:
start = start + 29
subject_base = stderr[start:]
subject_base = subject_base.strip()
2009-11-19 14:14:42 -05:00
finally:
if options.principal is not None:
2010-09-10 15:57:40 -04:00
(stderr, stdout, returncode) = run(["kdestroy"], raiseonerr=False, env=env)
2012-06-08 09:36:38 -04:00
try:
os.remove(krb_name)
except OSError:
root_logger.error("Could not remove %s", krb_name)
try:
os.remove(krb_name + ".ipabkp")
except OSError:
root_logger.error("Could not remove %s.ipabkp", krb_name)
2008-05-23 14:51:50 -04:00
2009-11-19 14:14:42 -05:00
# Configure ipa.conf
if not options.on_master:
configure_ipa_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server)
2012-06-08 09:36:38 -04:00
root_logger.info("Created /etc/ipa/default.conf")
2007-11-16 20:18:36 -05:00
2011-12-07 03:15:45 -05:00
api.bootstrap(context='cli_installer', debug=options.debug)
api.finalize()
if 'config_loaded' not in api.env:
2012-06-08 09:36:38 -04:00
root_logger.error("Failed to initialize IPA API.")
2011-12-07 03:15:45 -05:00
return CLIENT_INSTALL_ERROR
2011-04-21 15:55:17 -04:00
# Always back up sssd.conf. It gets updated by authconfig --enablekrb5.
fstore.backup_file("/etc/sssd/sssd.conf")
2010-02-03 15:41:02 -05:00
if options.sssd:
2012-04-12 14:19:15 +02:00
if configure_sssd_conf(fstore, cli_realm, cli_domain, cli_server, options, client_domain, hostname):
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2012-06-08 09:36:38 -04:00
root_logger.info("Configured /etc/sssd/sssd.conf")
2010-02-03 15:41:02 -05:00
2010-05-03 15:21:51 -04:00
# Add the CA to the default NSS database and trust it
2012-03-09 13:04:23 +01:00
try:
run(["/usr/bin/certutil", "-A", "-d", "/etc/pki/nssdb", "-n", "IPA CA", "-t", "CT,C,C", "-a", "-i", "/etc/ipa/ca.crt"])
except CalledProcessError, e:
2012-06-08 09:36:38 -04:00
root_logger.info("Failed to add CA to the default NSS database.")
2012-03-09 13:04:23 +01:00
return CLIENT_INSTALL_ERROR
2010-04-16 17:36:55 -04:00
2009-11-19 14:14:42 -05:00
# If on master assume kerberos is already configured properly.
2008-09-17 09:45:00 -04:00
if not options.on_master:
2009-11-19 14:14:42 -05:00
# Configure krb5.conf
2008-03-31 17:33:55 -04:00
fstore.backup_file("/etc/krb5.conf")
2011-10-21 11:18:26 +02:00
if configure_krb5_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, cli_kdc, dnsok, options, "/etc/krb5.conf", client_domain):
2011-08-29 17:44:02 -04:00
return CLIENT_INSTALL_ERROR
2009-11-19 14:14:42 -05:00
2012-06-08 09:36:38 -04:00
root_logger.info(
"Configured /etc/krb5.conf for IPA realm %s", cli_realm)
2007-08-30 19:40:54 -04:00
2011-12-07 03:15:45 -05:00
os.environ['KRB5CCNAME'] = CCACHE_FILE
try:
2012-05-02 15:36:04 +02:00
ipautil.run(['/usr/bin/kinit', '-k', '-t', '/etc/krb5.keytab', 'host/%s@%s' % (hostname, cli_realm)])
2011-12-07 03:15:45 -05:00
except CalledProcessError, e:
2012-06-08 09:36:38 -04:00
root_logger.error("Failed to obtain host TGT.")
2012-03-09 13:04:23 +01:00
# fail to obtain ticket makes it impossible to login and bind from sssd to LDAP,
# abort installation and rollback changes
return CLIENT_INSTALL_ERROR
2011-02-17 08:30:36 -05:00
2012-05-02 15:36:04 +02:00
# Now, we have a TGT, lets try to connect to the server's XML-RPC interface
try:
api.Backend.xmlclient.connect()
except errors.KerberosError, e:
2012-06-08 09:36:38 -04:00
root_logger.info('Cannot connect to the server due to ' +
'Kerberos error: %s. Trying with delegate=True', str(e))
2012-05-02 15:36:04 +02:00
try:
api.Backend.xmlclient.connect(delegate=True)
2012-06-08 09:36:38 -04:00
root_logger.info('Connection with delegate=True successful')
2012-05-02 15:36:04 +02:00
# The remote server is not capable of Kerberos S4U2Proxy delegation
# This features is implemented in IPA server version 2.2 and higher
2012-06-08 09:36:38 -04:00
root_logger.warning("Target IPA server has a lower version than " +
"the enrolled client")
root_logger.warning("Some capabilities including the ipa " +
"command capability may not be available")
2012-05-02 15:36:04 +02:00
except errors.PublicError, e2:
2012-06-08 09:36:38 -04:00
root_logger.warning(
'Second connect with delegate=True also failed: %s', str(e2))
root_logger.error(
"Cannot connect to the IPA server XML-RPC interface: %s",
str(e2))
2012-05-02 15:36:04 +02:00
return CLIENT_INSTALL_ERROR
except errors.PublicError, e:
2012-06-08 09:36:38 -04:00
root_logger.error(
'Cannot connect to the server due to generic error: %s', str(e))
2012-05-02 15:36:04 +02:00
return CLIENT_INSTALL_ERROR
2011-12-07 03:15:45 -05:00
if not options.on_master:
client_dns(cli_server, hostname, options.dns_updates)
2011-10-21 11:18:26 +02:00
configure_certmonger(fstore, subject_base, cli_realm, hostname, options)
2011-12-07 03:40:51 -05:00
update_ssh_keys(cli_server, hostname, ipaservices.knownservices.sshd.get_config_dir(), options.create_sshfp)
2011-12-07 03:15:45 -05:00
try:
os.remove(CCACHE_FILE)
except:
pass
2011-05-10 15:14:20 +02:00
#Name Server Caching Daemon. Disable for SSSD, use otherwise (if installed)
2011-09-13 00:11:24 +03:00
nscd = ipaservices.knownservices.nscd
if nscd.is_installed():
2011-05-10 15:14:20 +02:00
try:
2011-09-13 00:11:24 +03:00
if options.sssd:
nscd_service_action = 'stop'
nscd.stop()
else:
nscd_service_action = 'restart'
nscd.restart()
2011-05-10 15:14:20 +02:00
except:
2012-06-08 09:36:38 -04:00
root_logger.warning("Failed to %s the %s daemon",
nscd_service_action, nscd.service_name)
2011-05-10 15:14:20 +02:00
if not options.sssd:
2012-06-08 09:36:38 -04:00
root_logger.warning(
"Caching of users/groups will not be available")
2011-05-18 17:06:15 +02:00
2011-05-10 15:14:20 +02:00
try:
2011-09-13 00:11:24 +03:00
if options.sssd:
nscd.disable()
else:
nscd.enable()
2011-05-10 15:14:20 +02:00
except:
if not options.sssd:
2012-06-08 09:36:38 -04:00
root_logger.warning(
"Failed to configure automatic startup of the %s daemon",
nscd.service_name)
root_logger.info("Caching of users/groups will not be " +
"available after reboot")
2011-07-19 15:33:53 +03:00
else:
2012-06-08 09:36:38 -04:00
root_logger.warning(
"Failed to disable %s daemon. Disable it manually.",
nscd.service_name)
2011-07-01 11:11:38 +03:00
2011-05-10 15:14:20 +02:00
else:
# this is optional service, just log
2011-07-29 13:05:07 +03:00
if not options.sssd:
2012-06-08 09:36:38 -04:00
root_logger.info("%s daemon is not installed, skip configuration",
nscd.service_name)
2011-02-09 13:53:39 -05:00
2011-07-29 13:05:07 +03:00
retcode, conf, filename = (0, None, None)
2010-03-15 13:41:07 -04:00
2012-02-23 17:24:46 +01:00
if not options.no_ac:
# Modify nsswitch/pam stack
auth_config = ipaservices.authconfig()
if options.sssd:
statestore.backup_state('authconfig', 'sssd', True)
statestore.backup_state('authconfig', 'sssdauth', True)
auth_config.enable("sssd").\
enable("sssdauth")
message = "SSSD enabled"
conf = 'SSSD'
else:
statestore.backup_state('authconfig', 'ldap', True)
auth_config.enable("ldap").\
enable("forcelegacy")
message = "LDAP enabled"
2011-09-13 00:11:24 +03:00
2012-02-23 17:24:46 +01:00
if options.mkhomedir:
statestore.backup_state('authconfig', 'mkhomedir', True)
auth_config.enable("mkhomedir")
2007-08-30 19:40:54 -04:00
2012-02-23 17:24:46 +01:00
auth_config.add_option("update")
2011-10-04 14:33:36 +03:00
auth_config.execute()
2012-06-08 09:36:38 -04:00
root_logger.info("%s", message)
2011-05-18 17:06:15 +02:00
2012-02-23 17:24:46 +01:00
if not options.sssd:
#Modify pam to add pam_krb5 only when sssd is not in use
auth_config.reset()
statestore.backup_state('authconfig', 'krb5', True)
auth_config.enable("krb5").\
add_option("update").\
add_option("nostart")
auth_config.execute()
2012-06-08 09:36:38 -04:00
root_logger.info("Kerberos 5 enabled")
2012-02-23 17:24:46 +01:00
# Update non-SSSD LDAP configuration after authconfig calls as it would
# change its configuration otherways
if not options.sssd:
for configurer in [configure_ldap_conf, configure_nslcd_conf]:
2012-06-08 09:36:38 -04:00
(retcode, conf, filenames) = configurer(fstore, cli_basedn, cli_realm, cli_domain, cli_server, dnsok, options, nosssd_files[configurer.__name__])
2012-02-23 17:24:46 +01:00
if retcode:
return CLIENT_INSTALL_ERROR
if conf:
2012-06-08 09:36:38 -04:00
root_logger.info(
"%s configured using configuration file(s) %s",
conf, filenames)
2011-05-18 17:06:15 +02:00
2012-01-31 22:44:20 -05:00
configure_openldap_conf(fstore, cli_basedn, cli_server)
2012-06-08 09:36:38 -04:00
root_logger.info("Configured /etc/openldap/ldap.conf")
2012-01-31 22:44:20 -05:00
2012-02-23 17:24:46 +01:00
#Check that nss is working properly
if not options.on_master:
n = 0
found = False
# Loop for up to 10 seconds to see if nss is working properly.
# It can sometimes take a few seconds to connect to the remote provider.
# Particulary, SSSD might take longer than 6-8 seconds.
while n < 10 and not found:
try:
ipautil.run(["getent", "passwd", "admin"])
found = True
except Exception, e:
time.sleep(1)
n = n + 1
2008-02-20 10:16:19 -05:00
2012-02-23 17:24:46 +01:00
if not found:
2012-06-08 09:36:38 -04:00
root_logger.error(
"Unable to find 'admin' user with 'getent passwd admin'!")
2012-02-23 17:24:46 +01:00
if conf:
2012-06-08 09:36:38 -04:00
root_logger.info("Recognized configuration: %s", conf)
2012-02-23 17:24:46 +01:00
else:
2012-06-08 09:36:38 -04:00
root_logger.error("Unable to reliably detect " +
"configuration. Check NSS setup manually.")
2012-02-23 17:24:46 +01:00
try:
hardcode_ldap_server(cli_server)
except Exception, e:
2012-06-08 09:36:38 -04:00
root_logger.error("Adding hardcoded server name to " +
"/etc/ldap.conf failed: %s", str(e))
2008-02-20 10:16:19 -05:00
if options.conf_ntp and not options.on_master:
2008-03-14 08:42:06 -04:00
if options.ntp_server:
ntp_server = options.ntp_server
else:
2008-04-09 15:55:46 -04:00
ntp_server = cli_server
2011-10-04 13:56:12 +03:00
ipaclient.ntpconf.config_ntp(ntp_server, fstore, statestore)
2012-06-08 09:36:38 -04:00
root_logger.info("NTP enabled")
2011-12-07 03:49:09 -05:00
configure_ssh(fstore, ipaservices.knownservices.sshd.get_config_dir(), options)
2012-06-08 09:36:38 -04:00
root_logger.info('Client configuration complete.')
2008-01-17 16:36:05 -05:00
2007-08-16 18:00:16 -04:00
return 0
2011-08-29 17:44:02 -04:00
def main():
safe_options, options = parse_options()
2011-11-18 13:55:16 +01:00
if not os.getegid() == 0:
sys.exit("\nYou must be root to run ipa-client-install.\n")
2012-05-31 13:59:33 +02:00
ipaservices.check_selinux_status()
2011-08-29 17:44:02 -04:00
logging_setup(options)
2012-06-08 09:36:38 -04:00
root_logger.debug(
'%s was invoked with options: %s', sys.argv[0], safe_options)
root_logger.debug("missing options might be asked for interactively later")
2011-08-29 17:44:02 -04:00
env={"PATH":"/bin:/sbin:/usr/kerberos/bin:/usr/kerberos/sbin:/usr/bin:/usr/sbin"}
global fstore
fstore = sysrestore.FileStore('/var/lib/ipa-client/sysrestore')
global statestore
statestore = sysrestore.StateFile('/var/lib/ipa-client/sysrestore')
if options.uninstall:
return uninstall(options, env)
if fstore.has_files():
2012-06-08 09:36:38 -04:00
root_logger.error("IPA client is already configured on this system.")
root_logger.info(
"If you want to reinstall the IPA client, uninstall it first.")
2011-08-29 17:44:02 -04:00
return CLIENT_ALREADY_CONFIGURED
rval = install(options, env, fstore, statestore)
if rval == CLIENT_INSTALL_ERROR:
if options.force:
2012-06-08 09:36:38 -04:00
root_logger.warning(
"Installation failed. Force set so not rolling back changes.")
2011-08-29 17:44:02 -04:00
else:
2012-06-08 09:36:38 -04:00
root_logger.error("Installation failed. Rolling back changes.")
2011-08-29 17:44:02 -04:00
options.unattended = True
2012-06-08 09:36:38 -04:00
uninstall(options, env)
2011-08-29 17:44:02 -04:00
2011-10-07 14:47:28 +02:00
return rval
2008-02-26 15:31:34 -05:00
try:
2008-05-30 14:21:45 -04:00
if __name__ == "__main__":
sys.exit(main())
except SystemExit, e:
sys.exit(e)
2008-02-26 15:31:34 -05:00
except KeyboardInterrupt:
sys.exit(1)
2011-03-04 13:09:19 -05:00
except RuntimeError, e:
sys.exit(e)
2011-12-07 03:15:45 -05:00
finally:
try:
os.remove(CCACHE_FILE)
except:
pass