#! /usr/bin/python2 -E # Authors: Simo Sorce # Karl MacMillan # # 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 . # from __future__ import print_function import sys import os from optparse import SUPPRESS_HELP, OptionGroup, OptionValueError from ipaclient.install import client from ipapython.ipa_log_manager import standard_logging_setup, root_logger from ipaplatform.paths import paths from ipapython import version from ipapython.config import IPAOptionParser from ipalib import x509 from ipalib.util import normalize_hostname, validate_domain_name def parse_options(): def validate_ca_cert_file_option(option, opt, value, parser): if not os.path.exists(value): raise OptionValueError("%s option '%s' does not exist" % (opt, value)) if not os.path.isfile(value): raise OptionValueError("%s option '%s' is not a file" % (opt, value)) if not os.path.isabs(value): raise OptionValueError("%s option '%s' is not an absolute file path" % (opt, value)) try: x509.load_certificate_from_file(value) except Exception: raise OptionValueError("%s option '%s' is not a valid certificate file" % (opt, value)) parser.values.ca_cert_file = value def kinit_attempts_callback(option, opt, value, parser): if value < 1: raise OptionValueError( "Option %s expects an integer greater than 0." % opt) parser.values.kinit_attempts = value parser = IPAOptionParser(version=version.VERSION) basic_group = OptionGroup(parser, "basic options") basic_group.add_option("--domain", dest="domain", help="domain name") basic_group.add_option("--server", dest="server", help="FQDN of IPA server", action="append") basic_group.add_option("--realm", dest="realm_name", help="realm name") basic_group.add_option("--fixed-primary", dest="primary", action="store_true", default=False, help="Configure sssd to use fixed server as primary IPA server") 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, help="password to join the IPA realm (assumes bulk " "password unless principal is also set)") basic_group.add_option("-k", "--keytab", dest="keytab", help="path to backed up keytab from previous enrollment") basic_group.add_option("-W", dest="prompt_password", action="store_true", default=False, help="Prompt for a password to join the IPA realm") 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", help="The hostname of this machine (FQDN). If specified, the hostname will be set and " "the system configuration will be updated to persist over reboot. " "By default the result of getfqdn() call from " "Python's socket module is used.") basic_group.add_option("", "--force-join", dest="force_join", action="store_true", default=False, help="Force client enrollment even if already enrolled") basic_group.add_option("--ntp-server", dest="ntp_servers", action="append", help="ntp server to use. This option can be used " "multiple times") basic_group.add_option("-N", "--no-ntp", action="store_false", help="do not configure ntp", default=True, dest="conf_ntp") basic_group.add_option("", "--force-ntpd", dest="force_ntpd", action="store_true", default=False, help="Stop and disable any time&date synchronization services besides ntpd") basic_group.add_option("--nisdomain", dest="nisdomain", help="NIS domain name") basic_group.add_option("--no-nisdomain", action="store_true", default=False, help="do not configure NIS domain name", dest="no_nisdomain") 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-ssh", dest="conf_ssh", default=True, action="store_false", help="do not configure OpenSSH client") basic_group.add_option("--no-sshd", dest="conf_sshd", default=True, action="store_false", help="do not configure OpenSSH server") basic_group.add_option("--no-sudo", dest="conf_sudo", default=True, action="store_false", help="do not configure SSSD as data source for sudo") basic_group.add_option("--no-dns-sshfp", dest="create_sshfp", default=True, action="store_false", help="do not automatically create DNS SSHFP records") basic_group.add_option("--noac", dest="no_ac", default=False, action="store_true", help="do not modify the nsswitch.conf and PAM configuration") basic_group.add_option("-f", "--force", dest="force", action="store_true", default=False, help="force setting of LDAP/Kerberos conf") basic_group.add_option('--kinit-attempts', dest='kinit_attempts', action='callback', type='int', default=5, callback=kinit_attempts_callback, help=("number of attempts to obtain host TGT" " (defaults to %default).")) 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") basic_group.add_option("--ca-cert-file", dest="ca_cert_file", type="string", action="callback", callback=validate_ca_cert_file_option, help="load the CA certificate from this file") basic_group.add_option("--request-cert", dest="request_cert", action="store_true", default=False, help="request certificate for the machine") # --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) basic_group.add_option("--automount-location", dest="location", help="Automount location") basic_group.add_option("--configure-firefox", dest="configure_firefox", action="store_true", default=False, help="configure Firefox to use IPA domain credentials") basic_group.add_option("--firefox-dir", dest="firefox_dir", default=None, help="specify directory where Firefox is installed (for example: '/usr/lib/firefox')") basic_group.add_option("--ip-address", dest="ip_addresses", default=[], action="append", help="Specify IP address that should be added to DNS." " This option can be used multiple times") basic_group.add_option("--all-ip-addresses", dest="all_ip_addresses", default=False, action="store_true", help="All routable IP" " addresses configured on any inteface will be added to DNS") 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, help="Configures the machine to attempt dns updates when the ip address changes.") 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") sssd_group.add_option("--preserve-sssd", dest="preserve_sssd", action="store_true", default=False, help="Preserve old SSSD configuration if possible") 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) options, _args = parser.parse_args() safe_opts = parser.get_safe_opts(options) if (options.server and not options.domain): parser.error("--server cannot be used without providing --domain") if options.domain: try: validate_domain_name(options.domain) except ValueError as ex: parser.error("invalid domain name: %s" % ex) options.domain = normalize_hostname(options.domain) if options.force_ntpd and not options.conf_ntp: parser.error("--force-ntpd cannot be used together with --no-ntp") if options.firefox_dir and not options.configure_firefox: parser.error("--firefox-dir cannot be used without --configure-firefox option") if options.no_nisdomain and options.nisdomain: parser.error("--no-nisdomain cannot be used together with --nisdomain") if options.ip_addresses: if options.dns_updates: parser.error("--ip-address cannot be used together with" " --enable-dns-updates") if options.all_ip_addresses: parser.error("--ip-address cannot be used together with" " --all-ip-addresses") return safe_opts, options def logging_setup(options): log_file = paths.IPACLIENT_INSTALL_LOG if options.uninstall: log_file = paths.IPACLIENT_UNINSTALL_LOG standard_logging_setup( filename=log_file, verbose=True, debug=options.debug, console_format='%(message)s') def main(): safe_options, options = parse_options() logging_setup(options) 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") root_logger.debug('IPA version %s' % version.VENDOR_VERSION) if options.uninstall: rval_check = client.uninstall_check(options) if rval_check != client.SUCCESS: return rval_check return client.uninstall(options) else: rval_check = client.install_check(options) if rval_check != client.SUCCESS: return rval_check return client.install(options) if __name__ == "__main__": try: sys.exit(main()) except KeyboardInterrupt: sys.exit(1) except RuntimeError as e: sys.exit(e)