From 6f9151a8ce9a1466d6303206add416086c8abd93 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Wed, 7 Oct 2009 10:51:27 -0400
Subject: [PATCH] Cache installer questions for the 2-step process of an externally-signed CA

Installing a CA that is signed by another CA is a 2-step process. The first
step is to generate a CSR for the CA and the second step is to install
the certificate issued by the external CA. To avoid asking questions
over and over (and potentially getting different answers) the answers
are cached.
---
 install/tools/ipa-server-install |   68 ++++++++++++++++++++++++++++++++++---
 ipaserver/install/cainstance.py  |    3 +-
 2 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 094654d..62c8bf5 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -36,6 +36,7 @@ import shutil
 import glob
 import traceback
 from optparse import OptionParser
+from ConfigParser import RawConfigParser
 import random
 
 from ipaserver.install import dsinstance
@@ -167,6 +168,59 @@ def signal_handler(signum, frame):
             dsinstance.erase_ds_instance_data (ds.serverid)
     sys.exit(1)
 
+ANSWER_CACHE = "/root/.ipa_cache"
+
+def read_cache():
+    """
+    Returns a dict of cached answers or None if no cache file exists.
+    """
+    if not ipautil.file_exists(ANSWER_CACHE):
+        return {}
+
+    optdict={}
+    parser = RawConfigParser()
+    try:
+        fp = open(ANSWER_CACHE, "r")
+        parser.readfp(fp)
+        optlist = parser.items('options')
+        fp.close()
+
+        # this is one-use only
+        os.remove(ANSWER_CACHE)
+    except IOError, e:
+        raise RuntimeError("Unable to determine serial number: %s" % str(e))
+
+    for opt in optlist:
+        optdict[opt[0]] = opt[1]
+        if optdict[opt[0]] == 'None':
+            optdict[opt[0]] = None
+
+    # These are the only ones that may be overridden
+    if 'external_ca_file' in optdict:
+        del optdict['external_ca_file']
+    if 'external_cert_file' in optdict:
+        del optdict['external_cert_file']
+
+    return optdict
+
+def write_cache(options):
+    """
+    Takes a dict as input and writes a cached file of answers
+    """
+
+    # convert the options instance into a dict
+    optdict = eval(str(options))
+    parser = RawConfigParser()
+    try:
+        fp = open(ANSWER_CACHE, "w")
+        parser.add_section('options')
+        for opt in optdict:
+            parser.set('options', opt, optdict[opt])
+        parser.write(fp)
+        fp.close()
+    except IOError, e:
+        raise RuntimeError("Unable to cache command-line options %s" % str(e))
+
 def read_host_name(host_default,no_host_dns=False):
     host_name = ""
 
@@ -385,6 +439,10 @@ def uninstall(ca = False):
     krbinstance.KrbInstance(fstore).uninstall()
     dsinstance.DsInstance().uninstall()
     fstore.restore_all_files()
+    try:
+        os.remove(ANSWER_CACHE)
+    except Exception:
+        pass
     return 0
 
 def main():
@@ -428,6 +486,9 @@ def main():
 
         return uninstall(options.ca)
 
+    # This will override any settings passed in on the cmdline
+    options._update_loose(read_cache())
+
     print "=============================================================================="
     print "This program will setup the FreeIPA Server."
     print ""
@@ -597,12 +658,6 @@ def main():
         os.close(pw_fd)
 
     if options.ca:
-        try:
-            from ipaserver.install import cainstance
-        except ImportError:
-            print >> sys.stderr, "Import failed: %s" % sys.exc_value
-            sys.exit(1)
-
         # Clean up any previous self-signed CA that may exist
         try:
             os.remove(certs.CA_SERIALNO)
@@ -633,6 +688,7 @@ def main():
         if external == 0:
             ca.configure_instance("pkiuser", host_name, dm_password, dm_password)
         elif external == 1:
+            write_cache(options)
             ca.configure_instance("pkiuser", host_name, dm_password, dm_password, csr_file="/root/ipa.csr")
         else:
             ca.configure_instance("pkiuser", host_name, dm_password, dm_password, cert_file=options.external_cert_file, cert_chain_file=options.external_ca_file)
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index b5fb9e6..c3bbfc0 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -605,7 +605,8 @@ class CAInstance(service.Service):
             ipautil.run(args)
 
             if self.external == 1:
-                print "The next step is to get %s signed by your CA and re-run ipa-server-install" % self.csr_file
+                print "The next step is to get %s signed by your CA and re-run ipa-server-install as:" % self.csr_file
+                print "ipa-server-install --ca --external_cert_file=/path/to/signed_certificate --external_ca_file=/path/to/external_ca_certificate"
                 sys.exit(0)
 
             # pkisilent doesn't return 1 on error so look at the output of
-- 
1.6.2.5

