rpms/ipa/devel 0001-Fix-typo-in-inet-type.patch, NONE, 1.1 0001-In-openvz-we-found-out-some-interfaces-may-return-a.patch, NONE, 1.1 0001-slapi_pw_find_sv-expects-an-array-make-sure-we-ha.patch, NONE, 1.1 freeipa-change-mkey.patch, NONE, 1.1 freeipa-cve-2008-3274-fixes.patch, NONE, 1.1 freeipa-cve-2008-3274-utility.patch, NONE, 1.1 freeipa-encrypt-files.patch, NONE, 1.1 freeipa-fix-expire.patch, NONE, 1.1 freeipa-fix-key-encryption.patch, NONE, 1.1 freeipa-noi18n.patch, NONE, 1.1 freeipa-refresh-mkey.patch, NONE, 1.1 freeipa-user-input.patch, NONE, 1.1 ipa.spec, 1.13, 1.14

Robert Crittenden rcritten at fedoraproject.org
Thu Sep 11 02:58:19 UTC 2008


Author: rcritten

Update of /cvs/extras/rpms/ipa/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv4961

Modified Files:
	ipa.spec 
Added Files:
	0001-Fix-typo-in-inet-type.patch 
	0001-In-openvz-we-found-out-some-interfaces-may-return-a.patch 
	0001-slapi_pw_find_sv-expects-an-array-make-sure-we-ha.patch 
	freeipa-change-mkey.patch freeipa-cve-2008-3274-fixes.patch 
	freeipa-cve-2008-3274-utility.patch 
	freeipa-encrypt-files.patch freeipa-fix-expire.patch 
	freeipa-fix-key-encryption.patch freeipa-noi18n.patch 
	freeipa-refresh-mkey.patch freeipa-user-input.patch 
Log Message:
- Fix for CVE-2008-3274
- Fix segfault in ipa-kpasswd in case getifaddrs returns a NULL interface
- Add fix for bug #453185
- Rebuild against openldap libraries, mozldap ones do not work properly
- TurboGears is currently broken in rawhide. Added patch to not build
  the UI locales and removed them from the ipa-server files section.


0001-Fix-typo-in-inet-type.patch:

--- NEW FILE 0001-Fix-typo-in-inet-type.patch ---
>From 77906dce20a8d37b10225c4dc8701b25f172f362 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Mon, 9 Jun 2008 17:55:32 -0400
Subject: [PATCH] Fix typo in inet type

---
 ipa-server/ipa-kpasswd/ipa_kpasswd.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/ipa-server/ipa-kpasswd/ipa_kpasswd.c b/ipa-server/ipa-kpasswd/ipa_kpasswd.c
index 677b61b..72d3c13 100644
--- a/ipa-server/ipa-kpasswd/ipa_kpasswd.c
+++ b/ipa-server/ipa-kpasswd/ipa_kpasswd.c
@@ -1296,7 +1296,7 @@ int main(int argc, char *argv[])
 
 	for (tifa = ifa; tifa; tifa = tifa->ifa_next) {
 
-		if (tifa->ifa_addr->sa_family != PF_INET &&
+		if (tifa->ifa_addr->sa_family != AF_INET &&
 		    tifa->ifa_addr->sa_family != AF_INET6) {
 			/* not interesting for us */
 			continue;
-- 
1.5.5.1


0001-In-openvz-we-found-out-some-interfaces-may-return-a.patch:

--- NEW FILE 0001-In-openvz-we-found-out-some-interfaces-may-return-a.patch ---
>From 67f62709f83997945b69919cd744ce936ddf5596 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Tue, 15 Jul 2008 16:13:43 -0400
Subject: [PATCH] In openvz we found out some interfaces may return a null pointer here.
 Skip them if no address is provided or we later get a segfault because
 we dereference a null pointer.

---
 ipa-server/ipa-kpasswd/ipa_kpasswd.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/ipa-server/ipa-kpasswd/ipa_kpasswd.c b/ipa-server/ipa-kpasswd/ipa_kpasswd.c
index 7b4f39e..43ca223 100644
--- a/ipa-server/ipa-kpasswd/ipa_kpasswd.c
+++ b/ipa-server/ipa-kpasswd/ipa_kpasswd.c
@@ -1299,6 +1299,10 @@ int main(int argc, char *argv[])
 
 	for (tifa = ifa; tifa; tifa = tifa->ifa_next) {
 
+		if (NULL == tifa->ifa_addr)
+			/* uhmm no address ?? skip it */
+			continue;
+
 		if (tifa->ifa_addr->sa_family != AF_INET &&
 		    tifa->ifa_addr->sa_family != AF_INET6) {
 			/* not interesting for us */
-- 
1.5.5.1


0001-slapi_pw_find_sv-expects-an-array-make-sure-we-ha.patch:

--- NEW FILE 0001-slapi_pw_find_sv-expects-an-array-make-sure-we-ha.patch ---
>From 56a9569563b5dcc26a132d4ac91d940d34540a12 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Tue, 24 Jun 2008 08:40:58 -0400
Subject: [PATCH] slapi_pw_find_sv() expects an array, make sure we have a NULL terminated
 one to avoid potential segfaults
 Avoid leaking memory too.

---
 .../ipa-pwd-extop/ipa_pwd_extop.c                  |   14 +++++++++-----
 1 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
index 21e50db..c25d0f1 100644
--- a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
+++ b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
@@ -1258,24 +1258,28 @@ static int ipapwd_CheckPolicy(struct ipapwd_data *data)
 		/* skip policy checks */
 		slapi_entry_free(policy);
 		goto no_policy;
-	} 
+	}
 
 	/* first of all check current password, if any */
 	old_pw = slapi_entry_attr_get_charptr(data->target, "userPassword");
 	if (old_pw) {
-		Slapi_Value *cpw;
+		Slapi_Value *cpw[2] = {NULL, NULL};
 		Slapi_Value *pw;
 
-		cpw = slapi_value_new_string(old_pw);
+		cpw[0] = slapi_value_new_string(old_pw);
 		pw = slapi_value_new_string(data->password);
-		if (!cpw || !pw) {
+		if (!cpw[0] || !pw) {
 			slapi_log_error(SLAPI_LOG_PLUGIN, "ipa_pwd_extop",
 					"ipapwd_checkPassword: Out of Memory\n");
 			slapi_entry_free(policy);
+			slapi_value_free(&cpw[0]);
+			slapi_value_free(&pw);
 			return LDAP_OPERATIONS_ERROR;
 		}
 
-		ret = slapi_pw_find_sv(&cpw, pw);
+		ret = slapi_pw_find_sv(cpw, pw);
+		slapi_value_free(&cpw[0]);
+		slapi_value_free(&pw);
 
 		if (ret == 0) {
 			slapi_log_error(SLAPI_LOG_TRACE, "ipa_pwd_extop",
-- 
1.5.5.1


freeipa-change-mkey.patch:

--- NEW FILE freeipa-change-mkey.patch ---
>From ab6449e101d4282014a06ad3cd20961005fee2ce Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Wed, 6 Aug 2008 16:46:18 -0400
Subject: [PATCH] Add a tool to change the kerberos Master Key in case an admin wants to. This tool will dump and re-encrypt all keys, then reload and change the master key in LDAP and in the stash file. It will also restart the Directory Server and the the KDC

---
 ipa-admintools/Makefile              |    1 +
 ipa-admintools/ipa-change-master-key |  383 ++++++++++++++++++++++++++++++++++
 2 files changed, 384 insertions(+), 0 deletions(-)
 create mode 100644 ipa-admintools/ipa-change-master-key

diff --git a/ipa-admintools/Makefile b/ipa-admintools/Makefile
index 77cc38d..0b7cae8 100644
--- a/ipa-admintools/Makefile
+++ b/ipa-admintools/Makefile
@@ -26,6 +26,7 @@ install:
 	install -m 755 ipa-deldelegation $(SBINDIR)
 	install -m 755 ipa-listdelegation $(SBINDIR)
 	install -m 755 ipa-moddelegation $(SBINDIR)
+	install -m 755 ipa-change-master-key $(SBINDIR)
 
 	@for subdir in $(SUBDIRS); do \
 		(cd $$subdir && $(MAKE) $@) || exit 1; \
diff --git a/ipa-admintools/ipa-change-master-key b/ipa-admintools/ipa-change-master-key
new file mode 100644
index 0000000..233a7af
--- /dev/null
+++ b/ipa-admintools/ipa-change-master-key
@@ -0,0 +1,383 @@
+#! /usr/bin/python -E
+# Authors: Simo Sorce <ssorce at redhat.com>
+#
+# Copyright (C) 2007 Simo Sorce <ssorce at redhat.com>
+# 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 or later
+#
+# 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
+#
+
+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"
+
+password = ""
+
+import sys
+try:
+    from optparse import OptionParser
+    import ipa
+    import ipa.config
+    import ipa.ipautil
+    from ipaclient import ipachangeconf
+    from ipaserver import ipaldap
+
+    import krbV
+
+    import ldap
+    from ldap import LDAPError
+    from ldap import ldapobject
+
+    from pyasn1.type import univ, namedtype
+    import pyasn1.codec.ber.encoder
+    import pyasn1.codec.ber.decoder
+    import struct
+    import base64
+
+    import random
+    import time
+    import os
+    import shutil
+    import getpass
+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 usage():
+    print "ipa-change-master-key [-q|--quiet] [-p DM_PASSWORD]"
+    sys.exit(1)
+
+def parse_options():
+    parser = OptionParser()
+    parser.add_option("-p", "--dm-password", dest="dm_password",
+                      help="The Directory Manager password")
+    parser.add_option("-q", "--quiet", action="store_true", dest="quiet",
+                      help="Keep quiet")
+    parser.add_option("--usage", action="store_true",
+                      help="Program usage")
+
+    args = ipa.config.init_config(sys.argv)
+    options, args = parser.parse_args(args)
+
+    return options, args
+
+# 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 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 main():
+
+    global password
+
+    options, args = parse_options()
+
+    if options.usage:
+        usage()
+
+    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"
+
+    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
+
+    password = options.dm_password
+    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 options.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 options.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 options.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'"
+
+    #TODO: encrypt the backup/temp directory with the Directory Manager password
+
+    print "Master Password successfully changed"
+    print "You MUST now copy the stash file "+oldstashfile+" to all the replicas and restart them!"
+    print ""
+
+    return 0
+
+if __name__ == "__main__":
+    ret = 0
+    try:
+        ret = main()
+    except SystemExit, e:
+        ret = e
+    except KeyboardInterrupt, e:
+        ret = 1
+    except Exception, e:
+        print "%s" % str(e)
+        ret = 1
+
+    try:
+        msg = 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
+
+    sys.exit(ret)
-- 
1.5.5.1


freeipa-cve-2008-3274-fixes.patch:

--- NEW FILE freeipa-cve-2008-3274-fixes.patch ---
>From 7bd21c0d8b0c0889289c7e1eaeb21fb0f1d0c99f Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Fri, 15 Aug 2008 17:17:03 -0400
Subject: [PATCH] CVE 2008 3274 related fixes

---
 ipa-server/ipa-install/share/default-aci.ldif |    4 ++--
 ipa-server/ipaserver/krbinstance.py           |    8 +++++++-
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/ipa-server/ipa-install/share/default-aci.ldif b/ipa-server/ipa-install/share/default-aci.ldif
index d2946fa..25bd3b2 100644
--- a/ipa-server/ipa-install/share/default-aci.ldif
+++ b/ipa-server/ipa-install/share/default-aci.ldif
@@ -3,8 +3,8 @@
 dn: $SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";)
-aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Admin can manage any entry"; allow (all) userdn = "ldap:///uid=admin,cn=users,cn=accounts,$SUFFIX";)
+aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";)
+aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey")(version 3.0; acl "Admin can manage any entry"; allow (all) userdn = "ldap:///uid=admin,cn=users,cn=accounts,$SUFFIX";)
 aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword")(version 3.0; acl "Self can write own password"; allow (write) userdn="ldap:///self";)
 aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Admins can write passwords"; allow (add,delete,write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
 aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Password change service can read/write passwords"; allow (read, write) userdn="ldap:///krbprincipalname=kadmin/changepw@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";)
diff --git a/ipa-server/ipaserver/krbinstance.py b/ipa-server/ipaserver/krbinstance.py
index deea4a6..1668561 100644
--- a/ipa-server/ipaserver/krbinstance.py
+++ b/ipa-server/ipaserver/krbinstance.py
@@ -48,6 +48,10 @@
 import struct
 import base64
 
+KRBMKEY_DENY_ACI = """
+(targetattr = "krbMKey")(version 3.0; acl "No external access"; deny (all) userdn != "ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
+"""
+
 def update_key_val_in_file(filename, key, val):
     if os.path.exists(filename):
         pattern = "^[\s#]*%s\s*=\s*%s\s*" % (re.escape(key), re.escape(val))
@@ -358,7 +362,9 @@
 
         entry = ipaldap.Entry("cn="+self.realm+",cn=kerberos,"+self.suffix)
         dn = "cn="+self.realm+",cn=kerberos,"+self.suffix
-        mod = [(ldap.MOD_ADD, 'krbMKey', str(asn1key))]
+        #protect the master key by adding an appropriate deny rule along with the key
+        mod = [(ldap.MOD_ADD, 'aci', ipautil.template_str(KRBMKEY_DENY_ACI, self.sub_dict)),
+               (ldap.MOD_ADD, 'krbMKey', str(asn1key))]
         try:
             self.conn.modify_s(dn, mod)
         except ldap.TYPE_OR_VALUE_EXISTS, e:

freeipa-cve-2008-3274-utility.patch:

--- NEW FILE freeipa-cve-2008-3274-utility.patch ---
>From 40749e3ea6b727fa8c60e2d2af44a0e5ac725936 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Tue, 19 Aug 2008 13:31:26 -0400
Subject: [PATCH] Add script to simplify operations to fix CVE 2008 3274
 Import all of change master key directly into the help fix,
 allows for better control

---
 ipa-server/Makefile.am           |    1 +
 ipa-server/ipa-fix-CVE-2008-3274 |  520 ++++++++++++++++++++++++++++++++++++++
 ipa-server/ipa-server.spec.in    |    1 +
 3 files changed, 522 insertions(+), 0 deletions(-)
 create mode 100644 ipa-server/ipa-fix-CVE-2008-3274

diff --git a/ipa-server/Makefile.am b/ipa-server/Makefile.am
index 6fb854d..f058013 100644
--- a/ipa-server/Makefile.am
+++ b/ipa-server/Makefile.am
@@ -16,6 +16,7 @@ SUBDIRS =			\
 
 sbin_SCRIPTS =			\
 	ipa-upgradeconfig	\
+	ipa-fix-CVE-2008-3274	\
 	$(NULL)
 
 install-exec-local:
diff --git a/ipa-server/ipa-fix-CVE-2008-3274 b/ipa-server/ipa-fix-CVE-2008-3274
new file mode 100644
index 0000000..171a9db
--- /dev/null
+++ b/ipa-server/ipa-fix-CVE-2008-3274
@@ -0,0 +1,518 @@
+#!/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 usage():
+    print "ipa-fix-CVE-2008-3274 [--check] [--fix] [--fix-replica]"
+    sys.exit(1)
+
+def parse_options():
+    parser = OptionParser()
+    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")
+    parser.add_option("--usage", action="store_true",
+                      help="Program usage")
+
+    args = ipa.config.init_config(sys.argv)
+    options, args = parser.parse_args(args)
+
+    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"
+
+    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 ""
+
+    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.usage:
+        usage()
+
+    if not options.fix and not options.fix_replica and not options.check:
+        print "use --help for more info"
+        usage()
+
+    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/ipa-server/ipa-server.spec.in b/ipa-server/ipa-server.spec.in
index f8de8aa..2a79de0 100644
--- a/ipa-server/ipa-server.spec.in
+++ b/ipa-server/ipa-server.spec.in
@@ -123,6 +123,7 @@ fi
 %{_sbindir}/ipa_kpasswd
 %{_sbindir}/ipa_webgui
 %{_sbindir}/ipa-upgradeconfig
+%{_sbindir}/ipa-fix-CVE-2008-3274
 %attr(755,root,root) %{_initrddir}/ipa_kpasswd
 %attr(755,root,root) %{_initrddir}/ipa_webgui
 
-- 
1.5.5.1


freeipa-encrypt-files.patch:

--- NEW FILE freeipa-encrypt-files.patch ---
>From 5cbc453d89af0ef79b7c99849778f1982abeda05 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Thu, 7 Aug 2008 16:14:37 -0400
Subject: [PATCH] Add encrypt_file and decrypt_file utility functions.
 We will use them to encrypt the replica file so that we can
 transport it over more safely.
 It contains sensitive data, by encrypting it we assure that
 even if a distracted admin leaves it around it cannot be accessed
 without knowing the access passphrase (usually the Directory Manager
 password)

Along the way fix also ipautil.run which was buggy and not passing
in correctly stdin.

Add dependency for gnupg in spec file
---
 ipa-python/ipa-python.spec.in |    2 +-
 ipa-python/ipautil.py         |   65 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/ipa-python/ipa-python.spec.in b/ipa-python/ipa-python.spec.in
index 7d270b4..7744649 100755
--- a/ipa-python/ipa-python.spec.in
+++ b/ipa-python/ipa-python.spec.in
@@ -10,7 +10,7 @@ Source0:        http://www.freeipa.org/downloads/%{name}-%{version}.tgz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 BuildArch: 	noarch
 BuildRequires:  python-devel
-Requires:       python-kerberos
+Requires:       python-kerberos gnupg
 
 %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
 
diff --git a/ipa-python/ipautil.py b/ipa-python/ipautil.py
index 117171c..649a3f2 100644
--- a/ipa-python/ipautil.py
+++ b/ipa-python/ipautil.py
@@ -73,11 +73,13 @@ def write_tmp_file(txt):
     return fd
 
 def run(args, stdin=None):
-    p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
     if stdin:
+        p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
         stdout,stderr = p.communicate(stdin)
     else:
+        p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
         stdout,stderr = p.communicate()
+
     logging.info(stdout)
     logging.info(stderr)
 
@@ -115,6 +117,67 @@ def backup_file(fname):
     if file_exists(fname):
         os.rename(fname, fname + ".orig")
 
+# uses gpg to compress and encrypt a file
+def encrypt_file(source, dest, password, workdir = None):
+    if type(source) is not StringType or not len(source):
+        raise ValueError('Missing Source File')
+    #stat it so that we get back an exception if it does no t exist
+    os.stat(source)
+
+    if type(dest) is not StringType or not len(dest):
+        raise ValueError('Missing Destination File')
+
+    if type(password) is not StringType or not len(password):
+        raise ValueError('Missing Password')
+
+    #create a tempdir so that we can clean up with easily
+    tempdir = tempfile.mkdtemp('', 'ipa-', workdir)
+    gpgdir = tempdir+"/.gnupg"
+
+    try:
+        try:
+            #give gpg a fake dir so that we can leater remove all
+            #the cruft when we clean up the tempdir
+            os.mkdir(gpgdir)
+            args = ['/usr/bin/gpg', '--homedir', gpgdir, '--passphrase-fd', '0', '--yes', '--no-tty', '-o', dest, '-c', source]
+            run(args, password)
+        except:
+            raise
+    finally:
+        #job done, clean up
+        shutil.rmtree(tempdir, ignore_errors=True)
+
+
+def decrypt_file(source, dest, password, workdir = None):
+    if type(source) is not StringType or not len(source):
+        raise ValueError('Missing Source File')
+    #stat it so that we get back an exception if it does no t exist
+    os.stat(source)
+
+    if type(dest) is not StringType or not len(dest):
+        raise ValueError('Missing Destination File')
+
+    if type(password) is not StringType or not len(password):
+        raise ValueError('Missing Password')
+
+    #create a tempdir so that we can clean up with easily
+    tempdir = tempfile.mkdtemp('', 'ipa-', workdir)
+    gpgdir = tempdir+"/.gnupg"
+
+    try:
+        try:
+            #give gpg a fake dir so that we can leater remove all
+            #the cruft when we clean up the tempdir
+            os.mkdir(gpgdir)
+            args = ['/usr/bin/gpg', '--homedir', gpgdir, '--passphrase-fd', '0', '--yes', '--no-tty', '-o', dest, '-d', source]
+            run(args, password)
+        except:
+            raise
+    finally:
+        #job done, clean up
+        shutil.rmtree(tempdir, ignore_errors=True)
+
+
 class CIDict(dict):
     """
     Case-insensitive but case-respecting dictionary.
-- 
1.5.5.1


freeipa-fix-expire.patch:

--- NEW FILE freeipa-fix-expire.patch ---
>From cb641d756f0b3e55cc795cacbf122d7b0a6b1c77 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Wed, 6 Aug 2008 17:22:51 -0400
Subject: [PATCH] Treat Jan 1 1970 in krbPrincipalExpiration as a special date that means the account Never Expires

---
 .../ipa-pwd-extop/ipa_pwd_extop.c                  |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
index be440e8..56003f2 100644
--- a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
+++ b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
@@ -1240,10 +1240,11 @@ static int ipapwd_CheckPolicy(struct ipapwd_data *data)
 	int tmp, ret;
 	const char *old_pw;
 
-	/* check account is not expired */
+	/* check account is not expired. Ignore unixtime = 0 (Jan 1 1970) */
 	krbPrincipalExpiration = slapi_entry_attr_get_charptr(data->target, "krbPrincipalExpiration");
-	if (krbPrincipalExpiration) {
-		/* if expiration date set check it */
+	if (krbPrincipalExpiration &&
+	    (strcasecmp("19700101000000Z", krbPrincipalExpiration) != 0)) {
+		/* if expiration date is set check it */
 		memset(&tm, 0, sizeof(struct tm));
 		ret = sscanf(krbPrincipalExpiration,
 			     "%04u%02u%02u%02u%02u%02u",
@@ -1261,6 +1262,7 @@ static int ipapwd_CheckPolicy(struct ipapwd_data *data)
 		}
 		/* FIXME: else error out ? */
 	}
+	slapi_ch_free_string(&krbPrincipalExpiration);
 
 	/* find the entry with the password policy */
 	ret = ipapwd_getPolicy(data->dn, data->target, &policy);
-- 
1.5.5.1


freeipa-fix-key-encryption.patch:

--- NEW FILE freeipa-fix-key-encryption.patch ---
>From c5b44f77a1a2fcc19312dc2d5ad2a46836c936a2 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Tue, 12 Aug 2008 16:11:16 -0400
Subject: [PATCH] Comment out code that generates keys with a random salt, apparently this does not work as expected and generates faulty keys

---
 .../ipa-pwd-extop/ipa_pwd_extop.c                  |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
index 1697fb5..909476b 100644
--- a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
+++ b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
@@ -582,6 +582,7 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data
 			 * we have to use a more conservative approach and set the salt
 			 * to be REALMprincipal (the concatenation of REALM and principal
 			 * name without any separator) */
+#if 0
 			if (krbTicketFlags & KTF_REQUIRES_PRE_AUTH) {
 				salt.length = KRB5P_SALT_SIZE;
 				salt.data = malloc(KRB5P_SALT_SIZE);
@@ -598,6 +599,7 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data
 					goto enc_error;
 				}
 			} else {
+#endif
 				krberr = krb5_principal2salt(krbctx, princ, &salt);
 				if (krberr) {
 					slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop",
@@ -605,7 +607,9 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data
 							krb5_get_error_message(krbctx, krberr));
 					goto enc_error;
 				}
+#if 0
 			}
+#endif
 			break;
 
 		case KRB5_KDB_SALTTYPE_V4:
-- 
1.5.5.1


freeipa-noi18n.patch:

--- NEW FILE freeipa-noi18n.patch ---
diff -u --recursive freeipa-1.1.0.orig/ipa-server/ipa-gui/Makefile.am freeipa-1.1.0/ipa-server/ipa-gui/Makefile.am
--- freeipa-1.1.0.orig/ipa-server/ipa-gui/Makefile.am	2008-06-11 10:24:28.000000000 -0400
+++ freeipa-1.1.0/ipa-server/ipa-gui/Makefile.am	2008-09-10 22:13:53.000000000 -0400
@@ -14,7 +14,7 @@
 	ipa_webgui.cfg		\
 	$(NULL)
 
-LINGUAS = ja
+#LINGUAS = ja
 
 mo = $(foreach lang,$(LINGUAS),locales/$(lang)/LC_MESSAGES/messages.mo)
 po = $(foreach lang,$(LINGUAS),locales/$(lang)/LC_MESSAGES/messages.po)

freeipa-refresh-mkey.patch:

--- NEW FILE freeipa-refresh-mkey.patch ---
>From aad877939879b9c5781d90921d5867e48506b223 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Fri, 22 Aug 2008 15:03:50 -0400
Subject: [PATCH] Retrieve the kerberos configuration every time a new, it will be a bit slower
 but will allow for changing configurations without having to restart DS.
 Password operations are slow and rare enough this is an acceptable compromise.

---
 .../ipa-pwd-extop/ipa_pwd_extop.c                  |  482 ++++++++++----------
 1 files changed, 236 insertions(+), 246 deletions(-)

diff --git a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
index eae63da..9b746a9 100644
--- a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
+++ b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
@@ -137,27 +137,42 @@ struct ipapwd_encsalt {
 	krb5_int32	salt_type;
 };
 
-struct ipapwd_config {
-	char *realm;
-	krb5_keyblock *kmkey;
-	int num_supp_encsalts;
-	struct ipapwd_encsalt *supp_encsalts;
-	int num_pref_encsalts;
-	struct ipapwd_encsalt *pref_encsalts;
-};
-
 static const char *ipa_realm_dn = NULL;
 
 Slapi_Mutex *ipa_globals = NULL;
 
-static struct ipapwd_config *ipapwd_config = NULL;
-
 static void *ipapwd_plugin_id;
 
 #define IPA_CHANGETYPE_NORMAL 0
 #define IPA_CHANGETYPE_ADMIN 1
 #define IPA_CHANGETYPE_DSMGR 2
 
+struct ipapwd_krbcfg {
+    krb5_context krbctx;
+    char *realm;
+    krb5_keyblock *kmkey;
+    int num_supp_encsalts;
+    struct ipapwd_encsalt *supp_encsalts;
+    int num_pref_encsalts;
+    struct ipapwd_encsalt *pref_encsalts;
+};
+
+static void free_ipapwd_krbcfg(struct ipapwd_krbcfg **cfg)
+{
+    struct ipapwd_krbcfg *c = *cfg;
+
+    if (!c) return;
+
+    krb5_free_default_realm(c->krbctx, c->realm);
+    krb5_free_context(c->krbctx);
+    free(c->kmkey->contents);
+    free(c->kmkey);
+    free(c->supp_encsalts);
+    free(c->pref_encsalts);
+    free(c);
+    *cfg = NULL;
+};
+
 struct ipapwd_data {
 	Slapi_Entry *target;
 	const char *dn;
@@ -218,23 +233,18 @@ static void ipapwd_keyset_free(struct ipapwd_keyset **pkset)
 	*pkset = NULL;
 }
 
-static int filter_keys(struct ipapwd_keyset *kset)
+static int filter_keys(struct ipapwd_krbcfg *krbcfg, struct ipapwd_keyset *kset)
 {
-	struct ipapwd_config *config;
 	int i, j;
 
-	slapi_lock_mutex(ipa_globals);
-	config = ipapwd_config;
-	slapi_unlock_mutex(ipa_globals);
-
 	for (i = 0; i < kset->num_keys; i++) {
-		for (j = 0; j < config->num_supp_encsalts; j++) {
+		for (j = 0; j < krbcfg->num_supp_encsalts; j++) {
 			if (kset->keys[i].ekey->type ==
-					config->supp_encsalts[j].enc_type) {
+					krbcfg->supp_encsalts[j].enc_type) {
 				break;
 			}
 		}
-		if (j == config->num_supp_encsalts) { /* not valid */
+		if (j == krbcfg->num_supp_encsalts) { /* not valid */
 
 			/* free key */
 			if (kset->keys[i].ekey) {
@@ -458,9 +468,10 @@ static inline void encode_int16(unsigned int val, unsigned char *p)
 	p[0] = (val      ) & 0xff;
 }
 
-static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data *data)
+static Slapi_Value **encrypt_encode_key(struct ipapwd_krbcfg *krbcfg,
+					struct ipapwd_data *data)
 {
-	struct ipapwd_config *config;
+	krb5_context krbctx;
 	const char *krbPrincipalName;
 	uint32_t krbMaxTicketLife;
 	int kvno, i;
@@ -472,9 +483,7 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data
 	krb5_data pwd;
 	struct ipapwd_keyset *kset = NULL;
 
-	slapi_lock_mutex(ipa_globals);
-	config = ipapwd_config;
-	slapi_unlock_mutex(ipa_globals);
+	krbctx = krbcfg->krbctx;
 
 	svals = (Slapi_Value **)calloc(2, sizeof(Slapi_Value *));
 	if (!svals) {
@@ -524,7 +533,7 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data
 	/* we also assum mkvno is 0 */
 	kset->mkvno = 0;
 
-	kset->num_keys = config->num_pref_encsalts;
+	kset->num_keys = krbcfg->num_pref_encsalts;
 	kset->keys = calloc(kset->num_keys, sizeof(struct ipapwd_krbkey));
 	if (!kset->keys) {
 		slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop", "malloc failed!\n");
@@ -542,7 +551,7 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data
 
 		salt.data = NULL;
 
-		switch (config->pref_encsalts[i].salt_type) {
+		switch (krbcfg->pref_encsalts[i].salt_type) {
 
 		case KRB5_KDB_SALTTYPE_ONLYREALM:
 
@@ -629,12 +638,12 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data
 
 		default:
 			slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop",
-					"Invalid salt type [%d]\n", config->pref_encsalts[i].salt_type);
+					"Invalid salt type [%d]\n", krbcfg->pref_encsalts[i].salt_type);
 			goto enc_error;
 		}
 
 		/* need to build the key now to manage the AFS salt.length special case */
-		krberr = krb5_c_string_to_key(krbctx, config->pref_encsalts[i].enc_type, &pwd, &salt, &key);
+		krberr = krb5_c_string_to_key(krbctx, krbcfg->pref_encsalts[i].enc_type, &pwd, &salt, &key);
 		if (krberr) {
 			slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop",
 					"krb5_c_string_to_key failed [%s]\n",
@@ -646,7 +655,7 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data
 			salt.length = strlen(salt.data);
 		}
 
-		krberr = krb5_c_encrypt_length(krbctx, config->kmkey->enctype, key.length, &len);
+		krberr = krb5_c_encrypt_length(krbctx, krbcfg->kmkey->enctype, key.length, &len);
 		if (krberr) {
 			slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop",
 					"krb5_c_string_to_key failed [%s]\n",
@@ -672,7 +681,7 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data
 		cipher.ciphertext.length = len;
 		cipher.ciphertext.data = (char *)ptr+2;
 
-		krberr = krb5_c_encrypt(krbctx, config->kmkey, 0, 0, &plain, &cipher);
+		krberr = krb5_c_encrypt(krbctx, krbcfg->kmkey, 0, 0, &plain, &cipher);
 		if (krberr) {
 			slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop",
 					"krb5_c_encrypt failed [%s]\n",
@@ -692,7 +701,7 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data
 			goto enc_error;
 		}
 
-		kset->keys[i].salt->type = config->pref_encsalts[i].salt_type;
+		kset->keys[i].salt->type = krbcfg->pref_encsalts[i].salt_type;
 
 		if (salt.length) {
 			kset->keys[i].salt->value.bv_len = salt.length;
@@ -1633,7 +1642,8 @@ static void hexbuf(char *out, const uint8_t *in)
 }
 
 /* Modify the Password attributes of the entry */
-static int ipapwd_SetPassword(struct ipapwd_data *data)
+static int ipapwd_SetPassword(struct ipapwd_krbcfg *krbcfg,
+				struct ipapwd_data *data)
 {
 	int ret = 0, i = 0;
 	Slapi_Mods *smods;
@@ -1648,26 +1658,17 @@ static int ipapwd_SetPassword(struct ipapwd_data *data)
 	int ntlm_flags = 0;
 	Slapi_Value *sambaSamAccount;
 
-	krberr = krb5_init_context(&krbctx);
-	if (krberr) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop", "krb5_init_context failed\n");
-		return LDAP_OPERATIONS_ERROR;
-	}
-
 	slapi_log_error(SLAPI_LOG_TRACE, "ipa_pwd_extop", "=> ipapwd_SetPassword\n");
 
 	smods = slapi_mods_new();
 
 	/* generate kerberos keys to be put into krbPrincipalKey */
-	svals = encrypt_encode_key(krbctx, data);
+	svals = encrypt_encode_key(krbcfg, data);
 	if (!svals) {
 		slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop", "key encryption/encoding failed\n");
-		krb5_free_context(krbctx);
 		ret = LDAP_OPERATIONS_ERROR;
 		goto free_and_return;
 	}
-	/* done with it */
-	krb5_free_context(krbctx);
 
 	slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE, "krbPrincipalKey", svals);
 
@@ -1756,7 +1757,7 @@ free_and_return:
 	return ret;
 }
 
-static int ipapwd_chpwop(Slapi_PBlock *pb)
+static int ipapwd_chpwop(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
 {
 	char 		*bindDN = NULL;
 	char		*authmethod = NULL;
@@ -1772,11 +1773,6 @@ static int ipapwd_chpwop(Slapi_PBlock *pb)
 	Slapi_Entry *targetEntry=NULL;
 	char *attrlist[] = {"*", "passwordHistory", NULL };
 	struct ipapwd_data pwdata;
-	struct ipapwd_config *config;
-
-	slapi_lock_mutex(ipa_globals);
-	config = ipapwd_config;
-	slapi_unlock_mutex(ipa_globals);
 
 	/* Get the ber value of the extended operation */
 	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
@@ -1973,7 +1969,7 @@ parse_req_done:
 		if (bindexp) {
 			/* special case kpasswd and Directory Manager */
 			if ((strncasecmp(bindexp[0], "krbprincipalname=kadmin/changepw@", 33) == 0) &&
-			    (strcasecmp(&(bindexp[0][33]), config->realm) == 0)) {
+			    (strcasecmp(&(bindexp[0][33]), krbcfg->realm) == 0)) {
 				pwdata.changetype = IPA_CHANGETYPE_NORMAL;
 			}
 			if ((strcasecmp(bindexp[0], "cn=Directory Manager") == 0) &&
@@ -1999,7 +1995,7 @@ parse_req_done:
 	}
 
 	/* Now we're ready to set the kerberos key material */
-	ret = ipapwd_SetPassword(&pwdata);
+	ret = ipapwd_SetPassword(krbcfg, &pwdata);
 	if (ret != LDAP_SUCCESS) {
 		/* Failed to modify the password,
 		 * e.g. because insufficient access allowed */
@@ -2037,9 +2033,8 @@ free_and_return:
 }
 
 /* Password Modify Extended operation plugin function */
-static int ipapwd_setkeytab(Slapi_PBlock *pb)
+static int ipapwd_setkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
 {
-	struct ipapwd_config *config;
 	char *bindDN = NULL;
 	char *serviceName = NULL;
 	char *errMesg = NULL;
@@ -2071,10 +2066,6 @@ static int ipapwd_setkeytab(Slapi_PBlock *pb)
 	char timestr[GENERALIZED_TIME_LENGTH+1];
 	time_t time_now = time(NULL);
 
-	slapi_lock_mutex(ipa_globals);
-	config = ipapwd_config;
-	slapi_unlock_mutex(ipa_globals);
-
 	svals = (Slapi_Value **)calloc(2, sizeof(Slapi_Value *));
 	if (!svals) {
 		slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop",
@@ -2333,7 +2324,7 @@ static int ipapwd_setkeytab(Slapi_PBlock *pb)
 		plain.length = tval.bv_len;
 		plain.data = tval.bv_val;
 
-		krberr = krb5_c_encrypt_length(krbctx, config->kmkey->enctype, plain.length, &klen);
+		krberr = krb5_c_encrypt_length(krbctx, krbcfg->kmkey->enctype, plain.length, &klen);
 		if (krberr) {
 			free(tval.bv_val);
 			slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop", "krb encryption failed!\n");
@@ -2354,7 +2345,7 @@ static int ipapwd_setkeytab(Slapi_PBlock *pb)
 		cipher.ciphertext.length = klen;
 		cipher.ciphertext.data = (char *)kdata + 2;
 
-		krberr = krb5_c_encrypt(krbctx, config->kmkey, 0, 0, &plain, &cipher);
+		krberr = krb5_c_encrypt(krbctx, krbcfg->kmkey, 0, 0, &plain, &cipher);
 		if (krberr) {
 			free(tval.bv_val);
 			slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop", "krb encryption failed!\n");
@@ -2421,7 +2412,7 @@ static int ipapwd_setkeytab(Slapi_PBlock *pb)
 	ber = NULL;
 
 	/* filter un-supported encodings */
-	ret = filter_keys(kset);
+	ret = filter_keys(krbcfg, kset);
 	if (ret) {
 		slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop",
 				"keyset filtering failed\n");
@@ -2620,168 +2620,182 @@ static int new_ipapwd_encsalt(krb5_context krbctx, const char * const *encsalts,
 	return LDAP_SUCCESS;
 }
 
-static int ipapwd_getConfig(krb5_context krbctx, const char *realm_dn)
+static struct ipapwd_krbcfg *ipapwd_getConfig(const char *realm_dn)
 {
-	struct ipapwd_config *config = NULL;
-	krb5_keyblock *kmkey = NULL;
-	Slapi_Entry *realm_entry = NULL;
-	Slapi_Attr *a;
-	Slapi_Value *v;
-	BerElement *be = NULL;
-	ber_tag_t tag, tmp;
-	ber_int_t ttype;
-	const struct berval *bval;
-	struct berval *mkey = NULL;
-	char **encsalts;
-	int ret;
-
-	config = malloc(sizeof(struct ipapwd_config));
-	if (!config) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-				"Out of memory!\n");
-		goto free_and_error;
-	}
-	kmkey = malloc(sizeof(krb5_keyblock));
-	if (!kmkey) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-				"Out of memory!\n");
-		goto free_and_error;
-	}
-	config->kmkey = kmkey;
-
-	ret = krb5_get_default_realm(krbctx, &config->realm);
-	if (ret) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-				"Failed to get default realm?!\n");
-		goto free_and_error;
-	}
-
-
-	/* get the Realm Container entry */
-	ret = ipapwd_getEntry(realm_dn, &realm_entry, NULL);
-	if (ret != LDAP_SUCCESS) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-				"No realm Entry?\n");
-		goto free_and_error;
-	}
-
-	/*** get the Kerberos Master Key ***/
+    krb5_error_code krberr;
+    struct ipapwd_krbcfg *config = NULL;
+    krb5_keyblock *kmkey = NULL;
+    Slapi_Entry *realm_entry = NULL;
+    Slapi_Attr *a;
+    Slapi_Value *v;
+    BerElement *be = NULL;
+    ber_tag_t tag, tmp;
+    ber_int_t ttype;
+    const struct berval *bval;
+    struct berval *mkey = NULL;
+    char **encsalts;
+    int ret;
+
+    config = calloc(1, sizeof(struct ipapwd_krbcfg));
+    if (!config) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "Out of memory!\n");
+        goto free_and_error;
+    }
+    kmkey = calloc(1, sizeof(krb5_keyblock));
+    if (!kmkey) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "Out of memory!\n");
+        goto free_and_error;
+    }
+    config->kmkey = kmkey;
+
+    krberr = krb5_init_context(&config->krbctx);
+    if (krberr) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "krb5_init_context failed\n");
+        goto free_and_error;
+    }
+
+    ret = krb5_get_default_realm(config->krbctx, &config->realm);
+    if (ret) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "Failed to get default realm?!\n");
+        goto free_and_error;
+    }
+
+    /* get the Realm Container entry */
+    ret = ipapwd_getEntry(realm_dn, &realm_entry, NULL);
+    if (ret != LDAP_SUCCESS) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "No realm Entry?\n");
+        goto free_and_error;
+    }
+
+    /*** get the Kerberos Master Key ***/
+
+    ret = slapi_entry_attr_find(realm_entry, "krbMKey", &a);
+    if (ret == -1) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "No master key??\n");
+        goto free_and_error;
+    }
+
+    /* there should be only one value here */
+    ret = slapi_attr_first_value(a, &v);
+    if (ret == -1) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "No master key??\n");
+        goto free_and_error;
+    }
+
+    bval = slapi_value_get_berval(v);
+    if (!bval) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "Error retrieving master key berval\n");
+        goto free_and_error;
+    }
+
+    be = ber_init(bval);
+    if (!bval) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "ber_init() failed!\n");
+        goto free_and_error;
+    }
+
+    tag = ber_scanf(be, "{i{iO}}", &tmp, &ttype, &mkey);
+    if (tag == LBER_ERROR) {
+        slapi_log_error(SLAPI_LOG_TRACE, "ipapwd_getConfig",
+                        "Bad Master key encoding ?!\n");
+        goto free_and_error;
+    }
+
+    kmkey->magic = KV5M_KEYBLOCK;
+    kmkey->enctype = ttype;
+    kmkey->length = mkey->bv_len;
+    kmkey->contents = malloc(mkey->bv_len);
+    if (!kmkey->contents) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "Out of memory!\n");
+        goto free_and_error;
+    }
+    memcpy(kmkey->contents, mkey->bv_val, mkey->bv_len);
+    ber_bvfree(mkey);
+    ber_free(be, 1);
+    mkey = NULL;
+    be = NULL;
+
+    /*** get the Supported Enc/Salt types ***/
+
+    encsalts = slapi_entry_attr_get_charray(realm_entry, "krbSupportedEncSaltTypes");
+    if (encsalts) {
+        ret = new_ipapwd_encsalt(config->krbctx,
+                                 (const char * const *)encsalts,
+                                 &config->supp_encsalts,
+                                 &config->num_supp_encsalts);
+        slapi_ch_array_free(encsalts);
+    } else {
+        slapi_log_error(SLAPI_LOG_TRACE, "ipapwd_getConfig",
+                        "No configured salt types use defaults\n");
+        ret = new_ipapwd_encsalt(config->krbctx,
+                                 ipapwd_def_encsalts,
+                                 &config->supp_encsalts,
+                                 &config->num_supp_encsalts);
+    }
+    if (ret) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "Can't get Supported EncSalt Types\n");
+        goto free_and_error;
+    }
+
+    /*** get the Preferred Enc/Salt types ***/
+
+    encsalts = slapi_entry_attr_get_charray(realm_entry, "krbDefaultEncSaltTypes");
+    if (encsalts) {
+        ret = new_ipapwd_encsalt(config->krbctx,
+                                 (const char * const *)encsalts,
+                                 &config->pref_encsalts,
+                                 &config->num_pref_encsalts);
+        slapi_ch_array_free(encsalts);
+    } else {
+        slapi_log_error(SLAPI_LOG_TRACE, "ipapwd_getConfig",
+                        "No configured salt types use defaults\n");
+        ret = new_ipapwd_encsalt(config->krbctx,
+                                 ipapwd_def_encsalts,
+                                 &config->pref_encsalts,
+                                 &config->num_pref_encsalts);
+    }
+    if (ret) {
+        slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_getConfig",
+                        "Can't get Preferred EncSalt Types\n");
+        goto free_and_error;
+    }
 
-	ret = slapi_entry_attr_find(realm_entry, "krbMKey", &a);
-	if (ret == -1) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-				"No master key??\n");
-		goto free_and_error;
-	}
-
-	/* there should be only one value here */
-	ret = slapi_attr_first_value(a, &v);
-	if (ret == -1) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-				"No master key values??\n");
-		goto free_and_error;
-	}
-
-	bval = slapi_value_get_berval(v);
-	if (!bval) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-				"Error retrieving master key berval\n");
-		goto free_and_error;
-	}
-
-	be = ber_init(bval);
-	if (!bval) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-				"ber_init() failed!\n");
-		goto free_and_error;
-	}
-
-	tag = ber_scanf(be, "{i{iO}}", &tmp, &ttype, &mkey);
-	if (tag == LBER_ERROR) {
-		slapi_log_error(SLAPI_LOG_TRACE, "ipapwd_start",
-				"Bad Master key encoding ?!\n");
-		goto free_and_error;
-	}
+    slapi_entry_free(realm_entry);
 
-	kmkey->magic = KV5M_KEYBLOCK;
-	kmkey->enctype = ttype;
-	kmkey->length = mkey->bv_len;
-	kmkey->contents = malloc(mkey->bv_len);
-	if (!kmkey->contents) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-				"Out of memory!\n");
-		goto free_and_error;
-	}
-	memcpy(kmkey->contents, mkey->bv_val, mkey->bv_len);
-	ber_bvfree(mkey);
-	ber_free(be, 1);
-
-	/*** get the Supported Enc/Salt types ***/
-
-	encsalts = slapi_entry_attr_get_charray(realm_entry, "krbSupportedEncSaltTypes");
-	if (encsalts) {
-		ret = new_ipapwd_encsalt(krbctx, (const char * const *)encsalts,
-					 &config->supp_encsalts,
-					 &config->num_supp_encsalts);
-		slapi_ch_array_free(encsalts);
-	} else {
-		slapi_log_error(SLAPI_LOG_TRACE, "ipapwd_start",
-				"No configured salt types use defaults\n");
-		ret = new_ipapwd_encsalt(krbctx, ipapwd_def_encsalts,
-					 &config->supp_encsalts,
-					 &config->num_supp_encsalts);
-	}
-	if (ret) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-				"Can't get Supported EncSalt Types\n");
-		goto free_and_error;
-	}
-
-	/*** get the Preferred Enc/Salt types ***/
-
-	encsalts = slapi_entry_attr_get_charray(realm_entry, "krbDefaultEncSaltTypes");
-	if (encsalts) {
-		ret = new_ipapwd_encsalt(krbctx, (const char * const *)encsalts,
-					 &config->pref_encsalts,
-					 &config->num_pref_encsalts);
-		slapi_ch_array_free(encsalts);
-	} else {
-		slapi_log_error(SLAPI_LOG_TRACE, "ipapwd_start",
-				"No configured salt types use defaults\n");
-		ret = new_ipapwd_encsalt(krbctx, ipapwd_def_encsalts,
-					 &config->pref_encsalts,
-					 &config->num_pref_encsalts);
-	}
-	if (ret) {
-		slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-				"Can't get Preferred EncSalt Types\n");
-		goto free_and_error;
-	}
-
-	/*** set config/replace old config ***/
-
-	/* FIXME: free old one in a safe way, use read locks ? */
-	slapi_lock_mutex(ipa_globals);
-	ipapwd_config = config;
-	slapi_unlock_mutex(ipa_globals);
-
-	slapi_entry_free(realm_entry);
-	return LDAP_SUCCESS;
+    return config;
 
 free_and_error:
-	if (mkey) ber_bvfree(mkey);
-	if (be) ber_free(be, 1);
-	free(config->pref_encsalts);
-	free(config->supp_encsalts);
-	free(config->kmkey);
-	free(config);
-	if (realm_entry) slapi_entry_free(realm_entry);
-	return LDAP_OPERATIONS_ERROR;
+    if (mkey) ber_bvfree(mkey);
+    if (be) ber_free(be, 1);
+    if (kmkey) {
+        free(kmkey->contents);
+        free(kmkey);
+    }
+    if (config) {
+        if (config->krbctx) krb5_free_context(config->krbctx);
+        free(config->pref_encsalts);
+        free(config->supp_encsalts);
+        free(config);
+    }
+    if (realm_entry) slapi_entry_free(realm_entry);
+    return NULL;
 }
 
 
 static int ipapwd_extop(Slapi_PBlock *pb)
 {
+  	struct ipapwd_krbcfg *krbcfg = NULL;
 	char *oid = NULL;
 	char *errMesg = NULL;
 	int ret=0, rc=0, sasl_ssf=0, is_ssl=0;
@@ -2835,30 +2841,6 @@ static int ipapwd_extop(Slapi_PBlock *pb)
 	}
 #endif
 
-	/* make sure we have the master key */
-	if (ipapwd_config == NULL) {
-		krb5_context krbctx;
-		krb5_error_code krberr;
-
-		krberr = krb5_init_context(&krbctx);
-		if (krberr) {
-			slapi_log_error(SLAPI_LOG_FATAL, "ipapwd_start",
-					"krb5_init_context failed\n");
-			errMesg = "Fatal Internal Error";
-			rc = LDAP_OPERATIONS_ERROR;
-			goto free_and_return;
-		}
-		ret = ipapwd_getConfig(krbctx, ipa_realm_dn);
-		if (ret != LDAP_SUCCESS) {
-			slapi_log_error(SLAPI_LOG_PLUGIN, "ipa_pwd_extop",
-					"Error Retrieving Master Key");
-			errMesg = "Fatal Internal Error";
-			rc = LDAP_OPERATIONS_ERROR;
-			goto free_and_return;
-		}
-		krb5_free_context(krbctx);
-	}
-
 	/* Before going any further, we'll make sure that the right extended
 	 * operation plugin has been called: i.e., the OID shipped whithin the
 	 * extended operation request must match this very plugin's OIDs:
@@ -2873,11 +2855,25 @@ static int ipapwd_extop(Slapi_PBlock *pb)
 				"Received extended operation request with OID %s\n", oid);
 	}
 
+	/* get the kerberos context and master key */
+	krbcfg = ipapwd_getConfig(ipa_realm_dn);
+	if (NULL == krbcfg) {
+		slapi_log_error(SLAPI_LOG_PLUGIN, "ipa_pwd_extop",
+				"Error Retrieving Master Key");
+		errMesg = "Fatal Internal Error";
+		rc = LDAP_OPERATIONS_ERROR;
+		goto free_and_return;
+	}
+
 	if (strcasecmp(oid, EXOP_PASSWD_OID) == 0) {
-		return ipapwd_chpwop(pb);
+		ret = ipapwd_chpwop(pb, krbcfg);
+		free_ipapwd_krbcfg(&krbcfg);
+		return ret;
 	}
 	if (strcasecmp(oid, KEYTAB_SET_OID) == 0) {
-		return ipapwd_setkeytab(pb);
+		ret = ipapwd_setkeytab(pb, krbcfg);
+		free_ipapwd_krbcfg(&krbcfg);
+		return ret;
 	}
 
 	errMesg = "Request OID does not match supported OIDs.\n";
@@ -2952,12 +2948,6 @@ static int ipapwd_start( Slapi_PBlock *pb )
 	ipa_realm_dn = realm_dn;
 	slapi_unlock_mutex(ipa_globals);
 
-	ret = ipapwd_getConfig(krbctx, ipa_realm_dn);
-	if (ret) {
-		slapi_log_error( SLAPI_LOG_PLUGIN, "ipapwd_start", "Couldn't init master key at start delaying ...");
-		ret = LDAP_SUCCESS;
-	}
-
 	krb5_free_context(krbctx);
 	slapi_entry_free(config_entry);
 	return ret;
-- 
1.5.5.1


freeipa-user-input.patch:

--- NEW FILE freeipa-user-input.patch ---
>From f7ca405716b1ee8b92a940e07cd611f6b025795d Mon Sep 17 00:00:00 2001
From: Martin Nagy <mnagy at notas.(none)>
Date: Mon, 21 Jul 2008 12:25:37 +0200
Subject: [PATCH] Wrap up the raw_input() to user_input() for convenience and uniformity.

---
 ipa-admintools/ipa-addgroup                   |   17 +------
 ipa-admintools/ipa-adduser                    |   50 ++----------------
 ipa-admintools/ipa-moduser                    |   57 +++-------------------
 ipa-client/ipa-install/ipa-client-install     |   23 ++------
 ipa-python/ipautil.py                         |   66 +++++++++++++++++++++++++
 ipa-radius-server/ipa-radius-install          |    3 +-
 ipa-server/ipa-install/ipa-replica-install    |   10 +---
 ipa-server/ipa-install/ipa-server-certinstall |   19 ++-----
 ipa-server/ipa-install/ipa-server-install     |   64 +++++++++---------------
 9 files changed, 119 insertions(+), 190 deletions(-)

diff --git a/ipa-admintools/ipa-addgroup b/ipa-admintools/ipa-addgroup
index caf4e93..cc81383 100644
--- a/ipa-admintools/ipa-addgroup
+++ b/ipa-admintools/ipa-addgroup
@@ -81,29 +81,16 @@ def main():
     if options.usage:
         usage()
 
-    cont = False
-
     if (len(args) != 2):
-        while (cont != True):
-            cn = raw_input("Group name: ")
-            if (ipavalidate.String(cn, notEmpty=True)):
-                print "Please enter a value"
-            else:
-                cont = True
+        cn = ipautil.user_input("Group name", allow_empty = False)
     else:
         cn = args[1]
         if (ipavalidate.String(cn, notEmpty=True)):
             print "Please enter a value"
             return 1
 
-    cont = False
     if not options.desc:
-        while (cont != True):
-            desc = raw_input("Description: ")
-            if (ipavalidate.String(desc, notEmpty=True)):
-                print "Please enter a value"
-            else:
-                cont = True
+        desc = ipautil.user_input("Description", allow_empty = False)
     else:
         desc = options.desc
         if (ipavalidate.String(desc, notEmpty=True)):
diff --git a/ipa-admintools/ipa-adduser b/ipa-admintools/ipa-adduser
index 2c32d1e..17c75ed 100644
--- a/ipa-admintools/ipa-adduser
+++ b/ipa-admintools/ipa-adduser
@@ -102,7 +102,6 @@ def main():
     groups = ""
 
     match = False
-    cont = False
 
     all_interactive = False
 
@@ -116,40 +115,23 @@ def main():
         all_interactive = True
 
     if not options.gn:
-        while (cont != True):
-            givenname = raw_input("First name: ")
-            if (ipavalidate.String(givenname, notEmpty=True)):
-                print "Please enter a value"
-            else:
-                cont = True
+        givenname = ipautil.user_input("First name", allow_empty = False)
     else:
         givenname = options.gn
         if (ipavalidate.String(givenname, notEmpty=True)):
             print "Please enter a value"
             return 1
 
-    cont = False
     if not options.sn:
-        while (cont != True):
-            lastname = raw_input("Last name: ")
-            if (ipavalidate.String(lastname, notEmpty=True)):
-                print "Please enter a value"
-            else:
-                cont = True
+        lastname = ipautil.user_input("Last name", allow_empty = False)
     else:
         lastname = options.sn
         if (ipavalidate.String(lastname, notEmpty=True)):
             print "Please enter a value"
             return 1
 
-    cont = False
     if (len(args) != 2):
-        while (cont != True):
-            username = raw_input("Login name: ")
-            if (ipavalidate.Plain(username, notEmpty=True, allowSpaces=False)):
-                print "Please enter a value"
-            else:
-                cont = True
+        username = ipautil.user_input_plain("Login name", allow_empty = False, allow_spaces = False)
     else:
         username = args[1]
         if (ipavalidate.Plain(username, notEmpty=True, allowSpaces=False)):
@@ -180,32 +162,12 @@ def main():
     # Ask the questions we don't normally force. We don't require answers
     # for these.
     if all_interactive is True:
-        cont = False
         if not options.gecos:
-            while (cont != True):
-                gecos = raw_input("gecos []: ")
-                if (ipavalidate.String(gecos, notEmpty=False)):
-                    print "Please enter a value"
-                else:
-                    cont = True
-        cont = False
+            gecos = ipautil.user_input("gecos")
         if not options.directory:
-            while (cont != True):
-                directory = raw_input("home directory [/home/"+username+"]: ")
-                if directory == "":
-                     directory = "/home/"+username
-                if (ipavalidate.Path(directory, notEmpty=False)):
-                    print "Please enter a value"
-                else:
-                    cont = True
-        cont = False
+            directory = ipautil.user_input_path("Home directory", "/home/" + username, allow_empty = True)
         if not options.shell:
-            while (cont != True):
-                shell = raw_input("shell [/bin/sh]: ")
-
-                if len(shell) < 1:
-                    shell = None
-                cont = True
+            shell = ipautil.user_input("Shell", "/bin/sh", allow_empty = False)
 
     else:
         gecos = options.gecos
diff --git a/ipa-admintools/ipa-moduser b/ipa-admintools/ipa-moduser
index 22f2318..4b3bd5c 100644
--- a/ipa-admintools/ipa-moduser
+++ b/ipa-admintools/ipa-moduser
@@ -97,7 +97,6 @@ def main():
     shell = ""
 
     match = False
-    cont = False
 
     options, args = parse_options()
 
@@ -141,46 +140,23 @@ def main():
         shell = options.shell
     else:
         if not options.gn:
-            while (cont != True):
-                givenname = raw_input("First name: [%s] " % user.getValue('givenname'))
-                if (ipavalidate.String(givenname, notEmpty=False)):
-                    print "Please enter a value"
-                else:
-                    cont = True
-                if len(givenname) < 1:
-                    givenname = None
-                    cont = True
+            givenname = ipautil.user_input("First name", user.getValue('givenname'), allow_empty = False)
         else:
             givenname = options.gn
             if (ipavalidate.String(givenname, notEmpty=True)):
                 print "Please enter a value"
                 return 1
 
-        cont = False
         if not options.sn:
-            while (cont != True):
-                lastname = raw_input(" Last name: [%s] " % user.getValue('sn'))
-                if (ipavalidate.String(lastname, notEmpty=False)):
-                    print "Please enter a value"
-                else:
-                    cont = True
-                if len(lastname) < 1:
-                    lastname = None
-                    cont = True
+            lastname = ipautil.user_input("Last name", user.getValue('sn'), allow_empty = False)
         else:
             lastname = options.sn
             if (ipavalidate.String(lastname, notEmpty=True)):
                 print "Please enter a value"
                 return 1
 
-        cont = False
         if not options.mail:
-            while (cont != True):
-                mail = raw_input("E-mail addr: [%s]" % user.getValue('mail'))
-                if (ipavalidate.Email(mail, notEmpty=False)):
-                    print "E-mail must include a user and domain name"
-                else:
-                    cont = True
+            mail = ipautil.user_input_email("E-mail address", user.getValue('mail'), allow_empty = True)
         else:
             mail = options.mail
             if (ipavalidate.Email(mail)):
@@ -189,32 +165,13 @@ def main():
 
         # Ask the questions we don't normally force. We don't require answers
         # for these.
-        cont = False
         if not options.gecos:
-            while (cont != True):
-                gecos = raw_input("gecos: [%s] " % user.getValue('gecos'))
-                if (ipavalidate.String(gecos, notEmpty=False)):
-                    print "Please enter a value"
-                else:
-                    cont = True
+            gecos = ipautil.user_input("gecos", user.getValue('gecos'))
 
-        cont = False
         if not options.directory:
-            while (cont != True):
-                directory = raw_input("home directory: [%s] " % user.getValue('homeDirectory'))
-                if (ipavalidate.Path(gecos, notEmpty=False)):
-                    print "Valid path is required"
-                else:
-                    cont = True
-        cont = False
+            directory = ipautil.user_input_path("Home directory", user.getValue('homeDirectory'))
         if not options.shell:
-            while (cont != True):
-                shell = raw_input("shell: [%s] " % user.getValue('loginshell'))
-
-                if len(shell) < 1:
-                    shell = None
-                    cont = True
-        cont = False
+            shell = ipautil.user_input("Shell", user.getValue('loginshell'), allow_empty = False)
 
     if givenname:
         user.setValue('givenname', givenname)
diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index ecdf927..eec36e4 100644
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -30,7 +30,7 @@ try:
     import ipaclient.ipadiscovery
     import ipaclient.ipachangeconf
     import ipaclient.ntpconf
-    from ipa.ipautil import run
+    from ipa.ipautil import run, user_input
     from ipa import sysrestore
     from ipa import version
 except ImportError:
@@ -70,13 +70,6 @@ def parse_options():
 
     return options
 
-def ask_for_confirmation(message):
-    yesno = raw_input(message + " [y/N]: ")
-    if not yesno or yesno.lower()[0] != "y":
-        return False
-    print "\n"
-    return True
-
 def logging_setup(options):
     # Always log everything (i.e., DEBUG) to the log
     # file.
@@ -124,7 +117,7 @@ def uninstall(options):
         print "The original nsswitch.conf configuration has been restored."
         print "You may need to restart services or reboot the machine."
         if not options.on_master:
-            if ask_for_confirmation("Do you want to reboot the machine?"):
+            if user_input("Do you want to reboot the machine?", False):
                 try:
                     run(["/usr/bin/reboot"])
                 except Exception, e:
@@ -163,9 +156,7 @@ def main():
             return ret
         else:
             print "DNS discovery failed to determine your DNS domain"
-            cli_domain = ""
-            while cli_domain == "":
-                cli_domain = raw_input("Please provide the domain name of your IPA server (ex: example.com): ")
+            cli_domain = user_input("Please provide the domain name of your IPA server (ex: example.com)", allow_empty = False)
         ret = ds.search(domain=cli_domain, server=options.server)
     if not cli_domain:
         if ds.getDomainName():
@@ -180,9 +171,7 @@ def main():
             return ret
         else:
             print "DNS discovery failed to find the IPA Server"
-            cli_server = ""
-            while cli_server == "":
-                cli_server = raw_input("Please provide your IPA server name (ex: ipa.example.com): ")
+            cli_server = user_input("Please provide your IPA server name (ex: ipa.example.com)", allow_empty = False)
         ret = ds.search(domain=cli_domain, server=cli_server)
     if not cli_server:
         if ds.getServerName():
@@ -203,7 +192,7 @@ def main():
         print "If you proceed with the installation, services will be configured to always"
         print "access the discovered server for all operation and will not fail over to"
         print "other servers in case of failure.\n"
-        if not ask_for_confirmation("Do you want to proceed and configure the system with fixed values with no DNS discovery?"):
+        if not user_input("Do you want to proceed and configure the system with fixed values with no DNS discovery?", False):
             return ret
 
     if options.realm_name and options.realm_name != ds.getRealmName():
@@ -220,7 +209,7 @@ def main():
     print "BaseDN: "+cli_basedn
 
     print "\n"
-    if not options.unattended and not ask_for_confirmation("Continue to configure the system with these values?"):
+    if not options.unattended and not user_input("Continue to configure the system with these values?", False):
         return 1
 
     # Configure ipa.conf
diff --git a/ipa-python/ipautil.py b/ipa-python/ipautil.py
index 4e065fc..3526cc7 100644
--- a/ipa-python/ipautil.py
+++ b/ipa-python/ipautil.py
@@ -29,6 +29,7 @@ import os, sys, traceback, readline
 import stat
 import shutil
 
+from ipa import ipavalidate
 from types import *
 
 import re
@@ -482,6 +483,71 @@ def read_items_file(filename):
     if fd != sys.stdin: fd.close()
     return items
 
+def user_input(prompt, default = None, allow_empty = True):
+    if default == None:
+        while True:
+            ret = raw_input("%s: " % prompt)
+            if allow_empty or ret.strip():
+                return ret
+                
+    if isinstance(default, basestring):
+        while True:
+            ret = raw_input("%s [%s]: " % (prompt, default))
+            if not ret and (allow_empty or default):
+                return default
+            elif ret.strip():
+                return ret
+    if isinstance(default, bool):
+        if default:
+            choice = "yes"
+        else:
+            choice = "no"
+        while True:
+            ret = raw_input("%s [%s]: " % (prompt, choice))
+            if not ret:
+                return default
+            elif ret.lower()[0] == "y":
+                return True
+            elif ret.lower()[0] == "n":
+                return False
+    if isinstance(default, int):
+        while True:
+            try:
+                ret = raw_input("%s [%s]: " % (prompt, default))
+                if not ret:
+                    return default
+                ret = int(ret)
+            except ValueError:
+                pass
+            else:
+                return ret
+
+def user_input_email(prompt, default = None, allow_empty = False):
+    if default != None and allow_empty:
+        prompt += " (enter \"none\" for empty)"
+    while True:
+        ret = user_input(prompt, default, allow_empty)
+        if allow_empty and ret.lower() == "none":
+            return ""
+        if not ipavalidate.Email(ret, not allow_empty):
+            return ret.strip()
+
+def user_input_plain(prompt, default = None, allow_empty = True, allow_spaces = True):
+    while True:
+        ret = user_input(prompt, default, allow_empty)
+        if not ipavalidate.Plain(ret, not allow_empty, allow_spaces):
+            return ret
+
+def user_input_path(prompt, default = None, allow_empty = True):
+    if default != None and allow_empty:
+        prompt += " (enter \"none\" for empty)"
+    while True:
+        ret = user_input(prompt, default, allow_empty)
+        if allow_empty and ret.lower() == "none":
+            return ""
+        if not ipavalidate.Path(ret, not allow_empty):
+            return ret
+
 
 class AttributeValueCompleter:
     '''
diff --git a/ipa-radius-server/ipa-radius-install b/ipa-radius-server/ipa-radius-install
index 8ed3aab..83215b3 100644
--- a/ipa-radius-server/ipa-radius-install
+++ b/ipa-radius-server/ipa-radius-install
@@ -45,8 +45,7 @@ def main():
     if not ipautil.file_exists("/etc/ipa/ipa.conf"):
         print "This system does not appear to have IPA configured."
         print "Has ipa-server-install been run?"
-        yesno = raw_input("Continue with radius install [y/N]? ")
-        if yesno.lower() != "y":
+        if not ipautil.user_input("Continue with radius install?", False):
             sys.exit(1)
 
     installutils.standard_logging_setup("iparadius-install.log", False)
diff --git a/ipa-server/ipa-install/ipa-replica-install b/ipa-server/ipa-install/ipa-replica-install
index 31fd4cc..ab66a83 100644
--- a/ipa-server/ipa-install/ipa-replica-install
+++ b/ipa-server/ipa-install/ipa-replica-install
@@ -145,8 +145,7 @@ def check_dirsrv():
     if serverids:
         print ""
         print "An existing Directory Server has been detected."
-        yesno = raw_input("Do you wish to remove it and create a new one? [no]: ")
-        if not yesno or yesno.lower()[0] != "y":
+        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."
@@ -189,12 +188,9 @@ def main():
     if host != config.host_name:
         try:
             print "This replica was created for '%s' but this machine is named '%s'" % (host, config.host_name)
-            yesno = raw_input("This may cause problems. Continue? [Y/n]: ")
-            print ""
-            if not yesno or yesno.lower()[0] == "y":
-                pass
-            else:
+            if not ipautil.user_input("This may cause problems. Continue?", True):
                 sys.exit(0)
+            print ""
         except KeyboardInterrupt:
             sys.exit(0)
     config.repl_password = ipautil.ipa_generate_password()
diff --git a/ipa-server/ipa-install/ipa-server-certinstall b/ipa-server/ipa-install/ipa-server-certinstall
index 835af0a..a0d1185 100644
--- a/ipa-server/ipa-install/ipa-server-certinstall
+++ b/ipa-server/ipa-install/ipa-server-certinstall
@@ -27,6 +27,7 @@ import traceback
 
 import krbV, ldap, getpass
 
+from ipa.ipautil import user_input
 from ipaserver import certs, dsinstance, httpinstance, ipaldap, installutils
 
 def get_realm_name():
@@ -76,25 +77,15 @@ def choose_server_cert(server_certs):
         print "%d. %s" % (num, cert[0])
         num += 1
         
-    cert_num = 0
     while 1:
-        cert_input = raw_input("Certificate number [1]: ")
+        num = user_input("Certificate number", 1)
         print ""
-        if cert_input == "":
-            break
+        if num < 1 or num > len(server_certs):
+            print "number out of range"
         else:
-            try:
-                num = int(cert_input)
-            except ValueError:
-                print "invalid number"
-                continue
-            if num > len(server_certs):
-                print "number out of range"
-                continue
-            cert_num = num - 1
             break
-    return server_certs[cert_num]
     
+    return server_certs[num - 1]
 
 def import_cert(dirname, pkcs12_fname):
     cdb = certs.CertDB(dirname)
diff --git a/ipa-server/ipa-install/ipa-server-install b/ipa-server/ipa-install/ipa-server-install
index 8b5b831..ce300cc 100644
--- a/ipa-server/ipa-install/ipa-server-install
+++ b/ipa-server/ipa-install/ipa-server-install
@@ -120,7 +120,6 @@ def signal_handler(signum, frame):
     sys.exit(1)
 
 def read_host_name(host_default):
-    host_ok = False
     host_name = ""
 
     print "Enter the fully qualified domain name of the computer"
@@ -131,19 +130,15 @@ def read_host_name(host_default):
     print ""
     if host_default == "":
         host_default = "master.example.com"
-    while not host_ok:
-        host_input = raw_input("Server host name [" + host_default + "]: ")
+    while True:
+        host_name = user_input("Server host name", host_default, allow_empty = False)
         print ""
-        if host_input == "":
-            host_name = host_default
-        else:
-            host_name = host_input
         try:
             verify_fqdn(host_name)
         except Exception, e:
             raise e
         else:
-            host_ok = True
+            break
     return host_name
 
 def resolve_host(host_name):
@@ -178,10 +173,8 @@ def verify_ip_address(ip):
 
 def read_ip_address(host_name):
     while True:
-        ip = raw_input("Please provide the IP address to be used for this host name: ")
+        ip = user_input("Please provide the IP address to be used for this host name", allow_empty = False)
 
-        if ip == "":
-            continue
         if ip == "127.0.0.1" or ip == "::1":
             print "The IPA Server can't use localhost as a valid IP"
             continue
@@ -213,13 +206,12 @@ def read_ds_user():
         print "A user account named 'dirsrv' already exists. This is the user id"
         print "that the Directory Server will run as."
         print ""
-        yesno = raw_input("Do you want to use the existing 'dirsrv' account? [yes]: ")
-        print ""
-        if not yesno or yesno.lower()[0] != "n":
+        if user_input("Do you want to use the existing 'dirsrv' account?", True):
             ds_user = "dirsrv"
         else:
-            ds_user = raw_input("Which account name do you want to use for the DS instance? ")
             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"
 
@@ -229,37 +221,31 @@ def read_domain_name(domain_name, unattended):
     print "The domain name has been calculated based on the host name."
     print ""
     if not unattended:
-        dn = raw_input("Please confirm the domain name ["+domain_name+"]: ")
+        domain_name = user_input("Please confirm the domain name", domain_name)
         print ""
-        if dn != "":
-            domain_name = dn
     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 ""
-    upper_dom = domain_name.upper()
+    
     if unattended:
-        realm_name = upper_dom
-    else:
-        realm_name = raw_input("Please provide a realm name ["+upper_dom+"]: ")
-        print ""
-        if realm_name == "":
-            realm_name = upper_dom
-        else:
-            upper_dom = realm_name.upper()
-        if upper_dom != realm_name:
-            print "An upper-case realm name is required."
-            dom_realm = raw_input("Do you want to use "+upper_dom+" as realm name ? [yes]: ")
+        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 ""
-            if dom_realm and dom_realm.lower()[0] != "y":
-                print "An upper-case realm name is required. Unable to continue."
-                sys.exit(1)
-            else:
-                realm_name = upper_dom
+            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"
@@ -284,10 +270,7 @@ def check_dirsrv(unattended):
     if serverids:
         print ""
         print "An existing Directory Server has been detected."
-        if unattended:
-            sys.exit(1)
-        yesno = raw_input("Do you wish to remove it and create a new one? [no]: ")
-        if not yesno or yesno.lower()[0] != "y":
+        if unattended or 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."
@@ -354,8 +337,7 @@ def main():
     if options.uninstall:
         if not options.unattended:
             print "\nThis is a NON REVERSIBLE operation and will delete all data and configuration!\n"
-            yesno = raw_input("Are you sure you want to continue with the uninstall procedure?:[NO/yes] ")
-            if not yesno or yesno.lower() != "yes":
+            if not user_input("Are you sure you want to continue with the uninstall procedure?", False):
                 print ""
                 print "Aborting uninstall operation."
                 sys.exit(1)
-- 
1.5.5.1



Index: ipa.spec
===================================================================
RCS file: /cvs/extras/rpms/ipa/devel/ipa.spec,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- ipa.spec	18 Jun 2008 16:55:40 -0000	1.13
+++ ipa.spec	11 Sep 2008 02:58:19 -0000	1.14
@@ -1,3 +1,5 @@
+%define _default_patch_fuzz 30
+
 %define httpd_conf /etc/httpd/conf.d
 %define plugin_dir %{_libdir}/dirsrv/plugins
 %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
@@ -6,7 +8,7 @@
 
 Name:           ipa
 Version:        1.1.0
-Release:        2%{?dist}
+Release:        3%{?dist}
 Summary:        The Identity, Policy and Audit system
 
 Group:          System Environment/Base
@@ -19,6 +21,19 @@
 Patch2:         freeipa-noinit.patch
 Patch3:         freeipa-memberofindex.patch
 Patch4:         freeipa-index.patch
+Patch5:         0001-slapi_pw_find_sv-expects-an-array-make-sure-we-ha.patch
+Patch6:         0001-Fix-typo-in-inet-type.patch
+Patch7:         0001-In-openvz-we-found-out-some-interfaces-may-return-a.patch
+Patch8:         freeipa-noi18n.patch
+
+Patch101:	freeipa-refresh-mkey.patch
+Patch102:	freeipa-fix-expire.patch
+Patch103:	freeipa-fix-key-encryption.patch
+Patch104:	freeipa-user-input.patch
+Patch105:	freeipa-encrypt-files.patch
+Patch106:	freeipa-change-mkey.patch
+Patch107:	freeipa-cve-2008-3274-fixes.patch
+Patch108:	freeipa-cve-2008-3274-utility.patch
 
 BuildRequires:  fedora-ds-base-devel >= 1.1
 BuildRequires:  mozldap-devel
@@ -187,10 +202,25 @@
 %patch2 -p1 -b noinit
 %patch3 -p1 -b memberofindex
 %patch4 -p1 -b index
+%patch5 -p1 -b changepw
+%patch6 -p1 -b af-inet-fix
+%patch7 -p1 -b kpasswd-segfault
+%patch8 -p1 -b noi18n
+
+#START CVE-2008-3274 block
+%patch101 -p1 -b refresh-mkey
+%patch102 -p1 -b fix-expire
+%patch103 -p1 -b fix-key-encryption
+%patch104 -p1 -b user-input
+%patch105 -p1 -b encrypt-files
+%patch106 -p1 -b change-mkey
+%patch107 -p1 -b cve-2008-3274-fixes
+%patch108 -p1 -b cve-2008-3274-utility
+#END CVE-2008-3274 block
 
 %build
-cd ipa-server; ./autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir}; cd ..
-cd ipa-client; ./autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir}; cd ..
+cd ipa-server; ./autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir} --with-openldap=yes; cd ..
+cd ipa-client; ./autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir} --with-openldap=yes; cd ..
 
 make IPA_VERSION_IS_GIT_SNAPSHOT=no %{?_smp_mflags} version-update all
 cd ipa-server/selinux
@@ -325,8 +355,9 @@
 %{_usr}/share/ipa/ipa_gui.egg-info/*
 %dir %{_usr}/share/ipa/ipaserver
 %{_usr}/share/ipa/ipaserver/*
-%dir %{_usr}/share/ipa/locales/
-%{_usr}/share/ipa/locales/*
+# locales are not built because TurboGears is currently broken
+#%dir %{_usr}/share/ipa/locales/
+#%{_usr}/share/ipa/locales/*
 %attr(755,root,root) %{plugin_dir}/libipa_pwd_extop.so
 %attr(755,root,root) %{plugin_dir}/libipa-memberof-plugin.so
 %attr(755,root,root) %{plugin_dir}/libipa-dna-plugin.so
@@ -386,6 +417,8 @@
 %{_sbindir}/ipa-passwd
 %{_sbindir}/ipa-moduser
 %{_sbindir}/ipa-pwpolicy
+%{_sbindir}/ipa-change-master-key
+%{_sbindir}/ipa-fix-CVE-2008-3274
 %{_mandir}/man1/ipa-adddelegation.1.gz
 %{_mandir}/man1/ipa-addgroup.1.gz
 %{_mandir}/man1/ipa-addservice.1.gz
@@ -435,6 +468,14 @@
 %{_sbindir}/ipa-modradiusprofile
 
 %changelog
+* Wed Jul 23 2008 Simo Sorce <ssorce at redhat.com> - 1.1.0-3
+- Fix for CVE-2008-3274
+- Fix segfault in ipa-kpasswd in case getifaddrs returns a NULL interface
+- Add fix for bug #453185
+- Rebuild against openldap libraries, mozldap ones do not work properly
+- TurboGears is currently broken in rawhide. Added patch to not build
+  the UI locales and removed them from the ipa-server files section.
+
 * Wed Jun 18 2008 Rob Crittenden <rcritten at redhat.com> - 1.1.0-2
 - Add call to /usr/sbin/upgradeconfig to post install
 




More information about the fedora-extras-commits mailing list