summaryrefslogtreecommitdiffstats
path: root/install/tools
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2009-01-29 16:26:07 -0500
committerRob Crittenden <rcritten@redhat.com>2009-02-03 15:27:14 -0500
commite30cd6ba42c256d2016db45146d616f329455e86 (patch)
treed4c5291095c80c92bc4803fe7f20fc2838124ffa /install/tools
parentc4ed025001895bfc65c613cabbbfcb27c19cc29f (diff)
downloadfreeipa-e30cd6ba42c256d2016db45146d616f329455e86.tar.gz
freeipa-e30cd6ba42c256d2016db45146d616f329455e86.tar.xz
freeipa-e30cd6ba42c256d2016db45146d616f329455e86.zip
Mass tree reorganization for IPAv2. To view previous history of files use:
% git log --follow -- <file> renamed: ipa-server/autogen.sh -> autogen.sh renamed: ipa-server/ipa-kpasswd/Makefile.am -> daemons/ipa-kpasswd/Makefile.am renamed: ipa-server/ipa-kpasswd/README -> daemons/ipa-kpasswd/README renamed: ipa-server/ipa-kpasswd/ipa_kpasswd.c -> daemons/ipa-kpasswd/ipa_kpasswd.c renamed: ipa-server/ipa-kpasswd/ipa_kpasswd.init -> daemons/ipa-kpasswd/ipa_kpasswd.init renamed: ipa-server/ipa-slapi-plugins/Makefile.am -> daemons/ipa-slapi-plugins/Makefile.am renamed: ipa-server/ipa-slapi-plugins/README -> daemons/ipa-slapi-plugins/README renamed: ipa-server/ipa-slapi-plugins/dna/Makefile.am -> daemons/ipa-slapi-plugins/dna/Makefile.am renamed: ipa-server/ipa-slapi-plugins/dna/dna-conf.ldif -> daemons/ipa-slapi-plugins/dna/dna-conf.ldif renamed: ipa-server/ipa-slapi-plugins/dna/dna.c -> daemons/ipa-slapi-plugins/dna/dna.c renamed: ipa-server/ipa-slapi-plugins/ipa-memberof/Makefile.am -> daemons/ipa-slapi-plugins/ipa-memberof/Makefile.am renamed: ipa-server/ipa-slapi-plugins/ipa-memberof/ipa-memberof.c -> daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.c renamed: ipa-server/ipa-slapi-plugins/ipa-memberof/ipa-memberof.h -> daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.h renamed: ipa-server/ipa-slapi-plugins/ipa-memberof/ipa-memberof_config.c -> daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof_config.c renamed: ipa-server/ipa-slapi-plugins/ipa-memberof/memberof-conf.ldif -> daemons/ipa-slapi-plugins/ipa-memberof/memberof-conf.ldif renamed: ipa-server/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -> daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am renamed: ipa-server/ipa-slapi-plugins/ipa-pwd-extop/README -> daemons/ipa-slapi-plugins/ipa-pwd-extop/README renamed: ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -> daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c renamed: ipa-server/ipa-slapi-plugins/ipa-pwd-extop/pwd-extop-conf.ldif -> daemons/ipa-slapi-plugins/ipa-pwd-extop/pwd-extop-conf.ldif renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/Makefile.am -> daemons/ipa-slapi-plugins/ipa-winsync/Makefile.am renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/README -> daemons/ipa-slapi-plugins/ipa-winsync/README renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif -> daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/ipa-winsync-config.c -> daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-config.c renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/ipa-winsync.c -> daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync.c renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/ipa-winsync.h -> daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync.h renamed: ipa-server/xmlrpc-server/ipa-rewrite.conf -> install/conf/ipa-rewrite.conf renamed: ipa-server/xmlrpc-server/ipa.conf -> install/conf/ipa.conf renamed: ipa-server/xmlrpc-server/ssbrowser.html -> install/html/ssbrowser.html renamed: ipa-server/xmlrpc-server/unauthorized.html -> install/html/unauthorized.html renamed: ipa-server/ipa-install/share/60ipaconfig.ldif -> install/share/60ipaconfig.ldif renamed: ipa-server/ipa-install/share/60kerberos.ldif -> install/share/60kerberos.ldif renamed: ipa-server/ipa-install/share/60radius.ldif -> install/share/60radius.ldif renamed: ipa-server/ipa-install/share/60samba.ldif -> install/share/60samba.ldif renamed: ipa-server/ipa-install/share/Makefile.am -> install/share/Makefile.am renamed: ipa-server/ipa-install/share/bind.named.conf.template -> install/share/bind.named.conf.template renamed: ipa-server/ipa-install/share/bind.zone.db.template -> install/share/bind.zone.db.template renamed: ipa-server/ipa-install/share/bootstrap-template.ldif -> install/share/bootstrap-template.ldif renamed: ipa-server/ipa-install/share/certmap.conf.template -> install/share/certmap.conf.template renamed: ipa-server/ipa-install/share/default-aci.ldif -> install/share/default-aci.ldif renamed: ipa-server/ipa-install/share/default-keytypes.ldif -> install/share/default-keytypes.ldif renamed: ipa-server/ipa-install/share/dna-posix.ldif -> install/share/dna-posix.ldif renamed: ipa-server/ipa-install/share/encrypted_attribute.ldif -> install/share/encrypted_attribute.ldif renamed: ipa-server/ipa-install/share/fedora-ds.init.patch -> install/share/fedora-ds.init.patch renamed: ipa-server/ipa-install/share/indices.ldif -> install/share/indices.ldif renamed: ipa-server/ipa-install/share/kdc.conf.template -> install/share/kdc.conf.template renamed: ipa-server/ipa-install/share/kerberos.ldif -> install/share/kerberos.ldif renamed: ipa-server/ipa-install/share/krb.con.template -> install/share/krb.con.template renamed: ipa-server/ipa-install/share/krb5.conf.template -> install/share/krb5.conf.template renamed: ipa-server/ipa-install/share/krb5.ini.template -> install/share/krb5.ini.template renamed: ipa-server/ipa-install/share/krbrealm.con.template -> install/share/krbrealm.con.template renamed: ipa-server/ipa-install/share/master-entry.ldif -> install/share/master-entry.ldif renamed: ipa-server/ipa-install/share/memberof-task.ldif -> install/share/memberof-task.ldif renamed: ipa-server/ipa-install/share/ntp.conf.server.template -> install/share/ntp.conf.server.template renamed: ipa-server/ipa-install/share/ntpd.sysconfig.template -> install/share/ntpd.sysconfig.template renamed: ipa-server/ipa-install/share/preferences.html.template -> install/share/preferences.html.template renamed: ipa-server/ipa-install/share/referint-conf.ldif -> install/share/referint-conf.ldif renamed: ipa-server/ipa-install/share/schema_compat.uldif -> install/share/schema_compat.uldif renamed: ipa-server/ipa-install/share/unique-attributes.ldif -> install/share/unique-attributes.ldif renamed: ipa-server/ipa-install/Makefile.am -> install/tools/Makefile.am renamed: ipa-server/ipa-install/README -> install/tools/README renamed: ipa-server/ipa-compat-manage -> install/tools/ipa-compat-manage renamed: ipa-server/ipa-fix-CVE-2008-3274 -> install/tools/ipa-fix-CVE-2008-3274 renamed: ipa-server/ipa-ldap-updater -> install/tools/ipa-ldap-updater renamed: ipa-server/ipa-install/ipa-replica-install -> install/tools/ipa-replica-install renamed: ipa-server/ipa-install/ipa-replica-manage -> install/tools/ipa-replica-manage renamed: ipa-server/ipa-install/ipa-replica-prepare -> install/tools/ipa-replica-prepare renamed: ipa-server/ipa-install/ipa-server-certinstall -> install/tools/ipa-server-certinstall renamed: ipa-server/ipa-install/ipa-server-install -> install/tools/ipa-server-install renamed: ipa-server/ipa-upgradeconfig -> install/tools/ipa-upgradeconfig renamed: ipa-server/ipa-install/ipactl -> install/tools/ipactl renamed: ipa-server/man/Makefile.am -> install/tools/man/Makefile.am renamed: ipa-server/man/ipa-compat-manage.1 -> install/tools/man/ipa-compat-manage.1 renamed: ipa-server/man/ipa-ldap-updater.1 -> install/tools/man/ipa-ldap-updater.1 renamed: ipa-server/man/ipa-replica-install.1 -> install/tools/man/ipa-replica-install.1 renamed: ipa-server/man/ipa-replica-manage.1 -> install/tools/man/ipa-replica-manage.1 renamed: ipa-server/man/ipa-replica-prepare.1 -> install/tools/man/ipa-replica-prepare.1 renamed: ipa-server/man/ipa-server-certinstall.1 -> install/tools/man/ipa-server-certinstall.1 renamed: ipa-server/man/ipa-server-install.1 -> install/tools/man/ipa-server-install.1 renamed: ipa-server/man/ipa_kpasswd.8 -> install/tools/man/ipa_kpasswd.8 renamed: ipa-server/man/ipa_webgui.8 -> install/tools/man/ipa_webgui.8 renamed: ipa-server/man/ipactl.8 -> install/tools/man/ipactl.8 renamed: ipa-server/ipa-install/updates/Makefile.am -> install/updates/Makefile.am renamed: ipa-server/ipa-install/updates/RFC2307bis.update -> install/updates/RFC2307bis.update renamed: ipa-server/ipa-install/updates/RFC4876.update -> install/updates/RFC4876.update renamed: ipa-server/ipa-install/updates/indices.update -> install/updates/indices.update renamed: ipa-server/ipa-install/updates/nss_ldap.update -> install/updates/nss_ldap.update renamed: ipa-server/ipa-install/updates/replication.update -> install/updates/replication.update renamed: ipa-server/ipa-install/updates/winsync_index.update -> install/updates/winsync_index.update renamed: ipa-server/ipaserver/Makefile.am -> ipaserver/install/Makefile.am renamed: ipa-server/ipaserver/__init__.py -> ipaserver/install/__init__.py renamed: ipa-server/ipaserver/bindinstance.py -> ipaserver/install/bindinstance.py renamed: ipa-server/ipaserver/certs.py -> ipaserver/install/certs.py renamed: ipa-server/ipaserver/dsinstance.py -> ipaserver/install/dsinstance.py renamed: ipa-server/ipaserver/httpinstance.py -> ipaserver/install/httpinstance.py renamed: ipa-server/ipaserver/installutils.py -> ipaserver/install/installutils.py renamed: ipa-server/ipaserver/ipaldap.py -> ipaserver/install/ipaldap.py renamed: ipa-server/ipaserver/krbinstance.py -> ipaserver/install/krbinstance.py renamed: ipa-server/ipaserver/ldapupdate.py -> ipaserver/install/ldapupdate.py renamed: ipa-server/ipaserver/ntpinstance.py -> ipaserver/install/ntpinstance.py renamed: ipa-server/ipaserver/replication.py -> ipaserver/install/replication.py renamed: ipa-server/ipaserver/service.py -> ipaserver/install/service.py renamed: ipa-server/selinux/Makefile -> selinux/Makefile renamed: ipa-server/selinux/ipa-server-selinux.spec.in -> selinux/ipa-server-selinux.spec.in renamed: ipa-server/selinux/ipa_kpasswd/ipa_kpasswd.fc -> selinux/ipa_kpasswd/ipa_kpasswd.fc renamed: ipa-server/selinux/ipa_kpasswd/ipa_kpasswd.te -> selinux/ipa_kpasswd/ipa_kpasswd.te renamed: ipa-server/selinux/ipa_webgui/ipa_webgui.fc -> selinux/ipa_webgui/ipa_webgui.fc renamed: ipa-server/selinux/ipa_webgui/ipa_webgui.te -> selinux/ipa_webgui/ipa_webgui.te renamed: ipa-server/version.m4.in -> version.m4.in
Diffstat (limited to 'install/tools')
-rw-r--r--install/tools/Makefile.am24
-rw-r--r--install/tools/README67
-rwxr-xr-xinstall/tools/ipa-compat-manage171
-rw-r--r--install/tools/ipa-fix-CVE-2008-3274524
-rwxr-xr-xinstall/tools/ipa-ldap-updater126
-rw-r--r--install/tools/ipa-replica-install312
-rwxr-xr-xinstall/tools/ipa-replica-manage218
-rw-r--r--install/tools/ipa-replica-prepare294
-rw-r--r--install/tools/ipa-server-certinstall157
-rw-r--r--install/tools/ipa-server-install622
-rw-r--r--install/tools/ipa-upgradeconfig130
-rw-r--r--install/tools/ipactl57
-rw-r--r--install/tools/man/Makefile.am27
-rw-r--r--install/tools/man/ipa-compat-manage.145
-rw-r--r--install/tools/man/ipa-ldap-updater.178
-rw-r--r--install/tools/man/ipa-replica-install.141
-rw-r--r--install/tools/man/ipa-replica-manage.170
-rw-r--r--install/tools/man/ipa-replica-prepare.148
-rw-r--r--install/tools/man/ipa-server-certinstall.148
-rw-r--r--install/tools/man/ipa-server-install.181
-rw-r--r--install/tools/man/ipa_kpasswd.836
-rw-r--r--install/tools/man/ipa_webgui.837
-rw-r--r--install/tools/man/ipactl.837
23 files changed, 3250 insertions, 0 deletions
diff --git a/install/tools/Makefile.am b/install/tools/Makefile.am
new file mode 100644
index 00000000..3f566175
--- /dev/null
+++ b/install/tools/Makefile.am
@@ -0,0 +1,24 @@
+NULL =
+
+SUBDIRS = \
+ share \
+ updates \
+ $(NULL)
+
+sbin_SCRIPTS = \
+ ipa-server-install \
+ ipa-replica-install \
+ ipa-replica-prepare \
+ ipa-replica-manage \
+ ipa-server-certinstall \
+ ipactl \
+ $(NULL)
+
+EXTRA_DIST = \
+ README \
+ $(sbin_SCRIPTS) \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ *~ \
+ Makefile.in
diff --git a/install/tools/README b/install/tools/README
new file mode 100644
index 00000000..a52cede0
--- /dev/null
+++ b/install/tools/README
@@ -0,0 +1,67 @@
+
+Required packages:
+
+krb5-server
+fedora-ds-base
+fedora-ds-base-devel
+openldap-clients
+openldap-devel
+krb5-server-ldap
+cyrus-sasl-gssapi
+httpd
+mod_auth_kerb
+ntp
+openssl-devel
+nspr-devel
+nss-devel
+mozldap-devel
+mod_python
+gcc
+python-ldap
+TurboGears
+python-kerberos
+python-krbV
+python-tgexpandingformwidget
+python-pyasn1
+
+Installation example:
+
+TEMPORARY: until bug https://bugzilla.redhat.com/show_bug.cgi?id=248169 is
+ fixed.
+
+Please apply the fedora-ds.init.patch in freeipa/ipa-server/ipa-install/share/
+to patch your init scripts before running ipa-server-install. This tells
+FDS where to find its kerberos keytab.
+
+Things done as root are denoted by #. Things done as a unix user are denoted
+by %.
+
+# cd freeipa
+# patch -p0 < ipa-server/ipa-install/share/fedora-ds.init.patch
+
+Now to do the installation.
+
+# cd freeipa
+# make install
+
+To start an interactive installation use:
+# /usr/sbin/ipa-server-install
+
+For more verbose output add the -d flag run the command with -h to see all options
+
+You have a basic working system with one super administrator (named admin).
+
+To create another administrative user:
+
+% kinit admin@FREEIPA.ORG
+% /usr/sbin/ipa-adduser -f Test -l User test
+% ldappasswd -Y GSSAPI -h localhost -s password uid=test,cn=users,cn=accounts,dc=freeipa,dc=org
+% /usr/sbin/ipa-groupmod -a test admins
+
+An admin user is just a regular user in the group admin.
+
+Now you can destroy the old ticket and log in as test:
+
+% kdestroy
+% kinit test@FREEIPA.ORG
+% /usr/sbin/ipa-finduser test
diff --git a/install/tools/ipa-compat-manage b/install/tools/ipa-compat-manage
new file mode 100755
index 00000000..648e2c3a
--- /dev/null
+++ b/install/tools/ipa-compat-manage
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+# Authors: Rob Crittenden <rcritten@redhat.com>
+# Authors: Simo Sorce <ssorce@redhat.com>
+#
+# Copyright (C) 2008 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; version 2 only
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+import sys
+try:
+ from optparse import OptionParser
+ from ipaserver import ipaldap
+ from ipa import entity, ipaerror, ipautil, config
+ from ipaserver import installutils
+ from ipaserver.ldapupdate import LDAPUpdate, BadSyntax, UPDATES_DIR
+ import ldap
+ import logging
+ import re
+ import krbV
+ import platform
+ import shlex
+ import time
+ import random
+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)
+
+def parse_options():
+ usage = "%prog [options] <enable|disable>\n"
+ usage += "%prog [options]\n"
+ parser = OptionParser(usage=usage, formatter=config.IPAFormatter())
+
+ parser.add_option("-d", "--debug", action="store_true", dest="debug",
+ help="Display debugging information about the update(s)")
+ parser.add_option("-y", dest="password",
+ help="File containing the Directory Manager password")
+
+ config.add_standard_options(parser)
+ options, args = parser.parse_args()
+
+ config.init_config(options)
+
+ return options, args
+
+def get_dirman_password():
+ """Prompt the user for the Directory Manager password and verify its
+ correctness.
+ """
+ password = installutils.read_password("Directory Manager", confirm=False, validate=False)
+
+ return password
+
+def main():
+ retval = 0
+ loglevel = logging.NOTSET
+ files=['/usr/share/ipa/schema_compat.uldif']
+
+ options, args = parse_options()
+ if options.debug:
+ loglevel = logging.DEBUG
+
+ if len(args) != 1:
+ print "You must specify one action, either enable or disable"
+ sys.exit(1)
+ elif args[0] != "enable" and args[0] != "disable":
+ print "Unrecognized action [" + args[0] + "]"
+ sys.exit(1)
+
+ logging.basicConfig(level=loglevel,
+ format='%(levelname)s %(message)s')
+
+ dirman_password = ""
+ if options.password:
+ pw = ipautil.template_file(options.password, [])
+ dirman_password = pw.strip()
+ else:
+ dirman_password = get_dirman_password()
+
+ try:
+ try:
+ conn = ipaldap.IPAdmin(installutils.get_fqdn())
+ conn.do_simple_bind(bindpw=dirman_password)
+ except ldap.LDAPError, e:
+ print "An error occurred while connecting to the server."
+ print "%s" % e[0]['desc']
+ return 1
+
+ if args[0] == "enable":
+ try:
+ conn.getEntry("cn=Schema Compatibility,cn=plugins,cn=config",
+ ldap.SCOPE_BASE, "(objectclass=*)")
+ print "Plugin already Enabled"
+ retval = 2
+ except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+ print "Enabling plugin"
+ except ldap.LDAPError, e:
+ print "An error occurred while talking to the server."
+ print "%s" % e[0]['desc']
+ retval = 1
+
+ if retval == 0:
+ ld = LDAPUpdate(dm_password=dirman_password, sub_dict={})
+ retval = ld.update(files)
+ if retval == 0:
+ print "This setting will not take effect until you restart Directory Server."
+
+ elif args[0] == "disable":
+ # Make a quick hack foir now, directly delete the entries by name,
+ # In future we should add delete capabilites to LDAPUpdate
+ try:
+ conn.getEntry("cn=Schema Compatibility,cn=plugins,cn=config",
+ ldap.SCOPE_BASE, "(objectclass=*)")
+ conn.deleteEntry("cn=groups,cn=Schema Compatibility,cn=plugins,cn=config")
+ conn.deleteEntry("cn=users,cn=Schema Compatibility,cn=plugins,cn=config")
+ conn.deleteEntry("cn=Schema Compatibility,cn=plugins,cn=config")
+ except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+ print "Plugin is already disabled"
+ retval = 2
+ except ldap.LDAPError, e:
+ print "An error occurred while talking to the server."
+ print "%s" % e[0]['desc']
+ retval = 1
+
+ else:
+ retval = 1
+
+ finally:
+ if conn:
+ conn.unbind()
+
+ return retval
+
+try:
+ if __name__ == "__main__":
+ sys.exit(main())
+except BadSyntax, e:
+ print "There is a syntax error in this update file:"
+ print " %s" % e
+ sys.exit(1)
+except RuntimeError, e:
+ print "%s" % e
+ sys.exit(1)
+except SystemExit, e:
+ sys.exit(e)
+except KeyboardInterrupt, e:
+ sys.exit(1)
+except config.IPAConfigError, e:
+ print "An IPA server to update cannot be found. Has one been configured yet?"
+ print "The error was: %s" % e
+ sys.exit(1)
+except ipaerror, e:
+ print "An error occurred while performing operations: %s" % e
+ sys.exit(1)
diff --git a/install/tools/ipa-fix-CVE-2008-3274 b/install/tools/ipa-fix-CVE-2008-3274
new file mode 100644
index 00000000..41d3abc9
--- /dev/null
+++ b/install/tools/ipa-fix-CVE-2008-3274
@@ -0,0 +1,524 @@
+#!/usr/bin/python
+#
+# Upgrade configuration files to a newer template.
+
+etckrb5conf = "/etc/krb5.conf"
+krb5dir = "/var/kerberos/krb5kdc"
+cachedir = "/var/cache/ipa"
+libdir = "/var/lib/ipa"
+basedir = libdir+"/mkey"
+ourkrb5conf = basedir+"/krb5.conf"
+ldappwdfile = basedir+"/ldappwd"
+
+import sys
+try:
+ from optparse import OptionParser
+
+ import os
+ import random
+ import time
+ import shutil
+ import getpass
+
+ import ipa
+ import ipa.config
+ import ipa.ipautil
+
+ import krbV
+ import ldap
+
+ from ldap import LDAPError
+ from ldap import ldapobject
+
+ from ipaclient import ipachangeconf
+ from ipaserver import ipaldap
+
+ from pyasn1.type import univ, namedtype
+ import pyasn1.codec.ber.encoder
+ import pyasn1.codec.ber.decoder
+ import struct
+ import base64
+
+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)
+
+def parse_options():
+ parser = OptionParser("%prog [--check] [--fix] [--fix-replica]")
+ parser.add_option("--check", dest="check", action="store_true",
+ help="Just check for the vulnerability and report (default action)")
+ parser.add_option("--fix", dest="fix", action="store_true",
+ help="Run checks and start procedure to fix the problem")
+ parser.add_option("--fix-replica", dest="fix_replica", action="store_true",
+ help="Fix a replica after the tool has been tun with --fix on another master")
+
+ ipa.config.add_standard_options(parser)
+ options, args = parser.parse_args()
+
+ ipa.config.verify_args(parser, args)
+ if not options.fix and not options.fix_replica and not options.check:
+ parser.error("please specify at least one option")
+
+ ipa.config.init_config(options)
+
+ return options, args
+
+def check_vuln(realm, suffix):
+
+ try:
+ conn = ldapobject.SimpleLDAPObject("ldap://127.0.0.1/")
+ conn.simple_bind()
+ msgid = conn.search("cn="+realm+",cn=kerberos,"+suffix,
+ ldap.SCOPE_BASE,
+ "(objectclass=krbRealmContainer)",
+ ("krbmkey", "cn"))
+ res = conn.result(msgid)
+ conn.unbind()
+
+ if len(res) != 2:
+ err = 'Realm Container not found, unable to proceed'
+ print err
+ raise Exception, err
+
+ if 'krbmkey' in res[1][0][1]:
+ print 'System vulnerable'
+ return 1
+ else:
+ print 'System *not* vulnerable'
+ return 0
+ except Exception, e:
+ print "Could not connect to the LDAP server, unable to check server"
+ print "("+type(e)+")("+dir(e)+")"
+ raise e
+
+# We support only des3 encoded stash files for now
+def generate_new_stash_file(file):
+
+ odd_parity_bytes_pool = ['\x01', '\x02', '\x04', '\x07', '\x08', '\x0b',
+ '\r', '\x0e', '\x10', '\x13', '\x15', '\x16', '\x19', '\x1a', '\x1c',
+ '\x1f', ' ', '#', '%', '&', ')', '*', ',', '/', '1', '2', '4', '7', '8',
+ ';', '=', '>', '@', 'C', 'E', 'F', 'I', 'J', 'L', 'O', 'Q', 'R', 'T',
+ 'W', 'X', '[', ']', '^', 'a', 'b', 'd', 'g', 'h', 'k', 'm', 'n', 'p',
+ 's', 'u', 'v', 'y', 'z', '|', '\x7f', '\x80', '\x83', '\x85', '\x86',
+ '\x89', '\x8a', '\x8c', '\x8f', '\x91', '\x92', '\x94', '\x97', '\x98',
+ '\x9b', '\x9d', '\x9e', '\xa1', '\xa2', '\xa4', '\xa7', '\xa8', '\xab',
+ '\xad', '\xae', '\xb0', '\xb3', '\xb5', '\xb6', '\xb9', '\xba', '\xbc',
+ '\xbf', '\xc1', '\xc2', '\xc4', '\xc7', '\xc8', '\xcb', '\xcd', '\xce',
+ '\xd0', '\xd3', '\xd5', '\xd6', '\xd9', '\xda', '\xdc', '\xdf', '\xe0',
+ '\xe3', '\xe5', '\xe6', '\xe9', '\xea', '\xec', '\xef', '\xf1', '\xf2',
+ '\xf4', '\xf7', '\xf8', '\xfb', '\xfd', '\xfe']
+
+ pool_len = len(odd_parity_bytes_pool)
+ keytype = 16 # des3
+ keydata = ""
+
+ r = random.SystemRandom()
+ for k in range(24):
+ keydata += r.choice(odd_parity_bytes_pool)
+
+ format = '=hi%ss' % len(keydata)
+ s = struct.pack(format, keytype, len(keydata), keydata)
+ try:
+ fd = open(file, "w")
+ fd.write(s)
+ except os.error, e:
+ logging.critical("failed to write stash file")
+ raise e
+
+# clean up procedures
+def change_mkey_cleanup(password):
+ try:
+ os.stat(basedir)
+ except:
+ return None
+ try:
+ # always remove ldappwdfile as it contains the Directory Manager password
+ os.remove(ldappwdfile)
+ except:
+ pass
+
+ # tar and encrypt the working dir so that we do not leave sensitive data
+ # around unproteceted
+ curtime = time.strftime("%Y%m%d%H%M%S",time.gmtime())
+ tarfile = libdir+"/ipa-change-mkey-"+curtime+".tar"
+ gpgfile = tarfile+".gpg"
+ args = ['/bin/tar', '-C', libdir, '-cf', tarfile, 'mkey']
+ ipa.ipautil.run(args)
+ ipa.ipautil.encrypt_file(tarfile, gpgfile, password, cachedir)
+ os.remove(tarfile)
+ shutil.rmtree(basedir, ignore_errors=True)
+
+ return "The temporary working directory with backup dump files has been securely archived and gpg-encrypted as "+gpgfile+" using the Directory Manager password."
+
+def change_mkey(password = None, quiet = False):
+
+ krbctx = krbV.default_context()
+
+ realm = krbctx.default_realm
+ suffix = ipa.ipautil.realm_to_suffix(realm)
+
+ backupfile = basedir+"/backup.dump"
+ convertfile = basedir+"/convert.dump"
+ oldstashfile = krb5dir+"/.k5."+realm
+ newstashfile = basedir+"/.new.mkey"
+ bkpstashfile = basedir+"/.k5."+realm
+
+ if os.getuid() != 0:
+ print "ERROR: This command must be run as root"
+ sys.exit(1)
+
+ print "DANGER: This is a dangerous operation, make sure you backup all your IPA data before running the tool"
+ print "This command will restart your Directory and KDC Servers."
+
+ #TODO: ask for confirmation
+ if not ipa.ipautil.user_input("Do you want to proceed and change the Kerberos Master key?", False):
+ print ""
+ print "Aborting..."
+ return 1
+
+ if not password:
+ password = getpass.getpass("Directory Manager password: ")
+
+ # get a connection to the DS
+ try:
+ conn = ipaldap.IPAdmin(ipa.config.config.default_server[0])
+ conn.do_simple_bind(bindpw=password)
+ except Exception, e:
+ print "ERROR: Could not connect to the Directory Server on "+ipa.config.config.default_server[0]+" ("+str(e)+")"
+ return 1
+
+ # Wipe basedir and recreate it
+ shutil.rmtree(basedir, ignore_errors=True)
+ os.mkdir(basedir, 0700)
+
+ generate_new_stash_file(newstashfile)
+
+ # Generate conf files
+ try:
+ shutil.copyfile(etckrb5conf, ourkrb5conf)
+
+ krbconf = ipachangeconf.IPAChangeConf("IPA Installer")
+ krbconf.setOptionAssignment(" = ")
+ krbconf.setSectionNameDelimiters(("[","]"))
+ krbconf.setSubSectionDelimiters(("{","}"))
+ krbconf.setIndent((""," "," "))
+
+ #OPTS
+ opts = [{'name':'ldap_kadmind_dn', 'type':'option', 'action':'set', 'value':'cn=Directory Manager'},
+ {'name':'ldap_service_password_file', 'type':'option', 'action':'set', 'value':ldappwdfile}]
+
+ #REALM
+ realmopts = [{'name':realm, 'type':'subsection', 'action':'set', 'value':opts}]
+
+ #DBMODULES
+ dbopts = [{'name':'dbmodules', 'type':'section', 'action':'set', 'value':realmopts}]
+
+ krbconf.changeConf(ourkrb5conf, dbopts);
+
+ hexpwd = ""
+ for x in password:
+ hexpwd += (hex(ord(x))[2:])
+ pwd_fd = open(ldappwdfile, "w")
+ pwd_fd.write("cn=Directory Manager#{HEX}"+hexpwd+"\n")
+ pwd_fd.close()
+ os.chmod(ldappwdfile, 0600)
+
+ except Exception, e:
+ print "Failed to create custom configuration files ("+str(e)+") aborting..."
+ return 1
+
+ #Set environment vars so that the modified krb5.conf is used
+ os.environ['KRB5_CONFIG'] = ourkrb5conf
+
+ #Backup the kerberos key material for recovery if needed
+ args = ["/usr/kerberos/sbin/kdb5_util", "dump", "-verbose", backupfile]
+ print "Performing safety backup of the key material"
+ try:
+ output = ipa.ipautil.run(args)
+ except ipa.ipautil.CalledProcessError, e:
+ print "Failed to backup key material ("+str(e)+"), aborting ..."
+ return 1
+
+ if not quiet:
+ princlist = output[1].split('\n')
+ print "Principals stored into the backup file "+backupfile+":"
+ for p in princlist:
+ print p
+ print ""
+
+ #Convert the kerberos keys to the new master key
+ args = ["/usr/kerberos/sbin/kdb5_util", "dump", "-verbose", "-new_mkey_file", newstashfile, convertfile]
+ print "Converting key material to new master key"
+ try:
+ output = ipa.ipautil.run(args)
+ except ipa.ipautil.CalledProcessError, e:
+ print "Failed to convert key material, aborting ..."
+ return 1
+
+ savedprinclist = output[1].split('\n')
+
+ if not quiet:
+ princlist = output[1].split('\n')
+ print "Principals dumped for conversion:"
+ for p in princlist:
+ print p
+ print ""
+
+ #Stop the KDC
+ args = ["/etc/init.d/krb5kdc", "stop"]
+ try:
+ output = ipa.ipautil.run(args)
+ if output[0]:
+ print output[0]
+ if output[1]:
+ print output[1]
+ except ipa.ipautil.CalledProcessError, e:
+ print "WARNING: Failed to restart the KDC ("+str(e)+")"
+ print "You will have to manually restart the KDC when the operation is completed"
+
+ #Change the mkey into ldap
+ try:
+ stash = open(newstashfile, "r")
+ keytype = struct.unpack('h', stash.read(2))[0]
+ keylen = struct.unpack('i', stash.read(4))[0]
+ keydata = stash.read(keylen)
+
+ #encode it in the asn.1 attribute
+ MasterKey = univ.Sequence()
+ MasterKey.setComponentByPosition(0, univ.Integer(keytype))
+ MasterKey.setComponentByPosition(1, univ.OctetString(keydata))
+ krbMKey = univ.Sequence()
+ krbMKey.setComponentByPosition(0, univ.Integer(0)) #we have no kvno
+ krbMKey.setComponentByPosition(1, MasterKey)
+ asn1key = pyasn1.codec.ber.encoder.encode(krbMKey)
+
+ dn = "cn="+realm+",cn=kerberos,"+suffix
+ mod = [(ldap.MOD_REPLACE, 'krbMKey', str(asn1key))]
+ conn.modify_s(dn, mod)
+ except Exception, e:
+ print "ERROR: Failed to upload the Master Key from the Stash file: "+newstashfile+" ("+str(e)+")"
+ return 1
+
+ #Backup old stash file and substitute with new
+ try:
+ shutil.move(oldstashfile, bkpstashfile)
+ shutil.copyfile(newstashfile, oldstashfile)
+ except Exception, e:
+ print "ERROR: An error occurred while installing the new stash file("+str(e)+")"
+ print "The KDC may fail to start if the correct stash file is not in place"
+ print "Verify that "+newstashfile+" has been correctly installed into "+oldstashfile
+ print "A backup copy of the old stash file should be saved in "+bkpstashfile
+
+ #Finally upload the converted principals
+ args = ["/usr/kerberos/sbin/kdb5_util", "load", "-verbose", "-update", convertfile]
+ print "Uploading converted key material"
+ try:
+ output = ipa.ipautil.run(args)
+ except ipa.ipautil.CalledProcessError, e:
+ print "Failed to upload key material ("+e+"), aborting ..."
+ return 1
+
+ if not quiet:
+ princlist = output[1].split('\n')
+ print "Principals converted and uploaded:"
+ for p in princlist:
+ print p
+ print ""
+
+ uploadedprinclist = output[1].split('\n')
+
+ #Check for differences and report
+ d = []
+ for p in savedprinclist:
+ if uploadedprinclist.count(p) == 0:
+ d.append(p)
+ if len(d) != 0:
+ print "WARNING: Not all dumped principals have been updated"
+ print "Principals not Updated:"
+ for p in d:
+ print p
+
+ #Remove custom environ
+ del os.environ['KRB5_CONFIG']
+
+ #Restart Directory Server (the pwd plugin need to read the new mkey)
+ args = ["/etc/init.d/dirsrv", "restart"]
+ try:
+ output = ipa.ipautil.run(args)
+ if output[0]:
+ print output[0]
+ if output[1]:
+ print output[1]
+ except ipa.ipautil.CalledProcessError, e:
+ print "WARNING: Failed to restart the Directory Server ("+str(e)+")"
+ print "Please manually restart the DS with 'service dirsrv restart'"
+
+ #Restart the KDC
+ args = ["/etc/init.d/krb5kdc", "start"]
+ try:
+ output = ipa.ipautil.run(args)
+ if output[0]:
+ print output[0]
+ if output[1]:
+ print output[1]
+ except ipa.ipautil.CalledProcessError, e:
+ print "WARNING: Failed to restart the KDC ("+str(e)+")"
+ print "Please manually restart the kdc with 'service krb5kdc start'"
+
+ print "Master Password successfully changed"
+ #print "You MUST now copy the stash file "+oldstashfile+" to all the replicas and restart them!"
+ print ""
+
+ return 0
+
+def fix_replica(password, realm, suffix):
+
+ try:
+ conn = ldapobject.SimpleLDAPObject("ldap://127.0.0.1/")
+ conn.simple_bind("cn=Directory Manager", password)
+ msgid = conn.search("cn="+realm+",cn=kerberos,"+suffix,
+ ldap.SCOPE_BASE,
+ "(objectclass=krbRealmContainer)",
+ ("krbmkey", "cn"))
+ res = conn.result(msgid)
+ conn.unbind()
+ krbmkey = res[1][0][1]['krbmkey'][0]
+ except Exception, e:
+ print "Could not connect to the LDAP server, unable to fix server"
+ print "("+type(e)+")("+dir(e)+")"
+ raise e
+
+ krbMKey = pyasn1.codec.ber.decoder.decode(krbmkey)
+ keytype = int(krbMKey[0][1][0])
+ keydata = str(krbMKey[0][1][1])
+
+ format = '=hi%ss' % len(keydata)
+ s = struct.pack(format, keytype, len(keydata), keydata)
+ try:
+ fd = open("/var/kerberos/krb5kdc/.k5."+realm, "w")
+ fd.write(s)
+ fd.close()
+ except os.error, e:
+ print "failed to write stash file"
+ raise e
+
+ #restart KDC so that it can reload the new Master Key
+ os.system("/etc/init.d/krb5kdc restart")
+
+KRBMKEY_DENY_ACI = """
+(targetattr = "krbMKey")(version 3.0; acl "No external access"; deny (all) userdn != "ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
+"""
+
+def fix_main(password, realm, suffix):
+
+ #Run the change master key tool
+ print "Changing Kerberos master key"
+ try:
+ ret = change_mkey(password, True)
+ except SystemExit:
+ ret = 1
+ pass
+ except Exception, e:
+ ret = 1
+ print "%s" % str(e)
+
+ try:
+ msg = change_mkey_cleanup(password)
+ if msg:
+ print msg
+ except Exception, e:
+ print "Failed to clean up the temporary location for the dump files and generate and encrypted archive with error:"
+ print e
+ print "Please securely archive/encrypt "+basedir
+
+ if ret is not 0:
+ sys.exit(ret)
+
+ #Finally upload new master key
+
+ #get the Master Key from the stash file
+ try:
+ stash = open("/var/kerberos/krb5kdc/.k5."+realm, "r")
+ keytype = struct.unpack('h', stash.read(2))[0]
+ keylen = struct.unpack('i', stash.read(4))[0]
+ keydata = stash.read(keylen)
+ except os.error:
+ print "Failed to retrieve Master Key from Stash file: %s"
+ raise e
+ #encode it in the asn.1 attribute
+ MasterKey = univ.Sequence()
+ MasterKey.setComponentByPosition(0, univ.Integer(keytype))
+ MasterKey.setComponentByPosition(1, univ.OctetString(keydata))
+ krbMKey = univ.Sequence()
+ krbMKey.setComponentByPosition(0, univ.Integer(0)) #we have no kvno
+ krbMKey.setComponentByPosition(1, MasterKey)
+ asn1key = pyasn1.codec.ber.encoder.encode(krbMKey)
+
+ dn = "cn=%s,cn=kerberos,%s" % (realm, suffix)
+ sub_dict = dict(REALM=realm, SUFFIX=suffix)
+ #protect the master key by adding an appropriate deny rule along with the key
+ mod = [(ldap.MOD_ADD, 'aci', ipa.ipautil.template_str(KRBMKEY_DENY_ACI, sub_dict)),
+ (ldap.MOD_REPLACE, 'krbMKey', str(asn1key))]
+
+ conn = ldapobject.SimpleLDAPObject("ldap://127.0.0.1/")
+ conn.simple_bind("cn=Directory Manager", password)
+ conn.modify_s(dn, mod)
+ conn.unbind()
+
+ print "\n"
+ print "This server is now correctly configured and the master-key has been changed and secured."
+ print "Please now run this tool with the --fix-replica option on all your other replicas."
+ print "Until you fix the replicas their KDCs will not work."
+
+def main():
+
+ options, args = parse_options()
+
+ if options.fix or options.fix_replica:
+ password = getpass.getpass("Directory Manager password: ")
+
+ krbctx = krbV.default_context()
+ realm = krbctx.default_realm
+ suffix = ipa.ipautil.realm_to_suffix(realm)
+
+ try:
+ ret = check_vuln(realm, suffix)
+ except:
+ sys.exit(1)
+
+ if options.fix_replica:
+ if ret is 1:
+ print "Your system is still vulnerable"
+ print "If you have already run this tool with --fix on a master then make sure your replication is working correctly, before runnig --fix-replica"
+ sys.exit(1)
+ try:
+ fix_replica(password, realm, suffix)
+ except Exception, e:
+ print "Unexpected error ("+str(e)+")"
+ sys.exit(1)
+ sys.exit(0)
+
+ if options.check:
+ sys.exit(0)
+
+ if options.fix:
+ if ret is 1:
+ try:
+ ret = fix_main(password, realm, suffix)
+ except Exception, e:
+ print "Unexpected error ("+str(e)+")"
+ sys.exit(1)
+ sys.exit(ret)
+
+try:
+ if __name__ == "__main__":
+ sys.exit(main())
+except SystemExit, e:
+ sys.exit(e)
+except KeyboardInterrupt, e:
+ sys.exit(1)
diff --git a/install/tools/ipa-ldap-updater b/install/tools/ipa-ldap-updater
new file mode 100755
index 00000000..28fb1a17
--- /dev/null
+++ b/install/tools/ipa-ldap-updater
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+# Authors: Rob Crittenden <rcritten@redhat.com>
+#
+# Copyright (C) 2008 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; version 2 only
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+# Documentation can be found at http://freeipa.org/page/LdapUpdate
+
+# TODO
+# save undo files?
+
+import sys
+try:
+ from optparse import OptionParser
+ from ipaserver import ipaldap
+ from ipa import entity, ipaerror, ipautil, config
+ from ipaserver import installutils
+ from ipaserver.ldapupdate import LDAPUpdate, BadSyntax, UPDATES_DIR
+ import ldap
+ import logging
+ import re
+ import krbV
+ import platform
+ import shlex
+ import time
+ import random
+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)
+
+def parse_options():
+ usage = "%prog [options] input_file(s)\n"
+ usage += "%prog [options]\n"
+ parser = OptionParser(usage=usage, formatter=config.IPAFormatter())
+
+ parser.add_option("-d", "--debug", action="store_true", dest="debug",
+ help="Display debugging information about the update(s)")
+ parser.add_option("-t", "--test", action="store_true", dest="test",
+ help="Run through the update without changing anything")
+ parser.add_option("-y", dest="password",
+ help="File containing the Directory Manager password")
+
+ config.add_standard_options(parser)
+ options, args = parser.parse_args()
+
+ config.init_config(options)
+
+ return options, args
+
+def get_dirman_password():
+ """Prompt the user for the Directory Manager password and verify its
+ correctness.
+ """
+ password = installutils.read_password("Directory Manager", confirm=False, validate=False)
+
+ return password
+
+def main():
+ loglevel = logging.INFO
+
+ options, args = parse_options()
+ if options.debug:
+ loglevel = logging.DEBUG
+
+ logging.basicConfig(level=loglevel,
+ format='%(levelname)s %(message)s')
+
+ dirman_password = ""
+ if options.password:
+ pw = ipautil.template_file(options.password, [])
+ dirman_password = pw.strip()
+ else:
+ dirman_password = get_dirman_password()
+
+ ld = LDAPUpdate(dm_password=dirman_password, sub_dict={}, live_run=not options.test)
+
+ files=[]
+ if len(args) < 1:
+ files = ld.get_all_files(UPDATES_DIR)
+ else:
+ files = args
+
+ modified = ld.update(files)
+
+ if modified and options.test:
+ return 2
+ else:
+ return 0
+
+try:
+ if __name__ == "__main__":
+ sys.exit(main())
+except BadSyntax, e:
+ print "There is a syntax error in this update file:"
+ print " %s" % e
+ sys.exit(1)
+except RuntimeError, e:
+ print "%s" % e
+ sys.exit(1)
+except SystemExit, e:
+ sys.exit(e)
+except KeyboardInterrupt, e:
+ sys.exit(1)
+except config.IPAConfigError, e:
+ print "An IPA server to update cannot be found. Has one been configured yet?"
+ print "The error was: %s" % e
+ sys.exit(1)
diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
new file mode 100644
index 00000000..c2704be0
--- /dev/null
+++ b/install/tools/ipa-replica-install
@@ -0,0 +1,312 @@
+#! /usr/bin/python -E
+# Authors: 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; version 2 only
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+import sys
+
+import tempfile, os, pwd, traceback, logging, shutil
+from ConfigParser import SafeConfigParser
+import ldap
+
+from ipa import ipautil
+
+from ipaserver import dsinstance, replication, installutils, krbinstance, service
+from ipaserver import httpinstance, ntpinstance, certs, ipaldap
+from ipa import version
+
+CACERT="/usr/share/ipa/html/ca.crt"
+
+class ReplicaConfig:
+ def __init__(self):
+ self.realm_name = ""
+ self.domain_name = ""
+ self.master_host_name = ""
+ self.dirman_password = ""
+ self.ds_user = ""
+ self.host_name = ""
+ self.repl_password = ""
+ self.dir = ""
+
+def parse_options():
+ from optparse import OptionParser
+ parser = OptionParser(version=version.VERSION)
+ parser.add_option("-N", "--no-ntp", dest="conf_ntp", action="store_false",
+ help="do not configure ntp", default=True)
+ parser.add_option("-d", "--debug", dest="debug", action="store_true",
+ default=False, help="gather extra debugging information")
+ parser.add_option("-p", "--password", dest="password",
+ help="Directory Manager (existing master) password")
+
+ options, args = parser.parse_args()
+
+ if len(args) != 1:
+ parser.error("you must provide a file generated by ipa-replica-prepare")
+
+ return options, args[0]
+
+def get_dirman_password():
+ return installutils.read_password("Directory Manager (existing master)", confirm=False, validate=False)
+
+def expand_info(filename, password):
+ top_dir = tempfile.mkdtemp("ipa")
+ tarfile = top_dir+"/files.tar"
+ dir = top_dir + "/realm_info"
+ ipautil.decrypt_file(filename, tarfile, password, top_dir)
+ ipautil.run(["tar", "xf", tarfile, "-C", top_dir])
+ os.remove(tarfile)
+
+ return top_dir, dir
+
+def read_info(dir, rconfig):
+ filename = dir + "/realm_info"
+ fd = open(filename)
+ config = SafeConfigParser()
+ config.readfp(fd)
+
+ rconfig.realm_name = config.get("realm", "realm_name")
+ rconfig.master_host_name = config.get("realm", "master_host_name")
+ rconfig.ds_user = config.get("realm", "ds_user")
+ rconfig.domain_name = config.get("realm", "domain_name")
+ rconfig.host_name = config.get("realm", "destination_host")
+
+def get_host_name():
+ hostname = installutils.get_fqdn()
+ try:
+ installutils.verify_fqdn(hostname)
+ except RuntimeError, e:
+ logging.error(str(e))
+ sys.exit(1)
+
+ return hostname
+
+def set_owner(config, dir):
+ pw = pwd.getpwnam(config.ds_user)
+ os.chown(dir, pw.pw_uid, pw.pw_gid)
+
+def install_ds(config):
+ dsinstance.check_existing_installation()
+ dsinstance.check_ports()
+
+ # if we have a pkcs12 file, create the cert db from
+ # that. Otherwise the ds setup will create the CA
+ # cert
+ pkcs12_info = None
+ if ipautil.file_exists(config.dir + "/dscert.p12"):
+ pkcs12_info = (config.dir + "/dscert.p12",
+ config.dir + "/dirsrv_pin.txt")
+
+ ds = dsinstance.DsInstance()
+ ds.create_instance(config.ds_user, config.realm_name, config.host_name, config.domain_name, config.dirman_password, pkcs12_info)
+
+ return ds
+
+def install_krb(config):
+ krb = krbinstance.KrbInstance()
+ ldappwd_filename = config.dir + "/ldappwd"
+ kpasswd_filename = config.dir + "/kpasswd.keytab"
+ krb.create_replica(config.ds_user, config.realm_name, config.host_name,
+ config.domain_name, config.dirman_password,
+ ldappwd_filename, kpasswd_filename)
+
+def install_ca_cert(config):
+ if ipautil.file_exists(config.dir + "/ca.crt"):
+ try:
+ shutil.copy(config.dir + "/ca.crt", CACERT)
+ os.chmod(CACERT, 0444)
+ except Exception, e:
+ print "error copying files: " + str(e)
+ sys.exit(1)
+
+def install_http(config):
+ # if we have a pkcs12 file, create the cert db from
+ # that. Otherwise the ds setup will create the CA
+ # cert
+ pkcs12_info = None
+ if ipautil.file_exists(config.dir + "/httpcert.p12"):
+ pkcs12_info = (config.dir + "/httpcert.p12",
+ config.dir + "/http_pin.txt")
+
+ http = httpinstance.HTTPInstance()
+ http.create_instance(config.realm_name, config.host_name, config.domain_name, False, pkcs12_info)
+
+ # Now copy the autoconfiguration files
+ if ipautil.file_exists(config.dir + "/preferences.html"):
+ try:
+ shutil.copy(config.dir + "/preferences.html", "/usr/share/ipa/html/preferences.html")
+ shutil.copy(config.dir + "/configure.jar", "/usr/share/ipa/html/configure.jar")
+ except Exception, e:
+ print "error copying files: " + str(e)
+ sys.exit(1)
+
+def check_dirsrv():
+ serverids = dsinstance.check_existing_installation()
+ if serverids:
+ print ""
+ print "An existing Directory Server has been detected."
+ if not ipautil.user_input("Do you wish to remove it and create a new one?", False):
+ print ""
+ print "Only a single Directory Server instance is allowed on an IPA"
+ print "server, the one used by IPA itself."
+ sys.exit(1)
+
+ try:
+ service.stop("dirsrv")
+ except:
+ pass
+
+ for serverid in serverids:
+ dsinstance.erase_ds_instance_data(serverid)
+
+ (ds_unsecure, ds_secure) = dsinstance.check_ports()
+ if not ds_unsecure or not ds_secure:
+ print "IPA requires ports 389 and 636 for the Directory Server."
+ print "These are currently in use:"
+ if not ds_unsecure:
+ print "\t389"
+ if not ds_secure:
+ print "\t636"
+ sys.exit(1)
+
+def main():
+ options, filename = parse_options()
+ installutils.standard_logging_setup("/var/log/ipareplica-install.log", options.debug)
+
+ if not ipautil.file_exists(filename):
+ sys.exit("Replica file %s does not exist" % filename)
+
+ check_dirsrv()
+
+ # get the directory manager password
+ dirman_password = options.password
+ if not dirman_password:
+ try:
+ dirman_password = get_dirman_password()
+ except KeyboardInterrupt:
+ sys.exit(0)
+
+ try:
+ top_dir, dir = expand_info(filename, dirman_password)
+ except Exception, e:
+ print "ERROR: Failed to decrypt or open the replica file."
+ print "Verify you entered the correct Directory Manager password."
+ sys.exit(1)
+
+ config = ReplicaConfig()
+ read_info(dir, config)
+ config.dirman_password = dirman_password
+ host = get_host_name()
+ if config.host_name != host:
+ try:
+ print "This replica was created for '%s' but this machine is named '%s'" % (config.host_name, host)
+ if not ipautil.user_input("This may cause problems. Continue?", True):
+ sys.exit(0)
+ config.host_name = host
+ print ""
+ except KeyboardInterrupt:
+ sys.exit(0)
+ config.repl_password = ipautil.ipa_generate_password()
+ config.dir = dir
+
+ # Try out the password
+ try:
+ conn = ipaldap.IPAdmin(config.master_host_name)
+ conn.do_simple_bind(bindpw=config.dirman_password)
+ conn.unbind()
+ except ldap.CONNECT_ERROR, e:
+ sys.exit("\nUnable to connect to LDAP server %s" % config.master_host_name)
+ except ldap.SERVER_DOWN, e:
+ sys.exit("\nUnable to connect to LDAP server %s" % config.master_host_name)
+ except ldap.INVALID_CREDENTIALS, e :
+ sys.exit("\nThe password provided is incorrect for LDAP server %s" % config.master_host_name)
+
+ # Configure ntpd
+ if options.conf_ntp:
+ ntp = ntpinstance.NTPInstance()
+ ntp.create_instance()
+
+ # Configure dirsrv
+ ds = install_ds(config)
+
+ # Install CA cert so that we can do SSL connections with ldap
+ install_ca_cert(config)
+
+ try:
+ repl = replication.ReplicationManager(config.host_name, config.dirman_password)
+ ret = repl.setup_replication(config.master_host_name, config.realm_name)
+ except Exception, e:
+ logging.debug("Connection error: %s" % e)
+ raise RuntimeError("Unable to connect to LDAP server %s." % config.host_name)
+ if ret != 0:
+ raise RuntimeError("Failed to start replication")
+
+ install_krb(config)
+ install_http(config)
+
+ # Create the config file
+ fd = open("/etc/ipa/ipa.conf", "w")
+ fd.write("[defaults]\n")
+ fd.write("server=" + config.host_name + "\n")
+ fd.write("realm=" + config.realm_name + "\n")
+ fd.write("domain=" + config.domain_name + "\n")
+ fd.close()
+
+ # Create a Web Gui instance
+ webgui = httpinstance.WebGuiInstance()
+ webgui.create_instance()
+
+ # Apply any LDAP updates. Needs to be done after the replica is synced-up
+ service.print_msg("Applying LDAP updates")
+ ds.apply_updates()
+
+ service.restart("dirsrv")
+ service.restart("krb5kdc")
+
+ # Call client install script
+ try:
+ ipautil.run(["/usr/sbin/ipa-client-install", "--on-master", "--unattended", "--domain", config.domain_name, "--server", config.host_name, "--realm", config.realm_name])
+ except Exception, e:
+ print "Configuration of client side components failed!"
+ print "ipa-client-install returned: " + str(e)
+ raise RuntimeError("Failed to configure the client")
+
+ ds.init_memberof()
+
+try:
+ if not os.geteuid()==0:
+ sys.exit("\nYou must be root to run this script.\n")
+
+ main()
+ sys.exit(0)
+except SystemExit, e:
+ sys.exit(e)
+except Exception, e:
+ print "creation of replica failed: %s" % str(e)
+ message = str(e)
+ for str in traceback.format_tb(sys.exc_info()[2]):
+ message = message + "\n" + str
+ logging.debug(message)
+except KeyboardInterrupt:
+ print "Installation cancelled."
+
+print ""
+print "Your system may be partly configured."
+print "Run /usr/sbin/ipa-server-install --uninstall to clean up."
+
+# the only way to get here is on error or ^C
+sys.exit(1)
diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
new file mode 100755
index 00000000..db8c32d5
--- /dev/null
+++ b/install/tools/ipa-replica-manage
@@ -0,0 +1,218 @@
+#! /usr/bin/python -E
+# Authors: 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; version 2 only
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+import sys
+
+import getpass, ldap, re, krbV
+import traceback, logging
+
+from ipa import ipautil
+from ipaserver import replication, ipaldap, dsinstance, installutils
+from ipa import version
+
+def parse_options():
+ from optparse import OptionParser
+
+ parser = OptionParser(version=version.VERSION)
+ parser.add_option("-H", "--host", dest="host", help="starting host")
+ parser.add_option("-p", "--password", dest="dirman_passwd", help="Directory Manager password")
+ parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False,
+ help="provide additional information")
+ parser.add_option("--port", type="int", dest="port",
+ help="port number of other server")
+ parser.add_option("--binddn", dest="binddn",
+ help="Bind DN to use with remote server")
+ parser.add_option("--bindpw", dest="bindpw",
+ help="Password for Bind DN to use with remote server")
+ parser.add_option("--winsync", dest="winsync", action="store_true", default=False,
+ help="This is a Windows Sync Agreement")
+ parser.add_option("--cacert", dest="cacert",
+ help="Full path and filename of CA certificate to use with TLS/SSL to the remote server")
+ parser.add_option("--win-subtree", dest="win_subtree",
+ help="DN of Windows subtree containing the users you want to sync (default cn=Users,<domain suffix)")
+ parser.add_option("--passsync", dest="passsync",
+ help="Password for the Windows PassSync user")
+
+ options, args = parser.parse_args()
+
+ if not len(args) or not ("list" in args[0] or "add" in args[0] or "del" in args[0] or "init" in args[0] or "synch" in args[0]):
+ parser.error("must provide a command [list | add | del | init | synch]")
+
+ # set log level
+ if options.verbose:
+ # if verbose, output events at INFO level if not already
+ mylogger = logging.getLogger()
+ if mylogger.getEffectiveLevel() > logging.INFO:
+ mylogger.setLevel(logging.INFO)
+ # else user has already configured logging externally lower
+ return options, args
+
+def get_realm_name():
+ c = krbV.default_context()
+ return c.default_realm
+
+def get_suffix():
+ suffix = ipaldap.IPAdmin.normalizeDN(dsinstance.realm_to_suffix(get_realm_name()))
+ return suffix
+
+def get_host_name():
+ hostname = installutils.get_fqdn()
+ try:
+ installutils.verify_fqdn(hostname)
+ except RuntimeError, e:
+ logging.error(str(e))
+ sys.exit(1)
+
+ return hostname
+
+def list_masters(replman, verbose):
+ dns = replman.find_replication_dns(replman.conn)
+
+ for dn in dns:
+ entry = replman.conn.search_s(dn, ldap.SCOPE_SUBTREE)[0]
+ print entry.getValue('nsds5replicahost')
+
+ if verbose:
+ print " last init status: %s" % entry.nsds5replicalastinitstatus
+ print " last init ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastinitend))
+ print " last update status: %s" % entry.nsds5replicalastupdatestatus
+ print " last update ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastupdateend))
+
+def del_master(replman, hostname):
+ try:
+ t = replman.get_agreement_type(hostname)
+ except ldap.NO_SUCH_OBJECT:
+ print "No replication agreement found for %s" % hostname
+
+ if t == replication.IPA_REPLICA:
+ dirman_passwd = getpass.getpass("Directory Manager password (%s): " % hostname)
+ other_replman = replication.ReplicationManager(hostname, dirman_passwd)
+ other_replman.suffix = get_suffix()
+ other_replman.delete_agreement(replman.conn.host)
+
+ replman.delete_agreement(hostname)
+
+def add_master(replman, hostname, options):
+ other_args = {}
+ if options.port:
+ other_args['port'] = options.port
+ if options.binddn:
+ other_args['binddn'] = options.binddn
+ if options.bindpw:
+ other_args['bindpw'] = options.bindpw
+ if options.cacert:
+ other_args['cacert'] = options.cacert
+ if options.win_subtree:
+ other_args['win_subtree'] = options.win_subtree
+ if options.passsync:
+ other_args['passsync'] = options.passsync
+ if options.winsync:
+ other_args['winsync'] = True
+ if not options.binddn or not options.bindpw or not options.cacert or not options.passsync:
+ logging.error("The arguments --binddn, --bindpw, --passsync and --cacert are required to create a winsync agreement")
+ sys.exit(1)
+ if options.cacert:
+ # have to install the given CA cert before doing anything else
+ ds = dsinstance.DsInstance(realm_name = get_realm_name(),
+ dm_password = replman.dirman_passwd)
+ if not ds.add_ca_cert(options.cacert):
+ logging.error("Could not load the required CA certificate file [%s]" %
+ options.cacert)
+ sys.exit(1)
+ else:
+ logging.info("Added CA certificate %s to certificate database for %s" %
+ (options.cacert, replman.hostname))
+ # have to reconnect replman connection since the directory server was restarted
+ replman = replication.ReplicationManager(replman.hostname, replman.dirman_passwd)
+ logging.info("Restarted directory server " + replman.hostname)
+ replman.setup_replication(hostname, get_realm_name(), **other_args)
+ logging.info("Added agreement for other host " + hostname)
+
+def init_master(replman, dirman_passwd, hostname):
+ filter = "(&(nsDS5ReplicaHost=%s)(|(objectclass=nsDSWindowsReplicationAgreement)(objectclass=nsds5ReplicationAgreement)))" % hostname
+ entry = replman.conn.search_s("cn=config", ldap.SCOPE_SUBTREE, filter)
+ if len(entry) == 0:
+ logging.error("Unable to find replication agreement for %s" % hostname)
+ sys.exit(1)
+ if len(entry) > 1:
+ logging.error("Found multiple agreements for %s. Only initializing the first one returned: %s" % (hostname, entry[0].dn))
+ replman.initialize_replication(entry[0].dn, replman.conn)
+ ds = dsinstance.DsInstance(realm_name = get_realm_name(), dm_password = dirman_passwd)
+ ds.init_memberof()
+
+def synch_master(replman, hostname):
+ filter = "(&(nsDS5ReplicaHost=%s)(|(objectclass=nsDSWindowsReplicationAgreement)(objectclass=nsds5ReplicationAgreement)))" % hostname
+ entry = replman.conn.search_s("cn=config", ldap.SCOPE_SUBTREE, filter)
+ if len(entry) == 0:
+ logging.error("Unable to find replication agreement for %s" % hostname)
+ sys.exit(1)
+ if len(entry) > 1:
+ logging.error("Found multiple agreements for %s. Only initializing the first one returned: %s" % (hostname, entry[0].dn))
+ replman.force_synch(entry[0].dn, entry[0].nsds5replicaupdateschedule, replman.conn)
+
+def main():
+ options, args = parse_options()
+
+ if options.dirman_passwd:
+ dirman_passwd = options.dirman_passwd
+ else:
+ dirman_passwd = getpass.getpass("Directory Manager password: ")
+
+ if options.host:
+ host = options.host
+ else:
+ host = get_host_name()
+
+ r = replication.ReplicationManager(host, dirman_passwd)
+ r.suffix = get_suffix()
+
+ if args[0] == "list":
+ list_masters(r, options.verbose)
+ elif args[0] == "del":
+ if len(args) != 2:
+ print "must provide hostname of master to delete"
+ sys.exit(1)
+ del_master(r, args[1])
+ elif args[0] == "add":
+ if len(args) != 2:
+ print "must provide hostname of master to add"
+ sys.exit(1)
+ add_master(r, args[1], options)
+ elif args[0] == "init":
+ if len(args) != 2:
+ print "hostname of master to initialize is required."
+ sys.exit(1)
+ init_master(r, dirman_passwd, args[1])
+ elif args[0] == "synch":
+ if len(args) != 2:
+ print "must provide hostname of supplier to synchronize with"
+ sys.exit(1)
+ synch_master(r, args[1])
+
+try:
+ main()
+except KeyboardInterrupt:
+ sys.exit(1)
+except SystemExit, e:
+ sys.exit(e)
+except ldap.INVALID_CREDENTIALS:
+ print "Invalid password"
+ sys.exit(1)
+except Exception, e:
+ print "unexpected error: %s" % str(e)
diff --git a/install/tools/ipa-replica-prepare b/install/tools/ipa-replica-prepare
new file mode 100644
index 00000000..eb962b4c
--- /dev/null
+++ b/install/tools/ipa-replica-prepare
@@ -0,0 +1,294 @@
+#! /usr/bin/python -E
+# Authors: 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; version 2 only
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+import sys
+
+import logging, tempfile, shutil, os, pwd
+import traceback
+from ConfigParser import SafeConfigParser
+import krbV
+from optparse import OptionParser
+
+import ipa.config
+from ipa import ipautil
+from ipaserver import dsinstance, installutils, certs, ipaldap
+from ipa import version
+import ldap
+
+def parse_options():
+ usage = "%prog [options] FQDN (e.g. replica.example.com)"
+ parser = OptionParser(usage=usage, version=version.VERSION)
+
+ parser.add_option("--dirsrv_pkcs12", dest="dirsrv_pkcs12",
+ help="install certificate for the directory server")
+ parser.add_option("--http_pkcs12", dest="http_pkcs12",
+ help="install certificate for the http server")
+ parser.add_option("--dirsrv_pin", dest="dirsrv_pin",
+ help="PIN for the Directory Server PKCS#12 file")
+ parser.add_option("--http_pin", dest="http_pin",
+ help="PIN for the Apache Server PKCS#12 file")
+ parser.add_option("-p", "--password", dest="password",
+ help="Directory Manager (existing master) password")
+
+ ipa.config.add_standard_options(parser)
+ options, args = parser.parse_args()
+
+ # If any of the PKCS#12 options are selected, all are required. Create a
+ # list of the options and count it to enforce that all are required without
+ # having a huge set of it blocks.
+ pkcs12 = [options.dirsrv_pkcs12, options.http_pkcs12, options.dirsrv_pin, options.http_pin]
+ cnt = pkcs12.count(None)
+ if cnt > 0 and cnt < 4:
+ parser.error("error: All PKCS#12 options are required if any are used.")
+
+ if len(args) != 1:
+ parser.error("must provide the fully-qualified name of the replica")
+
+ ipa.config.init_config(options)
+
+ return options, args
+
+def get_host_name():
+ hostname = installutils.get_fqdn()
+ try:
+ installutils.verify_fqdn(hostname)
+ except RuntimeError, e:
+ logging.error(str(e))
+ sys.exit(1)
+
+ return hostname
+
+def get_realm_name():
+ try:
+ c = krbV.default_context()
+ return c.default_realm
+ except Exception, e:
+ return None
+
+def get_domain_name():
+ try:
+ ipa.config.init_config()
+ domain_name = ipa.config.config.get_domain()
+ except Exception, e:
+ return None
+
+ return domain_name
+
+def check_ipa_configuration(realm_name):
+ config_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name))
+ if not ipautil.dir_exists(config_dir):
+ logging.error("could not find directory instance: %s" % config_dir)
+ sys.exit(1)
+
+def export_certdb(realm_name, ds_dir, dir, passwd_fname, fname, subject):
+ """realm is the kerberos realm for the IPA server.
+ ds_dir is the location of the master DS we are creating a replica for.
+ dir is the location of the files for the replica we are creating.
+ passwd_fname is the file containing the PKCS#12 password
+ fname is the filename of the PKCS#12 file for this cert (minus the .p12).
+ subject is the subject of the certificate we are creating
+ """
+ try:
+ ds_ca = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name)))
+ ca = certs.CertDB(dir)
+ ca.create_from_cacert(ds_ca.cacert_fname)
+ ca.create_server_cert("Server-Cert", subject, ds_ca)
+ except Exception, e:
+ raise e
+
+ pkcs12_fname = dir + "/" + fname + ".p12"
+
+ try:
+ ca.export_pkcs12(pkcs12_fname, passwd_fname, "Server-Cert")
+ except ipautil.CalledProcessError, e:
+ print "error exporting CA certificate: " + str(e)
+ try:
+ os.unlink(pkcs12_fname)
+ os.unlink(passwd_fname)
+ except:
+ pass
+
+ os.unlink(dir + "/cert8.db")
+ os.unlink(dir + "/key3.db")
+ os.unlink(dir + "/secmod.db")
+ os.unlink(dir + "/noise.txt")
+ if ipautil.file_exists(passwd_fname + ".orig"):
+ os.unlink(passwd_fname + ".orig")
+
+def get_ds_user(ds_dir):
+ uid = os.stat(ds_dir).st_uid
+ user = pwd.getpwuid(uid)[0]
+
+ return user
+
+def save_config(dir, realm_name, host_name, ds_user, domain_name, dest_host):
+ config = SafeConfigParser()
+ config.add_section("realm")
+ config.set("realm", "realm_name", realm_name)
+ config.set("realm", "master_host_name", host_name)
+ config.set("realm", "ds_user", ds_user)
+ config.set("realm", "domain_name", domain_name)
+ config.set("realm", "destination_host", dest_host)
+ fd = open(dir + "/realm_info", "w")
+ config.write(fd)
+
+def copy_files(realm_name, dir):
+ config_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name))
+
+ try:
+ shutil.copy("/var/kerberos/krb5kdc/ldappwd", dir + "/ldappwd")
+ shutil.copy("/var/kerberos/krb5kdc/kpasswd.keytab", dir + "/kpasswd.keytab")
+ shutil.copy("/usr/share/ipa/html/ca.crt", dir + "/ca.crt")
+ if ipautil.file_exists("/usr/share/ipa/html/preferences.html"):
+ shutil.copy("/usr/share/ipa/html/preferences.html", dir + "/preferences.html")
+ shutil.copy("/usr/share/ipa/html/configure.jar", dir + "/configure.jar")
+ except Exception, e:
+ print "error copying files: " + str(e)
+ sys.exit(1)
+
+def get_dirman_password():
+ return installutils.read_password("Directory Manager (existing master)", confirm=False, validate=False)
+
+def main():
+ options, args = parse_options()
+
+ replica_fqdn = args[0]
+
+ if not ipautil.file_exists(certs.CA_SERIALNO) and not options.dirsrv_pin:
+ sys.exit("The replica must be created on the primary IPA server.\nIf you installed IPA with your own certificates using PKCS#12 files you must provide PKCS#12 files for any replicas you create as well.")
+
+ print "Determining current realm name"
+ realm_name = get_realm_name()
+ if realm_name is None:
+ print "Unable to determine default realm"
+ sys.exit(1)
+
+ check_ipa_configuration(realm_name)
+
+ print "Getting domain name from LDAP"
+ domain_name = get_domain_name()
+ if domain_name is None:
+ print "Unable to determine LDAP default domain"
+ sys.exit(1)
+
+ host_name = get_host_name()
+ if host_name == replica_fqdn:
+ print "You can't create a replica on itself"
+ sys.exit(1)
+ ds_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name))
+ ds_user = get_ds_user(ds_dir)
+
+ # get the directory manager password
+ dirman_password = options.password
+ if not options.password:
+ try:
+ dirman_password = get_dirman_password()
+ except KeyboardInterrupt:
+ sys.exit(0)
+
+ # Try out the password
+ try:
+ conn = ipaldap.IPAdmin(host_name)
+ conn.do_simple_bind(bindpw=dirman_password)
+ conn.unbind()
+ except ldap.CONNECT_ERROR, e:
+ sys.exit("\nUnable to connect to LDAP server %s" % host_name)
+ except ldap.SERVER_DOWN, e:
+ sys.exit("\nUnable to connect to LDAP server %s" % host_name)
+ except ldap.INVALID_CREDENTIALS, e :
+ sys.exit("\nThe password provided is incorrect for LDAP server %s" % host_name)
+
+ print "Preparing replica for %s from %s" % (replica_fqdn, host_name)
+
+ top_dir = tempfile.mkdtemp("ipa")
+ dir = top_dir + "/realm_info"
+ os.mkdir(dir, 0700)
+
+ if options.dirsrv_pin:
+ passwd = options.dirsrv_pin
+ else:
+ passwd = ""
+
+ passwd_fname = dir + "/dirsrv_pin.txt"
+ fd = open(passwd_fname, "w")
+ fd.write("%s\n" % passwd)
+ fd.close()
+
+ if options.dirsrv_pkcs12:
+ print "Copying SSL certificate for the Directory Server from %s" % options.dirsrv_pkcs12
+ try:
+ shutil.copy(options.dirsrv_pkcs12, dir + "/dscert.p12")
+ except IOError, e:
+ print "Copy failed %s" % e
+ sys.exit(1)
+ else:
+ print "Creating SSL certificate for the Directory Server"
+ export_certdb(realm_name, ds_dir, dir, passwd_fname, "dscert", "cn=%s,ou=Fedora Directory Server" % replica_fqdn)
+
+ if options.http_pin:
+ passwd = options.http_pin
+ else:
+ passwd = ""
+
+ passwd_fname = dir + "/http_pin.txt"
+ fd = open(passwd_fname, "w")
+ fd.write("%s\n" % passwd)
+ fd.close()
+
+ if options.http_pkcs12:
+ print "Copying SSL certificate for the Web Server from %s" % options.http_pkcs12
+ try:
+ shutil.copy(options.http_pkcs12, dir + "/httpcert.p12")
+ except IOError, e:
+ print "Copy failed %s" % e
+ sys.exit(1)
+ else:
+ print "Creating SSL certificate for the Web Server"
+ export_certdb(realm_name, ds_dir, dir, passwd_fname, "httpcert", "cn=%s,ou=Apache Web Server" % replica_fqdn)
+ print "Copying additional files"
+ copy_files(realm_name, dir)
+ print "Finalizing configuration"
+ save_config(dir, realm_name, host_name, ds_user, domain_name, replica_fqdn)
+
+ replicafile = "/var/lib/ipa/replica-info-" + replica_fqdn
+ encfile = replicafile+".gpg"
+
+ print "Packaging replica information into %s" % encfile
+ ipautil.run(["/bin/tar", "cf", replicafile, "-C", top_dir, "realm_info"])
+ ipautil.encrypt_file(replicafile, encfile, dirman_password, top_dir);
+
+ os.remove(replicafile)
+ shutil.rmtree(dir)
+
+try:
+ if not os.geteuid()==0:
+ sys.exit("\nYou must be root to run this script.\n")
+
+ main()
+except SystemExit, e:
+ sys.exit(e)
+except Exception, e:
+ print "preparation of replica failed: %s" % str(e)
+ message = str(e)
+ for str in traceback.format_tb(sys.exc_info()[2]):
+ message = message + "\n" + str
+ logging.debug(message)
+ print message
+ sys.exit(1)
diff --git a/install/tools/ipa-server-certinstall b/install/tools/ipa-server-certinstall
new file mode 100644
index 00000000..a0d11856
--- /dev/null
+++ b/install/tools/ipa-server-certinstall
@@ -0,0 +1,157 @@
+#! /usr/bin/python -E
+# Authors: 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; version 2 only
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+import sys
+import os
+import pwd
+import tempfile
+
+import traceback
+
+import krbV, ldap, getpass
+
+from ipa.ipautil import user_input
+from ipaserver import certs, dsinstance, httpinstance, ipaldap, installutils
+
+def get_realm_name():
+ c = krbV.default_context()
+ return c.default_realm
+
+def parse_options():
+ from optparse import OptionParser
+ parser = OptionParser()
+
+ parser.add_option("-d", "--dirsrv", dest="dirsrv", action="store_true",
+ default=False, help="install certificate for the directory server")
+ parser.add_option("-w", "--http", dest="http", action="store_true",
+ default=False, help="install certificate for the http server")
+ parser.add_option("--dirsrv_pin", dest="dirsrv_pin",
+ help="The password of the Directory Server PKCS#12 file")
+ parser.add_option("--http_pin", dest="http_pin",
+ help="The password of the Apache Server PKCS#12 file")
+
+ options, args = parser.parse_args()
+
+ if not options.dirsrv and not options.http:
+ parser.error("you must specify dirsrv and/or http")
+ if ((options.dirsrv and not options.dirsrv_pin) or
+ (options.http and not options.http_pin)):
+ parser.error("you must provide the password for the PKCS#12 file")
+
+ if len(args) != 1:
+ parser.error("you must provide a pkcs12 filename")
+
+ return options, args[0]
+
+def set_ds_cert_name(cert_name, dm_password):
+ conn = ipaldap.IPAdmin("127.0.0.1")
+ conn.simple_bind_s("cn=directory manager", dm_password)
+
+ mod = [(ldap.MOD_REPLACE, "nsSSLPersonalitySSL", cert_name)]
+
+ conn.modify_s("cn=RSA,cn=encryption,cn=config", mod)
+
+ conn.unbind()
+
+def choose_server_cert(server_certs):
+ print "Please select the certificate to use:"
+ num = 1
+ for cert in server_certs:
+ print "%d. %s" % (num, cert[0])
+ num += 1
+
+ while 1:
+ num = user_input("Certificate number", 1)
+ print ""
+ if num < 1 or num > len(server_certs):
+ print "number out of range"
+ else:
+ break
+
+ return server_certs[num - 1]
+
+def import_cert(dirname, pkcs12_fname, pkcs12_passwd, db_password):
+ cdb = certs.CertDB(dirname)
+ cdb.create_passwd_file(db_password)
+ cdb.create_certdbs()
+ [pw_fd, pw_name] = tempfile.mkstemp()
+ os.write(pw_fd, pkcs12_passwd)
+ os.close(pw_fd)
+
+ try:
+ try:
+ cdb.import_pkcs12(pkcs12_fname, pw_name)
+ except RuntimeError, e:
+ print str(e)
+ sys.exit(1)
+ finally:
+ os.remove(pw_name)
+
+ server_certs = cdb.find_server_certs()
+ if len(server_certs) == 0:
+ print "could not find a suitable server cert in import"
+ sys.exit(1)
+ elif len(server_certs) == 1:
+ server_cert = server_certs[0]
+ else:
+ server_cert = choose_server_cert(server_certs)
+
+ cdb.trust_root_cert(server_cert[0])
+
+ return server_cert
+
+def main():
+ options, pkcs12_fname = parse_options()
+
+ try:
+ if options.dirsrv:
+ dm_password = getpass.getpass("Directory Manager password: ")
+ realm = get_realm_name()
+ dirname = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm))
+ fd = open(dirname + "/pwdfile.txt")
+ passwd = fd.read()
+ fd.close()
+
+ server_cert = import_cert(dirname, pkcs12_fname, options.dirsrv_pin, passwd)
+ set_ds_cert_name(server_cert[0], dm_password)
+
+ if options.http:
+ dirname = httpinstance.NSS_DIR
+ server_cert = import_cert(dirname, pkcs12_fname, options.http_pin, "")
+ installutils.set_directive(httpinstance.NSS_CONF, 'NSSNickname', server_cert[0])
+
+ # Fix the database permissions
+ os.chmod(dirname + "/cert8.db", 0640)
+ os.chmod(dirname + "/key3.db", 0640)
+ os.chmod(dirname + "/secmod.db", 0640)
+
+ pent = pwd.getpwnam("apache")
+ os.chown(dirname + "/cert8.db", 0, pent.pw_gid )
+ os.chown(dirname + "/key3.db", 0, pent.pw_gid )
+ os.chown(dirname + "/secmod.db", 0, pent.pw_gid )
+
+ except Exception, e:
+ print "an unexpected error occurred: %s" % str(e)
+ traceback.print_exc()
+ return 1
+
+ return 0
+
+sys.exit(main())
diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
new file mode 100644
index 00000000..c9d5c5bf
--- /dev/null
+++ b/install/tools/ipa-server-install
@@ -0,0 +1,622 @@
+#! /usr/bin/python -E
+# Authors: 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; version 2 only
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+
+# requires the following packages:
+# fedora-ds-base
+# openldap-clients
+# nss-tools
+
+import sys
+import os
+import socket
+import errno
+import logging
+import pwd
+import subprocess
+import signal
+import shutil
+import glob
+import traceback
+from optparse import OptionParser
+
+import ipaserver.dsinstance
+import ipaserver.krbinstance
+import ipaserver.bindinstance
+import ipaserver.httpinstance
+import ipaserver.ntpinstance
+
+from ipaserver import service
+from ipa import version
+from ipaserver.installutils import *
+
+from ipa import sysrestore
+from ipa.ipautil import *
+
+pw_name = None
+
+def parse_options():
+ parser = OptionParser(version=version.VERSION)
+ parser.add_option("-u", "--user", dest="ds_user",
+ help="ds user")
+ parser.add_option("-r", "--realm", dest="realm_name",
+ help="realm name")
+ parser.add_option("-n", "--domain", dest="domain_name",
+ help="domain name")
+ parser.add_option("-p", "--ds-password", dest="dm_password",
+ help="admin password")
+ parser.add_option("-P", "--master-password", dest="master_password",
+ help="kerberos master password (normally autogenerated)")
+ parser.add_option("-a", "--admin-password", dest="admin_password",
+ help="admin user kerberos password")
+ parser.add_option("-d", "--debug", dest="debug", action="store_true",
+ default=False, help="print debugging information")
+ parser.add_option("--hostname", dest="host_name", help="fully qualified name of server")
+ parser.add_option("--ip-address", dest="ip_address", help="Master Server IP Address")
+ parser.add_option("--setup-bind", dest="setup_bind", action="store_true",
+ default=False, help="configure bind with our zone file")
+ parser.add_option("-U", "--unattended", dest="unattended", action="store_true",
+ default=False, help="unattended installation never prompts the user")
+ parser.add_option("", "--uninstall", dest="uninstall", action="store_true",
+ default=False, help="uninstall an existing installation")
+ parser.add_option("-N", "--no-ntp", dest="conf_ntp", action="store_false",
+ help="do not configure ntp", default=True)
+ parser.add_option("--dirsrv_pkcs12", dest="dirsrv_pkcs12",
+ help="PKCS#12 file containing the Directory Server SSL certificate")
+ parser.add_option("--http_pkcs12", dest="http_pkcs12",
+ help="PKCS#12 file containing the Apache Server SSL certificate")
+ parser.add_option("--dirsrv_pin", dest="dirsrv_pin",
+ help="The password of the Directory Server PKCS#12 file")
+ parser.add_option("--http_pin", dest="http_pin",
+ help="The password of the Apache Server PKCS#12 file")
+ parser.add_option("--no-host-dns", dest="no_host_dns", action="store_true",
+ default=False,
+ help="Do not use DNS for hostname lookup during installation")
+
+ options, args = parser.parse_args()
+
+ if options.uninstall:
+ if (options.ds_user or options.realm_name or
+ options.dm_password or options.admin_password or
+ options.master_password):
+ parser.error("error: In uninstall mode, -u, r, -p and -P options are not allowed")
+ elif options.unattended:
+ if (not options.ds_user or not options.realm_name or
+ not options.dm_password or not options.admin_password):
+ parser.error("error: In unattended mode you need to provide at least -u, -r, -p and -a options")
+
+ # If any of the PKCS#12 options are selected, all are required. Create a
+ # list of the options and count it to enforce that all are required without
+ # having a huge set of it blocks.
+ pkcs12 = [options.dirsrv_pkcs12, options.http_pkcs12, options.dirsrv_pin, options.http_pin]
+ cnt = pkcs12.count(None)
+ if cnt > 0 and cnt < 4:
+ parser.error("error: All PKCS#12 options are required if any are used.")
+
+ return options
+
+def signal_handler(signum, frame):
+ global ds
+ print "\nCleaning up..."
+ if ds:
+ print "Removing configuration for %s instance" % ds.serverid
+ ds.stop()
+ if ds.serverid:
+ ipaserver.dsinstance.erase_ds_instance_data (ds.serverid)
+ sys.exit(1)
+
+def read_host_name(host_default,no_host_dns=False):
+ host_name = ""
+
+ print "Enter the fully qualified domain name of the computer"
+ print "on which you're setting up server software. Using the form"
+ print "<hostname>.<domainname>"
+ print "Example: master.example.com."
+ print ""
+ print ""
+ if host_default == "":
+ host_default = "master.example.com"
+ while True:
+ host_name = user_input("Server host name", host_default, allow_empty = False)
+ print ""
+ try:
+ verify_fqdn(host_name,no_host_dns)
+ except Exception, e:
+ raise e
+ else:
+ break
+ return host_name
+
+def resolve_host(host_name):
+ ip = ""
+ try:
+ ip = socket.gethostbyname(host_name)
+
+ if ip == "127.0.0.1" or ip == "::1":
+ print "The hostname resolves to the localhost address (127.0.0.1/::1)"
+ print "Please change your /etc/hosts file so that the hostname"
+ print "resolves to the ip address of your network interface."
+ print "The KDC service does not listen on localhost"
+ print ""
+ print "Please fix your /etc/hosts file and restart the setup program"
+ return None
+
+ except:
+ print "Unable to lookup the IP address of the provided host"
+ return ip
+
+def verify_ip_address(ip):
+ is_ok = True
+ try:
+ socket.inet_pton(socket.AF_INET, ip)
+ except:
+ try:
+ socket.inet_pton(socket.AF_INET6, ip)
+ except:
+ print "Unable to verify IP address"
+ is_ok = False
+ return is_ok
+
+def read_ip_address(host_name):
+ while True:
+ ip = user_input("Please provide the IP address to be used for this host name", allow_empty = False)
+
+ if ip == "127.0.0.1" or ip == "::1":
+ print "The IPA Server can't use localhost as a valid IP"
+ continue
+
+ if not verify_ip_address(ip):
+ continue
+
+ print "Adding ["+ip+" "+host_name+"] to your /etc/hosts file"
+ fstore.backup_file("/etc/hosts")
+ hosts_fd = open('/etc/hosts', 'r+')
+ hosts_fd.seek(0, 2)
+ hosts_fd.write(ip+'\t'+host_name+' '+host_name.split('.')[0]+'\n')
+ hosts_fd.close()
+
+ return ip
+
+def read_ds_user():
+ print "The server must run as a specific user in a specific group."
+ print "It is strongly recommended that this user should have no privileges"
+ print "on the computer (i.e. a non-root user). The setup procedure"
+ print "will give this user/group some permissions in specific paths/files"
+ print "to perform server-specific operations."
+ print ""
+
+ ds_user = ""
+ try:
+ pwd.getpwnam('dirsrv')
+
+ print "A user account named 'dirsrv' already exists. This is the user id"
+ print "that the Directory Server will run as."
+ print ""
+ if user_input("Do you want to use the existing 'dirsrv' account?", True):
+ ds_user = "dirsrv"
+ else:
+ print ""
+ ds_user = user_input_plain("Which account name do you want to use for the DS instance?", allow_empty = False, allow_spaces = False)
+ print ""
+ except KeyError:
+ ds_user = "dirsrv"
+
+ return ds_user
+
+def read_domain_name(domain_name, unattended):
+ print "The domain name has been calculated based on the host name."
+ print ""
+ if not unattended:
+ domain_name = user_input("Please confirm the domain name", domain_name)
+ print ""
+ return domain_name
+
+def read_realm_name(domain_name, unattended):
+ print "The kerberos protocol requires a Realm name to be defined."
+ print "This is typically the domain name converted to uppercase."
+ print ""
+
+ if unattended:
+ return domain_name.upper()
+ realm_name = user_input("Please provide a realm name", domain_name.upper())
+ upper_dom = realm_name.upper()
+ if upper_dom != realm_name:
+ print "An upper-case realm name is required."
+ if not user_input("Do you want to use " + upper_dom + " as realm name?", True):
+ print ""
+ print "An upper-case realm name is required. Unable to continue."
+ sys.exit(1)
+ else:
+ realm_name = upper_dom
+ print ""
+ return realm_name
+
+
+def read_dm_password():
+ print "Certain directory server operations require an administrative user."
+ print "This user is referred to as the Directory Manager and has full access"
+ print "to the Directory for system management tasks and will be added to the"
+ print "instance of directory server created for IPA."
+ print "The password must be at least 8 characters long."
+ print ""
+ #TODO: provide the option of generating a random password
+ dm_password = read_password("Directory Manager")
+ return dm_password
+
+def read_admin_password():
+ print "The IPA server requires an administrative user, named 'admin'."
+ print "This user is a regular system account used for IPA server administration."
+ print ""
+ #TODO: provide the option of generating a random password
+ admin_password = read_password("IPA admin")
+ return admin_password
+
+def check_dirsrv(unattended):
+ serverids = ipaserver.dsinstance.check_existing_installation()
+ if serverids:
+ print ""
+ print "An existing Directory Server has been detected."
+ if unattended or not user_input("Do you wish to remove it and create a new one?", False):
+ print ""
+ print "Only a single Directory Server instance is allowed on an IPA"
+ print "server, the one used by IPA itself."
+ sys.exit(1)
+
+ try:
+ service.stop("dirsrv")
+ except:
+ pass
+
+ for serverid in serverids:
+ ipaserver.dsinstance.erase_ds_instance_data(serverid)
+
+ (ds_unsecure, ds_secure) = ipaserver.dsinstance.check_ports()
+ if not ds_unsecure or not ds_secure:
+ print "IPA requires ports 389 and 636 for the Directory Server."
+ print "These are currently in use:"
+ if not ds_unsecure:
+ print "\t389"
+ if not ds_secure:
+ print "\t636"
+ sys.exit(1)
+
+def uninstall():
+ try:
+ run(["/usr/sbin/ipa-client-install", "--on-master", "--unattended", "--uninstall"])
+ except Exception, e:
+ print "Uninstall of client side components failed!"
+ print "ipa-client-install returned: " + str(e)
+ pass
+
+ ipaserver.ntpinstance.NTPInstance(fstore).uninstall()
+ ipaserver.bindinstance.BindInstance(fstore).uninstall()
+ ipaserver.httpinstance.WebGuiInstance().uninstall()
+ ipaserver.httpinstance.HTTPInstance(fstore).uninstall()
+ ipaserver.krbinstance.KrbInstance(fstore).uninstall()
+ ipaserver.dsinstance.DsInstance().uninstall()
+ fstore.restore_all_files()
+ return 0
+
+def main():
+ global ds
+ global pw_name
+ ds = None
+
+ options = parse_options()
+
+ if os.getegid() != 0:
+ print "Must be root to setup server"
+ return 1
+
+ signal.signal(signal.SIGTERM, signal_handler)
+ signal.signal(signal.SIGINT, signal_handler)
+
+ if options.uninstall:
+ standard_logging_setup("/var/log/ipaserver-uninstall.log", options.debug)
+ else:
+ standard_logging_setup("/var/log/ipaserver-install.log", options.debug)
+ print "\nThe log file for this installation can be found in /var/log/ipaserver-install.log"
+
+ global fstore
+ fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
+
+ if options.uninstall:
+ if not options.unattended:
+ print "\nThis is a NON REVERSIBLE operation and will delete all data and configuration!\n"
+ if not user_input("Are you sure you want to continue with the uninstall procedure?", False):
+ print ""
+ print "Aborting uninstall operation."
+ sys.exit(1)
+
+ return uninstall()
+
+ print "=============================================================================="
+ print "This program will setup the FreeIPA Server."
+ print ""
+ print "This includes:"
+ if options.conf_ntp:
+ print " * Configure the Network Time Daemon (ntpd)"
+ print " * Create and configure an instance of Directory Server"
+ print " * Create and configure a Kerberos Key Distribution Center (KDC)"
+ print " * Configure Apache (httpd)"
+ print " * Configure TurboGears"
+ if options.setup_bind:
+ print " * Configure DNS (bind)"
+ if not options.conf_ntp:
+ print ""
+ print "Excluded by options:"
+ print " * Configure the Network Time Daemon (ntpd)"
+ print ""
+ print "To accept the default shown in brackets, press the Enter key."
+ print ""
+
+ check_dirsrv(options.unattended)
+
+ ds_user = ""
+ realm_name = ""
+ host_name = ""
+ domain_name = ""
+ ip_address = ""
+ master_password = ""
+ dm_password = ""
+ admin_password = ""
+
+ # check bind packages are installed
+ if options.setup_bind:
+ if not ipaserver.bindinstance.check_inst():
+ print "--setup-bind was specified but bind is not installed on the system"
+ print "Please install bind and restart the setup program"
+ return 1
+
+ # check the hostname is correctly configured, it must be as the kldap
+ # utilities just use the hostname as returned by gethostbyname to set
+ # up some of the standard entries
+
+ host_default = ""
+ if options.host_name:
+ host_default = options.host_name
+ else:
+ host_default = get_fqdn()
+
+ if options.unattended:
+ try:
+ verify_fqdn(host_default,options.no_host_dns)
+ except RuntimeError, e:
+ logging.error(str(e) + "\n")
+ return 1
+
+ host_name = host_default
+ else:
+ host_name = read_host_name(host_default,options.no_host_dns)
+
+ host_name = host_name.lower()
+
+ if not options.domain_name:
+ domain_name = read_domain_name(host_name[host_name.find(".")+1:], options.unattended)
+ else:
+ domain_name = options.domain_name
+
+ domain_name = domain_name.lower()
+
+ # Check we have a public IP that is associated with the hostname
+ ip = resolve_host(host_name)
+ if ip is None:
+ if options.ip_address:
+ ip = options.ip_address
+ if ip is None and options.unattended:
+ print "Unable to resolve IP address for host name"
+ return 1
+
+ if not verify_ip_address(ip):
+ ip = ""
+ if options.unattended:
+ return 1
+
+ if options.ip_address and options.ip_address != ip:
+ if options.setup_bind:
+ ip = options.ip_address
+ else:
+ print "Error: the hostname resolves to an IP address that is different"
+ print "from the one provided on the command line. Please fix your DNS"
+ print "or /etc/hosts file and restart the installation."
+ return 1
+
+ if options.unattended:
+ if not ip:
+ print "Unable to resolve IP address"
+ return 1
+
+ if not ip:
+ ip = read_ip_address(host_name)
+ ip_address = ip
+
+ print "The IPA Master Server will be configured with"
+ print "Hostname: " + host_name
+ print "IP address: " + ip_address
+ print "Domain name: " + domain_name
+ print ""
+
+ if not options.ds_user:
+ ds_user = read_ds_user()
+ if ds_user == "":
+ return 1
+ else:
+ ds_user = options.ds_user
+
+ if not options.realm_name:
+ realm_name = read_realm_name(domain_name, options.unattended)
+ else:
+ realm_name = options.realm_name.upper()
+
+ if not options.dm_password:
+ dm_password = read_dm_password()
+ else:
+ dm_password = options.dm_password
+
+ if not options.master_password:
+ master_password = ipa_generate_password()
+ else:
+ master_password = options.master_password
+
+ if not options.admin_password:
+ admin_password = read_admin_password()
+ else:
+ admin_password = options.admin_password
+
+ if not options.unattended:
+ print ""
+ print "The following operations may take some minutes to complete."
+ print "Please wait until the prompt is returned."
+
+ # Configure ntpd
+ if options.conf_ntp:
+ ntp = ipaserver.ntpinstance.NTPInstance(fstore)
+ ntp.create_instance()
+
+ if options.dirsrv_pin:
+ [pw_fd, pw_name] = tempfile.mkstemp()
+ os.write(pw_fd, options.dirsrv_pin)
+ os.close(pw_fd)
+
+ # Create a directory server instance
+ ds = ipaserver.dsinstance.DsInstance()
+ if options.dirsrv_pkcs12:
+ pkcs12_info = (options.dirsrv_pkcs12, pw_name)
+ ds.create_instance(ds_user, realm_name, host_name, domain_name, dm_password, pkcs12_info)
+ os.remove(pw_name)
+ else:
+ ds.create_instance(ds_user, realm_name, host_name, domain_name, dm_password)
+
+ # Create a kerberos instance
+ krb = ipaserver.krbinstance.KrbInstance(fstore)
+ krb.create_instance(ds_user, realm_name, host_name, domain_name, dm_password, master_password)
+
+ # Create a HTTP instance
+
+ if options.http_pin:
+ [pw_fd, pw_name] = tempfile.mkstemp()
+ os.write(pw_fd, options.http_pin)
+ os.close(pw_fd)
+
+ http = ipaserver.httpinstance.HTTPInstance(fstore)
+ if options.http_pkcs12:
+ pkcs12_info = (options.http_pkcs12, pw_name)
+ http.create_instance(realm_name, host_name, domain_name, autoconfig=False, pkcs12_info=pkcs12_info)
+ os.remove(pw_name)
+ else:
+ http.create_instance(realm_name, host_name, domain_name, autoconfig=True)
+
+ # Create the config file
+ fstore.backup_file("/etc/ipa/ipa.conf")
+ fd = open("/etc/ipa/ipa.conf", "w")
+ fd.write("[defaults]\n")
+ fd.write("server=" + host_name + "\n")
+ fd.write("realm=" + realm_name + "\n")
+ fd.write("domain=" + domain_name + "\n")
+ fd.close()
+
+ # Create a Web Gui instance
+ webgui = ipaserver.httpinstance.WebGuiInstance()
+ webgui.create_instance()
+
+ bind = ipaserver.bindinstance.BindInstance(fstore)
+ bind.setup(host_name, ip_address, realm_name, domain_name)
+ if options.setup_bind:
+ bind.create_instance()
+ else:
+ bind.create_sample_bind_zone()
+
+ # Apply any LDAP updates. Needs to be done after the configuration file
+ # is created
+ service.print_msg("Applying LDAP updates")
+ ds.apply_updates()
+
+ # Restart ds and krb after configurations have been changed
+ service.print_msg("restarting the directory server")
+ ds.restart()
+
+ service.print_msg("restarting the KDC")
+ krb.restart()
+
+ # Set the admin user kerberos password
+ ds.change_admin_password(admin_password)
+
+ # Call client install script
+ try:
+ run(["/usr/sbin/ipa-client-install", "--on-master", "--unattended", "--domain", domain_name, "--server", host_name, "--realm", realm_name])
+ except Exception, e:
+ print "Configuration of client side components failed!"
+ print "ipa-client-install returned: " + str(e)
+ return 1
+
+ print "=============================================================================="
+ print "Setup complete"
+ print ""
+ print "Next steps:"
+ print "\t1. You must make sure these network ports are open:"
+ print "\t\tTCP Ports:"
+ print "\t\t * 80, 443: HTTP/HTTPS"
+ print "\t\t * 389, 636: LDAP/LDAPS"
+ print "\t\t * 88, 464: kerberos"
+ if options.setup_bind:
+ print "\t\t * 53: bind"
+ print "\t\tUDP Ports:"
+ print "\t\t * 88, 464: kerberos"
+ if options.setup_bind:
+ print "\t\t * 53: bind"
+ if options.conf_ntp:
+ print "\t\t * 123: ntp"
+ print ""
+ print "\t2. You can now obtain a kerberos ticket using the command: 'kinit admin'"
+ print "\t This ticket will allow you to use the IPA tools (e.g., ipa-adduser)"
+ print "\t and the web user interface."
+
+ if not service.is_running("ntpd"):
+ print "\t3. Kerberos requires time synchronization between clients"
+ print "\t and servers for correct operation. You should consider enabling ntpd."
+
+ print ""
+ if not options.dirsrv_pkcs12:
+ print "Be sure to back up the CA certificate stored in " + ipaserver.dsinstance.config_dirname(ds.serverid) + "cacert.p12"
+ print "The password for this file is in " + ipaserver.dsinstance.config_dirname(ds.serverid) + "pwdfile.txt"
+ else:
+ print "In order for Firefox autoconfiguration to work you will need to"
+ print "use a SSL signing certificate. See the IPA documentation for more details."
+ print "You also need to install a PEM copy of the HTTP issuing CA into"
+ print "/usr/share/ipa/html/ca.crt"
+
+ return 0
+
+try:
+ try:
+ sys.exit(main())
+ except SystemExit, e:
+ sys.exit(e)
+ except Exception, e:
+ message = "Unexpected error - see ipaserver-install.log for details:\n %s" % str(e)
+ print message
+ message = str(e)
+ for str in traceback.format_tb(sys.exc_info()[2]):
+ message = message + "\n" + str
+ logging.debug(message)
+ sys.exit(1)
+finally:
+ if pw_name and ipautil.file_exists(pw_name):
+ os.remove(pw_name)
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig
new file mode 100644
index 00000000..48c4117d
--- /dev/null
+++ b/install/tools/ipa-upgradeconfig
@@ -0,0 +1,130 @@
+#!/usr/bin/python
+#
+# Upgrade configuration files to a newer template.
+
+import sys
+try:
+ from ipa import ipautil
+ import krbV
+ import re
+ import os
+ import shutil
+ import fileinput
+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)
+
+def backup_file(filename, ext):
+ """Make a backup of filename using ext as the extension. Do not overwrite
+ previous backups."""
+ if not os.path.isabs(filename):
+ raise ValueError("Absolute path required")
+
+ backupfile = filename + ".bak"
+ (reldir, file) = os.path.split(filename)
+
+ while os.path.exists(backupfile):
+ backupfile = backupfile + "." + str(ext)
+
+ shutil.copy2(filename, backupfile)
+
+def update_conf(sub_dict, filename, template_filename):
+ template = ipautil.template_file(template_filename, sub_dict)
+ fd = open(filename, "w")
+ fd.write(template)
+ fd.close()
+
+def find_hostname():
+ """Find the hostname currently configured in ipa-rewrite.conf"""
+ filename="/etc/httpd/conf.d/ipa-rewrite.conf"
+ pattern = "^[\s#]*.*https:\/\/([A-Za-z0-9\.\-]*)\/.*"
+ p = re.compile(pattern)
+ for line in fileinput.input(filename):
+ if p.search(line):
+ fileinput.close()
+ return p.search(line).group(1)
+ fileinput.close()
+
+ return None
+
+def find_version(filename):
+ """Find the version of a configuration file"""
+ if os.path.exists(filename):
+ pattern = "^[\s#]*VERSION\s+([0-9]+)\s+.*"
+ p = re.compile(pattern)
+ for line in fileinput.input(filename):
+ if p.search(line):
+ fileinput.close()
+ return p.search(line).group(1)
+ fileinput.close()
+
+ # no VERSION found
+ return 0
+ else:
+ return -1
+
+def upgrade(sub_dict, filename, template):
+ old = int(find_version(filename))
+ new = int(find_version(template))
+
+ if old < 0:
+ print "%s not found." % filename
+ sys.exit(1)
+
+ if new < 0:
+ print "%s not found." % template
+
+ if old < new:
+ backup_file(filename, new)
+ update_conf(sub_dict, filename, template)
+ print "Upgraded %s to version %d" % (filename, new)
+
+def check_certs(realm_name):
+ """Check ca.crt is in the right place, and try to fix if not"""
+ if not os.path.exists("/usr/share/ipa/html/ca.crt"):
+ ca_file = "/etc/dirsrv/slapd-" + ("-".join(realm_name.split("."))) + "/cacert.asc"
+ if os.path.exists(ca_file):
+ shutil.copyfile(ca_file, "/usr/share/ipa/html/ca.crt")
+ else:
+ print "Missing Certification Authority file."
+ print "You should place a copy of the CA certificate in /usr/share/ipa/html/ca.crt"
+
+def main():
+ try:
+ krbctx = krbV.default_context()
+ except krbV.Krb5Error, e:
+ print "Unable to get default kerberos realm: %s" % e[1]
+ sys.exit(1)
+
+ try:
+ check_certs(krbctx.default_realm)
+ except Error, e:
+ print "Failed to check CA certificate: %s" % e
+
+ try:
+ fqdn = find_hostname()
+ except IOError:
+ # ipa-rewrite.conf doesn't exist, nothing to do
+ sys.exit(0)
+
+ if fqdn is None:
+ print "Unable to determine hostname from ipa-rewrite.conf"
+ sys.exit(1)
+
+ sub_dict = { "REALM" : krbctx.default_realm, "FQDN": fqdn }
+
+ upgrade(sub_dict, "/etc/httpd/conf.d/ipa.conf", ipautil.SHARE_DIR + "ipa.conf")
+ upgrade(sub_dict, "/etc/httpd/conf.d/ipa-rewrite.conf", ipautil.SHARE_DIR + "ipa-rewrite.conf")
+
+try:
+ if __name__ == "__main__":
+ sys.exit(main())
+except SystemExit, e:
+ sys.exit(e)
+except KeyboardInterrupt, e:
+ sys.exit(1)
diff --git a/install/tools/ipactl b/install/tools/ipactl
new file mode 100644
index 00000000..11038394
--- /dev/null
+++ b/install/tools/ipactl
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# Copyright (C) 2008 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; version 2 only
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# IPA control to start/stop the various services required for IPA in the
+# proper order
+#
+
+function start() {
+ /sbin/service dirsrv start
+ /sbin/service ntpd start
+ /sbin/service krb5kdc start
+ /sbin/service ipa_kpasswd start
+ /sbin/service ipa_webgui start
+ /sbin/service httpd start
+}
+
+function stop() {
+ /sbin/service ipa_webgui stop
+ /sbin/service ipa_kpasswd stop
+ /sbin/service httpd stop
+ /sbin/service krb5kdc stop
+ /sbin/service dirsrv stop
+ /sbin/service ntpd stop
+}
+
+case "$1" in
+restart)
+ stop
+ start
+ ;;
+start)
+ start
+ ;;
+stop)
+ stop
+ ;;
+*)
+ echo "Usage: ipactl {start|stop|restart}"
+ exit 1
+ ;;
+esac
diff --git a/install/tools/man/Makefile.am b/install/tools/man/Makefile.am
new file mode 100644
index 00000000..244b06b8
--- /dev/null
+++ b/install/tools/man/Makefile.am
@@ -0,0 +1,27 @@
+# This file will be processed with automake-1.7 to create Makefile.in
+
+AUTOMAKE_OPTIONS = 1.7
+
+NULL=
+
+man1_MANS = \
+ ipa-replica-install.1 \
+ ipa-replica-manage.1 \
+ ipa-replica-prepare.1 \
+ ipa-server-certinstall.1 \
+ ipa-server-install.1 \
+ ipa-ldap-updater.1 \
+ ipa-compat-manage.1
+
+man8_MANS = \
+ ipactl.8 \
+ ipa_kpasswd.8 \
+ ipa_webgui.8
+
+install-data-hook:
+ @for i in $(man1_MANS) ; do gzip -f $(DESTDIR)$(man1dir)/$$i ; done
+ @for i in $(man8_MANS) ; do gzip -f $(DESTDIR)$(man8dir)/$$i ; done
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ $(NULL)
diff --git a/install/tools/man/ipa-compat-manage.1 b/install/tools/man/ipa-compat-manage.1
new file mode 100644
index 00000000..767384a4
--- /dev/null
+++ b/install/tools/man/ipa-compat-manage.1
@@ -0,0 +1,45 @@
+.\" A man page for ipa-ldap-updater
+.\" Copyright (C) 2008 Red Hat, Inc.
+.\"
+.\" This is free software; you can redistribute it and/or modify it under
+.\" the terms of the GNU Library General Public License as published by
+.\" the Free Software Foundation; version 2 only
+.\"
+.\" 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 Library General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Author: Simo Sorce <ssorce@redhat.com>
+.\"
+.TH "ipa-compat-manage" "1" "Dec 2 2008" "freeipa" ""
+.SH "NAME"
+ipa\-compat\-manage \- Enables or disables the schema compatibility plugin
+.SH "SYNOPSIS"
+ipa\-compat\-manage [options] <enable|disable>
+.SH "DESCRIPTION"
+Run the command with the \fBenable\fR option to enable the compat plugin.
+
+Run the command with the \fBdisable\fR option to disable the compat plugin.
+
+In both cases the user will be prompted to provide the Directory Manager's password unless option \fB\-y\fR is used.
+
+Directory Server will need to be restarted after the schema compatibility plugin has been enabled.
+
+.SH "OPTIONS"
+.TP
+\fB\-d\fR, \fB\-\-debug\fR
+Enable debug logging when more verbose output is needed
+.TP
+\fB\-y\fR \fIfile\fR
+File containing the Directory Manager password
+.SH "EXIT STATUS"
+0 if the command was successful
+
+1 if an error occurred
+
+2 if the plugin is already in the required status (enabled or disabled)
diff --git a/install/tools/man/ipa-ldap-updater.1 b/install/tools/man/ipa-ldap-updater.1
new file mode 100644
index 00000000..453ac758
--- /dev/null
+++ b/install/tools/man/ipa-ldap-updater.1
@@ -0,0 +1,78 @@
+.\" A man page for ipa-ldap-updater
+.\" Copyright (C) 2008 Red Hat, Inc.
+.\"
+.\" This is free software; you can redistribute it and/or modify it under
+.\" the terms of the GNU Library General Public License as published by
+.\" the Free Software Foundation; version 2 only
+.\"
+.\" 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 Library General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Author: Rob Crittenden <rcritten@redhat.com>
+.\"
+.TH "ipa-ldap-updater" "1" "Sep 12 2008" "freeipa" ""
+.SH "NAME"
+ipa\-ldap\-updater \- Update the IPA LDAP configuration
+.SH "SYNOPSIS"
+ipa\-ldap\-updater [options] input_file(s)
+ipa\-ldap\-updater [options]
+.SH "DESCRIPTION"
+Run with no file arguments, ipa\-ldap\-updater will process all files with the extension .update in /usr/share/ipa/updates.
+
+An update file describes an LDAP entry and a set of operations to be performed on that entry. It can be used to add new entries or modify existing entries. It cannot remove entries, just specific values in a given attribute.
+
+Blank lines and lines beginning with # are ignored.
+
+There are 4 keywords:
+
+ * default: the starting value
+ * add: add a value (or values) to an attribute
+ * remove: remove a value (or values) from an attribute
+ * only: set an attribute to this
+
+Values is a comma\-separated field so multi\-values may be added at one time. Double or single quotes may be put around individual values that contain embedded commas.
+
+The difference between the default and add keywords is if the DN of the entry exists then default is ignored. So for updating something like schema, which will be under cn=schema, you must always use add (because cn=schema is guaranteed to exist). It will not re\-add the same information again and again.
+
+It alsos provide some things that can be templated such as architecture (for plugin paths), realm and domain name.
+
+The available template variables are:
+
+ * $REALM \- the kerberos realm (EXAMPLE.COM)
+ * $FQDN \- the fully\-qualified domain name of the IPA server being updated (ipa.example.com)
+ * $DOMAIN \- the domain name (example.com)
+ * $SUFFIX \- the IPA LDAP suffix (dc=example,dc=com)
+ * $LIBARCH \- set to 64 on x86_64 systems to be used for plugin paths
+ * $TIME \- an integer representation of current time
+
+A few rules:
+
+ 1. Only one rule per line
+ 2. Each line stands alone (e.g. an only followed by an only results in the last only being used)
+ 3. adding a value that exists is ok. The request is ignored, duplicate values are not added
+ 4. removing a value that doesn't exist is ok. It is simply ignored.
+ 5. If a DN doesn't exist it is created from the 'default' entry and all updates are applied
+ 6. If a DN does exist the default values are skipped
+ 7. Only the first rule on a line is respected
+.SH "OPTIONS"
+.TP
+\fB\-d\fR, \fB\-\-debug
+Enable debug logging when more verbose output is needed
+.TP
+\fB\-t\fR, \fB\-\-test\fR
+Run through the update without changing anything. If changes are available then the command returns 2. If no updates are available it returns 0.
+.TP
+\fB\-y\fR
+File containing the Directory Manager password
+.SH "EXIT STATUS"
+0 if the command was successful
+
+1 if an error occurred
+
+2 if run with in test mode (\-t) and updates are available
diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1
new file mode 100644
index 00000000..674afd12
--- /dev/null
+++ b/install/tools/man/ipa-replica-install.1
@@ -0,0 +1,41 @@
+.\" A man page for ipa-replica-install
+.\" Copyright (C) 2008 Red Hat, Inc.
+.\"
+.\" This is free software; you can redistribute it and/or modify it under
+.\" the terms of the GNU Library General Public License as published by
+.\" the Free Software Foundation; version 2 only
+.\"
+.\" 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 Library General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Author: Rob Crittenden <rcritten@redhat.com>
+.\"
+.TH "ipa-replica-install" "1" "Mar 14 2008" "freeipa" ""
+.SH "NAME"
+ipa\-replica\-install \- Create an IPA replica
+.SH "SYNOPSIS"
+ipa\-replica\-install [\fIOPTION\fR]... replica_file
+.SH "DESCRIPTION"
+Configures a new IPA server that is a replica of the server that generated it. Once it has been created it is an exact copy of the original IPA server and is an equal master. Changes made to any master are automatically replicated to other masters.
+
+The replica_file is created using the ipa\-replica\-prepare utility.
+.SH "OPTIONS"
+.TP
+\fB\-d\fR, \fB\-\-debug
+Enable debug logging when more verbose output is needed
+.TP
+\fB\-n\fR, \fB\-\-no\-ntp\fR
+Do not configure NTP
+.TP
+\fB\-p\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR
+Directory Manager (existing master) password
+.SH "EXIT STATUS"
+0 if the command was successful
+
+1 if an error occurred
diff --git a/install/tools/man/ipa-replica-manage.1 b/install/tools/man/ipa-replica-manage.1
new file mode 100644
index 00000000..810cf1de
--- /dev/null
+++ b/install/tools/man/ipa-replica-manage.1
@@ -0,0 +1,70 @@
+.\" A man page for ipa-replica-manage
+.\" Copyright (C) 2008 Red Hat, Inc.
+.\"
+.\" This is free software; you can redistribute it and/or modify it under
+.\" the terms of the GNU Library General Public License as published by
+.\" the Free Software Foundation; version 2 only
+.\"
+.\" 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 Library General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Author: Rob Crittenden <rcritten@redhat.com>
+.\"
+.TH "ipa-replica-manage" "1" "Mar 14 2008" "freeipa" ""
+.SH "NAME"
+ipa\-replica\-manage \- Manage an IPA replica
+.SH "SYNOPSIS"
+ipa\-replica\-manage [\fIOPTION\fR]... [add|del|list|init|synch] [SERVER]
+.SH "DESCRIPTION"
+Manages the replication agreements of an IPA server.
+.TP
+add \- Adds a new replication agreement between two existing IPA servers
+.TP
+del \- Removes a replication agreement
+.TP
+list \- Lists the hostnames that HOST IPA server has agreements with
+.TP
+init \- Forces a full initialization of the IPA server on SERVER from HOST
+.TP
+synch \- Immediately flush any data to be replicated to SERVER
+.SH "OPTIONS"
+.TP
+\fB\-H HOST\fR, \fB\-\-host\fR=\fIHOST\fR
+The IPA server to manage
+.TP
+\fB\-p DM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR
+The Directory Manager password to use for authentication
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+Provide additional information
+.TP
+\fB\-\-winsync\fR
+Specifies to create/use a Windows Sync Agreement
+.TP
+\fB\-\-port\fR=\fISERVER_PORT\fR
+Port number of other server (default is 636, the LDAPS port)
+.TP
+\fB\-\-binddn\fR=\fIADMIN_DN\fR
+Bind DN to use with remote server (default is cn=Directory Manager) - Be careful to quote this value on the command line
+.TP
+\fB--bindpw\fR=\fIADMIN_PWD\fR
+Password for Bind DN to use with remote server (default is the DM_PASSWORD above)
+.TP
+\fB\-\-cacert\fR=\fI/path/to/cacertfile\fR
+Full path and filename of CA certificate to use with TLS/SSL to the remote server - this CA certificate will be installed in the directory server's certificate database
+.TP
+\fB\-\-win-subtree\fR=\fIcn=Users,dc=example,dc=com\fR
+DN of Windows subtree containing the users you want to sync (default cn=Users,<domain suffix> - this is typically what Windows AD uses as the default value) - Be careful to quote this value on the command line
+.TP
+\fB\-\-passsync\fR=\fIPASSSYNC_PWD\fR
+Password for the Windows PassSync user.
+.SH "EXIT STATUS"
+0 if the command was successful
+
+1 if an error occurred
diff --git a/install/tools/man/ipa-replica-prepare.1 b/install/tools/man/ipa-replica-prepare.1
new file mode 100644
index 00000000..8eb49444
--- /dev/null
+++ b/install/tools/man/ipa-replica-prepare.1
@@ -0,0 +1,48 @@
+.\" A man page for ipa-replica-prepare
+.\" Copyright (C) 2008 Red Hat, Inc.
+.\"
+.\" This is free software; you can redistribute it and/or modify it under
+.\" the terms of the GNU Library General Public License as published by
+.\" the Free Software Foundation; version 2 only
+.\"
+.\" 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 Library General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Author: Rob Crittenden <rcritten@redhat.com>
+.\"
+.TH "ipa-replica-prepare" "1" "Mar 14 2008" "freeipa" ""
+.SH "NAME"
+ipa\-replica\-prepare \- Create an IPA replica file
+.SH "SYNOPSIS"
+ipa\-replica\-prepare [\fIOPTION\fR]... hostname
+.SH "DESCRIPTION"
+Generates a replica file that may be used with ipa\-replica\-install to create a replica of an IPA server.
+
+A replica can only be created on an IPA server installed with ipa\-server\-install (the first server).
+
+You must provide the fully\-qualified hostname of the machine you want to install the replica on and a host\-specific replica_file will be created. It is host\-specific because SSL server certificates are generated as part of the process and they are specific to a particular hostname.
+
+Once the file has been created it will be named replica\-hostname. This file can then be moved across the network to the target machine and a new IPA replica setup by running ipa\-replica\-install replica\-hostname.
+.SH "OPTIONS"
+.TP
+\fB\-\-dirsrv_pkcs12\fR=\fIFILE\fR
+PKCS#12 file containing the Directory Server SSL Certificate
+.TP
+\fB\-\-http_pkcs12\fR=\fIFILE\fR
+PKCS#12 file containing the Apache Server SSL Certificate
+.TP
+\fB\-\-dirsrv_pin\fR=\fIDIRSRV_PIN\fR
+The password of the Directory Server PKCS#12 file
+.TP
+\fB\-\-http_pin\fR=\fIHTTP_PIN\fR
+The password of the Apache Server PKCS#12 file
+.SH "EXIT STATUS"
+0 if the command was successful
+
+1 if an error occurred
diff --git a/install/tools/man/ipa-server-certinstall.1 b/install/tools/man/ipa-server-certinstall.1
new file mode 100644
index 00000000..946ab9f8
--- /dev/null
+++ b/install/tools/man/ipa-server-certinstall.1
@@ -0,0 +1,48 @@
+.\" A man page for ipa-server-certinstall
+.\" Copyright (C) 2008 Red Hat, Inc.
+.\"
+.\" This is free software; you can redistribute it and/or modify it under
+.\" the terms of the GNU Library General Public License as published by
+.\" the Free Software Foundation; version 2 only
+.\"
+.\" 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 Library General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Author: Rob Crittenden <rcritten@redhat.com>
+.\"
+.TH "ipa-server-certinstall" "1" "Mar 14 2008" "freeipa" ""
+.SH "NAME"
+ipa\-server\-certinstall \- Install new SSL server certificates
+.SH "SYNOPSIS"
+ipa\-server\-certinstall [\fIOPTION\fR]... PKCS12_FILE
+.SH "DESCRIPTION"
+Replace the current SSL Directory and/or Apache server certificate(s) with the certificate in the PKCS#12 file.
+
+PKCS#12 is a file format used to safely transport SSL certificates and public/private keypairs.
+
+They may be generated and managed using the NSS pk12util command or the OpenSSL pkcs12 command.
+
+The service(s) are not automatically restarted. In order to use the newly installed certificate(s) you will need to manually restart the Directory and/or Apache servers.
+.SH "OPTIONS"
+.TP
+\fB\-d\fR, \fB\-\-dirsrv\fR
+Install the certificate on the Directory Server
+.TP
+\fB\-w\fR, \fB\-\-http\fR
+Install the certificate in the Apache Web Server
+.TP
+\fB\-\-dirsrv_pin\fR=\fIDIRSRV_PIN\fR
+The password of the Directory Server PKCS#12 file
+.TP
+\fB\-\-http_pin\fR=\fIHTTP_PIN\fR
+The password of the Apache Server PKCS#12 file
+.SH "EXIT STATUS"
+0 if the installation was successful
+
+1 if an error occurred
diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1
new file mode 100644
index 00000000..8854f4e5
--- /dev/null
+++ b/install/tools/man/ipa-server-install.1
@@ -0,0 +1,81 @@
+.\" A man page for ipa-server-install
+.\" Copyright (C) 2008 Red Hat, Inc.
+.\"
+.\" This is free software; you can redistribute it and/or modify it under
+.\" the terms of the GNU Library General Public License as published by
+.\" the Free Software Foundation; version 2 only
+.\"
+.\" 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 Library General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Author: Rob Crittenden <rcritten@redhat.com>
+.\"
+.TH "ipa-server-install" "1" "Mar 14 2008" "freeipa" ""
+.SH "NAME"
+ipa\-server\-install \- Configure an IPA server
+.SH "SYNOPSIS"
+ipa\-server\-install [\fIOPTION\fR]...
+.SH "DESCRIPTION"
+Configures the services needed by an IPA server. This includes setting up a Kerberos Key Distribution Center (KDC) with an LDAP back\-end, configuring Apache, configuring NTP and starting some IPA\-provided services: ipa_kpasswd and ipa_webgui.
+.SH "OPTIONS"
+.TP
+\fB\-u\fR, \fB\-\-user\fR=\fIDS_USER\fR
+The user that the Directory Server will run as
+.TP
+\fB\-r\fR, \fB\-\-realm\fR=\fIREALM_NAME\fR
+The Kerberos realm name for the IPA server
+.TP
+\fB\-n\fR, \fB\-\-domain\fR=\fIDOMAIN_NAME\fR
+Your DNS domain name
+.TP
+\fB\-p\fR, \fB\-\-ds\-password\fR=\fIDM_PASSWORD\fR
+The password to be used by the Directory Server for the Directory Manager user
+.TP
+\fB\-P\fR, \fB\-\-master\-password\fR=\fIMASTER_PASSWORD\fR
+The kerberos master password (normally autogenerated)
+.TP
+\fB\-a\fR, \fB\-\-admin\-password\fR=\fIADMIN_PASSWORD\fR
+The password for the IPA admin user
+.TP
+\fB\-d\fR, \fB\-\-debug\fR
+Enable debug logging when more verbose output is needed
+.TP
+\fB\-\-hostname\fR=\fIHOST_NAME\fR
+The fully\-qualified DNS name of this server
+.TP
+\fB\-\-ip\-address\fR=\fIIP_ADDRESS\fR
+The IP address of this server
+.TP
+\fB\-U\fR, \fB\-\-unattended\fR
+An unattended installation that will never prompt for user input
+.TP
+\fB\-\-setup\-bind\fR
+Generate a DNS zone file that contains auto\-discovery records for this IPA server
+.TP
+\fB\-n\fR, \fB\-\-no\-ntp\fR
+Do not configure NTP
+\fB\-U\fR, \fB\-\-uninstall\fR
+Uninstall an existing IPA installation
+.TP
+\fB\-\-dirsrv_pkcs12\fR=\fIFILE\fR
+PKCS#12 file containing the Directory Server SSL Certificate
+.TP
+\fB\-\-http_pkcs12\fR=\fIFILE\fR
+PKCS#12 file containing the Apache Server SSL Certificate
+.TP
+\fB\-\-dirsrv_pin\fR=\fIDIRSRV_PIN\fR
+The password of the Directory Server PKCS#12 file
+.TP
+\fB\-\-http_pin\fR=\fIHTTP_PIN\fR
+The password of the Apache Server PKCS#12 file
+.PP
+.SH "EXIT STATUS"
+0 if the installation was successful
+
+1 if an error occurred
diff --git a/install/tools/man/ipa_kpasswd.8 b/install/tools/man/ipa_kpasswd.8
new file mode 100644
index 00000000..f2ba3dd9
--- /dev/null
+++ b/install/tools/man/ipa_kpasswd.8
@@ -0,0 +1,36 @@
+.\" A man page for ipa_kpasswd
+.\" Copyright (C) 2008 Red Hat, Inc.
+.\"
+.\" This is free software; you can redistribute it and/or modify it under
+.\" the terms of the GNU Library General Public License as published by
+.\" the Free Software Foundation; version 2 only
+.\"
+.\" 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 Library General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Author: Rob Crittenden <rcritten@redhat.com>
+.\"
+.TH "ipa_kpasswd" "8" "Mar 14 2008" "freeipa" ""
+.SH "NAME"
+ipa_kpasswd \- Proxy Kerberos password change requests
+.SH "SYNOPSIS"
+ipa_kpasswd
+.SH "DESCRIPTION"
+Implementation of the kpasswd protocol (RFC 3244).
+
+It is used to proxy password change operations to Directory Server.
+.SH "ENVIRONMENT VARIABLES"
+.TP
+KRB5_KTNAME
+Location of the keytab to be used by ipa_kpasswd
+.TP
+IPA_KPASSWD_DEBUG
+Enable additional syslog output from ipa_kpasswd. Setting greater than 0 gets basic output. Setting higher than 100 gets more.
+.SH "EXIT STATUS"
+\-1 if an error occurred
diff --git a/install/tools/man/ipa_webgui.8 b/install/tools/man/ipa_webgui.8
new file mode 100644
index 00000000..20545363
--- /dev/null
+++ b/install/tools/man/ipa_webgui.8
@@ -0,0 +1,37 @@
+.\" A man page for ipa_webgui
+.\" Copyright (C) 2008 Red Hat, Inc.
+.\"
+.\" This is free software; you can redistribute it and/or modify it under
+.\" the terms of the GNU Library General Public License as published by
+.\" the Free Software Foundation; version 2 only
+.\"
+.\" 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 Library General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Author: Rob Crittenden <rcritten@redhat.com>
+.\"
+.TH "ipa_webgui" "8" "Mar 14 2008" "freeipa" ""
+.SH "NAME"
+ipa_webgui \- Start the IPA Web User Interface
+.SH "SYNOPSIS"
+ipa_webgui [\fIOPTION\fR]...
+
+.SH "DESCRIPTION"
+Used to start the TurboGears web user interface for IPA
+.SH "OPTIONS"
+.TP
+\fB\-f\fR, \fB\-\-foreground\fR
+Remain in the foreground instead of becoming a daemon.
+.TP
+\fB\-d\fR, \fB\-\-debug\fR
+.TP
+Increase the amount of logging and print it to stdout instead of logging to /var/log/ipa_error.log
+
+.SH "EXIT STATUS"
+1 if an error occurred
diff --git a/install/tools/man/ipactl.8 b/install/tools/man/ipactl.8
new file mode 100644
index 00000000..a4797f96
--- /dev/null
+++ b/install/tools/man/ipactl.8
@@ -0,0 +1,37 @@
+.\" A man page for ipactl
+.\" Copyright (C) 2008 Red Hat, Inc.
+.\"
+.\" This is free software; you can redistribute it and/or modify it under
+.\" the terms of the GNU Library General Public License as published by
+.\" the Free Software Foundation; version 2 only
+.\"
+.\" 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 Library General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Author: Rob Crittenden <rcritten@redhat.com>
+.\"
+.TH "ipactl" "8" "Mar 14 2008" "freeipa" ""
+.SH "NAME"
+ipactl \- IPA Server Control Interface
+.SH "SYNOPSIS"
+ipactl \fIcommand\fR
+.SH "DESCRIPTION"
+A tool to help an administer control an IPA environment.
+
+IPA glues several discrete services together to work in concert and the order that these services are started and stopped is important. ipactl ensures that they are started and stopped in the correct order.
+.SH "OPTIONS"
+.TP
+start
+Start all of the services that make up IPA
+.TP
+stop
+Stop all of the services that make up IPA
+.TP
+restart
+Stop then start all of the services that make up IPA