#! /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
2008-02-04 15:15:52 -05:00
# 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
2008-02-05 12:23:53 -05:00
import traceback
from ConfigParser import SafeConfigParser
import krbV
2008-02-05 12:23:53 -05:00
from optparse import OptionParser
2008-02-05 12:23:53 -05:00
import ipa.config
from ipa import ipautil
2008-02-15 20:47:29 -05:00
from ipaserver import dsinstance, installutils, certs, ipaldap
2008-06-04 17:32:32 -04:00
from ipa import version
2008-02-15 20:47:29 -05:00
import ldap
2008-02-05 12:23:53 -05:00
def usage():
print "ipa-replica-prepate FQDN (e.g. replica.example.com)"
sys.exit(1)
def parse_options():
2008-05-08 11:45:38 -04:00
parser = OptionParser(version=version.VERSION)
2008-02-05 12:23:53 -05:00
args = ipa.config.init_config(sys.argv)
2008-07-11 11:34:29 -04:00
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")
2008-02-05 12:23:53 -05:00
options, args = parser.parse_args(args)
2008-07-11 11:34:29 -04:00
# 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.")
2008-02-05 12:23:53 -05:00
if len(args) != 2:
parser.error("must provide the fully-qualified name of the replica")
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():
2008-02-15 20:47:29 -05:00
try:
c = krbV.default_context()
return c.default_realm
except Exception, e:
return None
def get_domain_name():
try:
2008-05-23 14:51:50 -04:00
ipa.config.init_config()
domain_name = ipa.config.config.get_domain()
2008-02-15 20:47:29 -05:00
except Exception, e:
return None
return domain_name
def check_ipa_configuration(realm_name):
2008-02-05 12:23:53 -05:00
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)
2008-07-11 11:34:29 -04:00
def export_certdb(realm_name, ds_dir, dir, passwd_fname, fname, subject):
2008-02-05 12:23:53 -05:00
"""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.
2008-07-11 11:34:29 -04:00
passwd_fname is the file containing the PKCS#12 password
2008-02-05 12:23:53 -05:00
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
"""
2008-02-20 16:31:32 -05:00
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
2008-02-05 12:23:53 -05:00
pkcs12_fname = dir + "/" + fname + ".p12"
try:
2008-02-05 12:23:53 -05:00
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
2008-02-05 12:23:53 -05:00
os.unlink(dir + "/cert8.db")
os.unlink(dir + "/key3.db")
os.unlink(dir + "/secmod.db")
2008-02-15 20:47:29 -05:00
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
2008-02-15 20:47:29 -05:00
def save_config(dir, realm_name, host_name, ds_user, domain_name):
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)
2008-02-15 20:47:29 -05:00
config.set("realm", "domain_name", domain_name)
fd = open(dir + "/realm_info", "w")
config.write(fd)
def copy_files(realm_name, dir):
2008-02-05 12:23:53 -05:00
config_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name))
try:
shutil.copy("/var/kerberos/krb5kdc/ldappwd", dir + "/ldappwd")
2008-04-09 16:57:41 -04:00
shutil.copy("/var/kerberos/krb5kdc/kpasswd.keytab", dir + "/kpasswd.keytab")
2008-02-05 12:23:53 -05:00
shutil.copy("/usr/share/ipa/html/preferences.html", dir + "/preferences.html")
shutil.copy("/usr/share/ipa/html/configure.jar", dir + "/configure.jar")
shutil.copy(config_dir + "/cacert.asc", dir + "/ca.crt")
except Exception, e:
print "error copying files: " + str(e)
sys.exit(1)
def main():
2008-02-05 12:23:53 -05:00
options, args = parse_options()
replica_fqdn = args[1]
2008-07-24 14:34:43 -04:00
if not ipautil.file_exists(certs.CA_SERIALNO) and not options.dirsrv_pin:
2008-07-11 11:34:29 -04:00
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.")
2008-02-15 20:47:29 -05:00
print "Determining current realm name"
realm_name = get_realm_name()
2008-02-15 20:47:29 -05:00
if realm_name is None:
print "Unable to determine default realm"
sys.exit(1)
2008-02-05 12:23:53 -05:00
check_ipa_configuration(realm_name)
2008-02-15 20:47:29 -05:00
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()
2008-04-22 09:50:04 -04:00
if host_name == replica_fqdn:
print "You can't create a replica on itself"
sys.exit(1)
2008-02-08 15:10:26 -05:00
ds_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name))
ds_user = get_ds_user(ds_dir)
2008-02-05 12:23:53 -05:00
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)
2008-07-11 11:34:29 -04:00
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)
2008-02-05 12:23:53 -05:00
print "Copying additional files"
copy_files(realm_name, dir)
2008-02-05 12:23:53 -05:00
print "Finalizing configuration"
2008-02-15 20:47:29 -05:00
save_config(dir, realm_name, host_name, ds_user, domain_name)
2008-03-28 15:56:07 -04:00
print "Packaging the replica into /var/lib/ipa/%s" % "replica-info-" + replica_fqdn
ipautil.run(["/bin/tar", "cfz", "/var/lib/ipa/replica-info-" + replica_fqdn, "-C", top_dir, "realm_info"])
2008-04-09 16:57:41 -04:00
os.chmod("/var/lib/ipa/replica-info-" + replica_fqdn, 0600)
shutil.rmtree(dir)
2008-02-05 12:23:53 -05:00
try:
if not os.geteuid()==0:
sys.exit("\nYou must be root to run this script.\n")
main()
2008-02-08 15:10:26 -05:00
except SystemExit, e:
sys.exit(e)
2008-02-05 12:23:53 -05:00
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)