On 04/13/2015 02:16 PM, Martin Babinsky wrote:
On 04/09/2015 03:38 PM, Jan Cholasta wrote:


Some comments:

Patch 15:

1) The functions should be as similar as possible:

     a) kinit_password() should have a 'ccache_path' argument instead of
passing the path in KRB5CCNAME in the 'env' argument.

     b) I don't think kinit_password() should have the 'env' argument at
all. You can always call kinit with LC_ALL=C and set other variables in
os.environ if you want.

     c) The arguments should have the same ordering.

     d) Either set KRB5CCNAME in both kinit_keytab() and
kinit_password() or in none of them.

     e) Either rename armor_ccache to armor_ccache_path or ccache_path
to ccache.

I have done some reordering of parameters in both functions so they are
very similar now and the parameter ordering should make more sense (at
least to me).

Neither of them sets KRB5CCNAME env. variable since I think that it is
not a very good practice and the developer should be responsible for
pointing to correct CCache path. Jan agrees with this and the other
patches are updated accordingly.

2) Space before comma in docstring:

+    Given a ccache_path , keytab file and a principal kinit as that
user.


3) I would prefer if the default value of 'armor_ccache' in
kinit_password() was None.

Fixed.

Patch 16:

1) The callback should not be named 'validate_kinit_attempts_option',
but rather 'kinit_attempts_callback', as it doesn't just validate the
value.

Fixed.

2) Why is there the sys.maxint upper bound on --kinit-attempts again? A
comment with explanation would be nice.

It actually doesn't make much sense to have such upper bound, so I have
removed it from the check and updated the error message accordingly.

Patch 17:

1) Is there a reason for the ccache filename changes in DNSSEC code?

That was Petr Spacek's request since a sane naming of persistent Ccaches
makes debugging of Kerberos-related errors a bit easier for him.

Attaching updated patches.




Jan had some further suggestions so I am attaching updated patches which should reflect them.

He also recommended to split the naming changes of DNSSEC daemon credential caches to a separate patch, so I will submit them later when this patchset is pushed.

--
Martin^3 Babinsky
From f73731c388e39fe0ff6bbaaa534ddc80248956b6 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Mon, 16 Mar 2015 16:28:54 +0100
Subject: [PATCH 1/3] ipautil: new functions kinit_keytab and kinit_password

kinit_keytab replaces kinit_hostprincipal and performs Kerberos auth using
keytab file. Function is also able to repeat authentication multiple times
before giving up and raising Krb5Error.

kinit_password wraps kinit auth using password and also supports FAST
authentication using httpd armor ccache.

---
 ipapython/ipautil.py | 71 +++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 54 insertions(+), 17 deletions(-)

diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 6a06a8e956552597dfd48128b60a1dd6a4cc92f6..bdbf8da49ba4136a7948d31616f1dcf348662ccf 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -1185,27 +1185,64 @@ def wait_for_open_socket(socket_name, timeout=0):
             else:
                 raise e
 
-def kinit_hostprincipal(keytab, ccachedir, principal):
+
+def kinit_keytab(principal, keytab, ccache_name, attempts=1):
+    """
+    Given a ccache_path, keytab file and a principal kinit as that user.
+
+    The optional parameter 'attempts' specifies how many times the credential
+    initialization should be attempted in case of non-responsive KDC.
     """
-    Given a ccache directory and a principal kinit as that user.
+    errors_to_retry = {krbV.KRB5KDC_ERR_SVC_UNAVAILABLE,
+                       krbV.KRB5_KDC_UNREACH}
+    root_logger.debug("Initializing principal %s using keytab %s"
+                      % (principal, keytab))
+    root_logger.debug("using ccache %s" % ccache_name)
+    for attempt in range(1, attempts + 1):
+        try:
+            krbcontext = krbV.default_context()
+            ktab = krbV.Keytab(name=keytab, context=krbcontext)
+            princ = krbV.Principal(name=principal, context=krbcontext)
+            ccache = krbV.CCache(name=ccache_name, context=krbcontext,
+                                 primary_principal=princ)
+            ccache.init(princ)
+            ccache.init_creds_keytab(keytab=ktab, principal=princ)
+            root_logger.debug("Attempt %d/%d: success"
+                              % (attempt, attempts))
+            return
+        except krbV.Krb5Error as e:
+            if e.args[0] not in errors_to_retry:
+                raise
+            root_logger.debug("Attempt %d/%d: failed: %s"
+                              % (attempt, attempts, e))
+            if attempt == attempts:
+                root_logger.debug("Maximum number of attempts (%d) reached"
+                                  % attempts)
+                raise
+            root_logger.debug("Waiting 5 seconds before next retry")
+            time.sleep(5)
 
-    This blindly overwrites the current CCNAME so if you need to save
-    it do so before calling this function.
 
-    Thus far this is used to kinit as the local host.
+def kinit_password(principal, password, ccache_name, armor_ccache_name=None):
     """
-    try:
-        ccache_file = 'FILE:%s/ccache' % ccachedir
-        krbcontext = krbV.default_context()
-        ktab = krbV.Keytab(name=keytab, context=krbcontext)
-        princ = krbV.Principal(name=principal, context=krbcontext)
-        os.environ['KRB5CCNAME'] = ccache_file
-        ccache = krbV.CCache(name=ccache_file, context=krbcontext, primary_principal=princ)
-        ccache.init(princ)
-        ccache.init_creds_keytab(keytab=ktab, principal=princ)
-        return ccache_file
-    except krbV.Krb5Error, e:
-        raise StandardError('Error initializing principal %s in %s: %s' % (principal, keytab, str(e)))
+    perform interactive kinit as principal using password. If using FAST for
+    web-based authentication, use armor_ccache_path to specify http service
+    ccache.
+    """
+    root_logger.debug("Initializing principal %s using password" % principal)
+    args = [paths.KINIT, principal, '-c', ccache_name]
+    if armor_ccache_name is not None:
+        root_logger.debug("Using armor ccache %s for FAST webauth"
+                          % armor_ccache_name)
+        args.extend(['-T', armor_ccache_name])
+
+    # this workaround enables us to capture stderr and put it
+    # into the raised exception in case of unsuccessful authentication
+    (stdout, stderr, retcode) = run(args, stdin=password, env={'LC_ALL': 'C'},
+                                    raiseonerr=False)
+    if retcode:
+        raise RuntimeError(stderr)
+
 
 def dn_attribute_property(private_name):
     '''
-- 
2.1.0

From 86d115ee19431e2c67a8e6e5774d47e851f31881 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Mon, 16 Mar 2015 16:30:55 +0100
Subject: [PATCH 2/3] ipa-client-install: try to get host TGT several times
 before giving up

New option '--kinit-attempts' enables the host to make multiple attempts to
obtain host TGT from master before giving up and aborting client installation.

In addition, all kinit attempts were replaced by calls to
'ipautil.kinit_keytab' and 'ipautil.kinit_password'.

https://fedorahosted.org/freeipa/ticket/4808
---
 ipa-client/ipa-install/ipa-client-install | 69 ++++++++++++++++++-------------
 ipa-client/man/ipa-client-install.1       |  8 ++++
 2 files changed, 48 insertions(+), 29 deletions(-)

diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index 1590a08600bbb1b2fd7f4c3338b5060156d7dc38..47f1c128ce72b5e17071e9fecdbec0bfb3876e8b 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -31,6 +31,7 @@ try:
     from ConfigParser import RawConfigParser
     from optparse import SUPPRESS_HELP, OptionGroup, OptionValueError
     import shutil
+    from krbV import Krb5Error
 
     import nss.nss as nss
     import SSSDConfig
@@ -91,6 +92,14 @@ def parse_options():
 
         parser.values.ca_cert_file = value
 
+    def kinit_attempts_callback(option, opt, value, parser):
+        if value < 1:
+            raise OptionValueError(
+                "Option %s expects an integer greater than 0."
+                % opt)
+
+        parser.values.kinit_attempts = value
+
     parser = IPAOptionParser(version=version.VERSION)
 
     basic_group = OptionGroup(parser, "basic options")
@@ -144,6 +153,11 @@ def parse_options():
                       help="do not modify the nsswitch.conf and PAM configuration")
     basic_group.add_option("-f", "--force", dest="force", action="store_true",
                       default=False, help="force setting of LDAP/Kerberos conf")
+    basic_group.add_option('--kinit-attempts', dest='kinit_attempts',
+                           action='callback', type='int', default=5,
+                           callback=kinit_attempts_callback,
+                           help=("number of attempts to obtain host TGT"
+                                 " (defaults to %default)."))
     basic_group.add_option("-d", "--debug", dest="debug", action="store_true",
                       default=False, help="print debugging information")
     basic_group.add_option("-U", "--unattended", dest="unattended",
@@ -2354,6 +2368,7 @@ def install(options, env, fstore, statestore):
             root_logger.debug(
                 "will use principal provided as option: %s", options.principal)
 
+    host_principal = 'host/%s@%s' % (hostname, cli_realm)
     if not options.on_master:
         nolog = tuple()
         # First test out the kerberos configuration
@@ -2374,7 +2389,6 @@ def install(options, env, fstore, statestore):
             env['KRB5_CONFIG'] = krb_name
             (ccache_fd, ccache_name) = tempfile.mkstemp()
             os.close(ccache_fd)
-            env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = ccache_name
             join_args = [paths.SBIN_IPA_JOIN,
                          "-s", cli_server[0],
                          "-b", str(realm_to_suffix(cli_realm)),
@@ -2412,29 +2426,23 @@ def install(options, env, fstore, statestore):
                         else:
                             stdin = sys.stdin.readline()
 
-                (stderr, stdout, returncode) = run(["kinit", principal],
-                                                    raiseonerr=False,
-                                                    stdin=stdin,
-                                                    env=env)
-                if returncode != 0:
+                try:
+                    ipautil.kinit_password(principal, stdin, ccache_name)
+                except RuntimeError as e:
                     print_port_conf_info()
-                    root_logger.error("Kerberos authentication failed")
-                    root_logger.info("%s", stdout)
+                    root_logger.error("Kerberos authentication failed: %s" % e)
                     return CLIENT_INSTALL_ERROR
             elif options.keytab:
                 join_args.append("-f")
                 if os.path.exists(options.keytab):
-                    (stderr, stdout, returncode) = run(
-                        [paths.KINIT,'-k', '-t', options.keytab,
-                            'host/%s@%s' % (hostname, cli_realm)],
-                        env=env,
-                        raiseonerr=False)
-
-                    if returncode != 0:
+                    try:
+                        ipautil.kinit_keytab(host_principal, options.keytab,
+                                             ccache_name,
+                                             attempts=options.kinit_attempts)
+                    except Krb5Error as e:
                         print_port_conf_info()
-                        root_logger.error("Kerberos authentication failed "
-                                          "using keytab: %s", options.keytab)
-                        root_logger.info("%s", stdout)
+                        root_logger.error("Kerberos authentication failed: %s"
+                                          % e)
                         return CLIENT_INSTALL_ERROR
                 else:
                     root_logger.error("Keytab file could not be found: %s"
@@ -2460,6 +2468,7 @@ def install(options, env, fstore, statestore):
                 join_args.append(password)
                 nolog = (password,)
 
+            env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = ccache_name
             # Get the CA certificate
             try:
                 os.environ['KRB5_CONFIG'] = env['KRB5_CONFIG']
@@ -2504,12 +2513,14 @@ def install(options, env, fstore, statestore):
             # only the KDC we're installing under is contacted.
             # Other KDCs might not have replicated the principal yet.
             # Once we have the TGT, it's usable on any server.
-            env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = CCACHE_FILE
             try:
-                run([paths.KINIT, '-k', '-t', paths.KRB5_KEYTAB,
-                        'host/%s@%s' % (hostname, cli_realm)], env=env)
-            except CalledProcessError, e:
-                root_logger.error("Failed to obtain host TGT.")
+                ipautil.kinit_keytab(host_principal, paths.KRB5_KEYTAB,
+                                     CCACHE_FILE,
+                                     attempts=options.kinit_attempts)
+                env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = CCACHE_FILE
+            except Krb5Error as e:
+                print_port_conf_info()
+                root_logger.error("Failed to obtain host TGT: %s" % e)
                 # failure to get ticket makes it impossible to login and bind
                 # from sssd to LDAP, abort installation and rollback changes
                 return CLIENT_INSTALL_ERROR
@@ -2546,16 +2557,16 @@ def install(options, env, fstore, statestore):
             return CLIENT_INSTALL_ERROR
         root_logger.info("Configured /etc/sssd/sssd.conf")
 
-    host_principal = 'host/%s@%s' % (hostname, cli_realm)
     if options.on_master:
         # If on master assume kerberos is already configured properly.
         # Get the host TGT.
-        os.environ['KRB5CCNAME'] = CCACHE_FILE
         try:
-            run([paths.KINIT, '-k', '-t', paths.KRB5_KEYTAB,
-                    host_principal])
-        except CalledProcessError, e:
-            root_logger.error("Failed to obtain host TGT.")
+            ipautil.kinit_keytab(host_principal, paths.KRB5_KEYTAB,
+                                 CCACHE_FILE,
+                                 attempts=options.kinit_attempts)
+            os.environ['KRB5CCNAME'] = CCACHE_FILE
+        except Krb5Error as e:
+            root_logger.error("Failed to obtain host TGT: %s" % e)
             return CLIENT_INSTALL_ERROR
     else:
         # Configure krb5.conf
diff --git a/ipa-client/man/ipa-client-install.1 b/ipa-client/man/ipa-client-install.1
index 726a6c133132dd2e3ba2fde43d8a2ec0549bfcef..985cfb064917bba171c68956fc54a62202308892 100644
--- a/ipa-client/man/ipa-client-install.1
+++ b/ipa-client/man/ipa-client-install.1
@@ -152,6 +152,14 @@ Do not use Authconfig to modify the nsswitch.conf and PAM configuration.
 \fB\-f\fR, \fB\-\-force\fR
 Force the settings even if errors occur
 .TP
+\fB\-\-kinit\-attempts\fR=\fIKINIT_ATTEMPTS\fR
+In case of unresponsive KDC (e.g. when enrolling multiple hosts at once in a
+heavy load environment) repeat the request for host Kerberos ticket up to a
+total number of \fIKINIT_ATTEMPTS\fR times before giving up and aborting client
+installation. Default number of attempts is 5. The request is not repeated when
+there is a problem with host credentials themselves (e.g. wrong keytab format
+or invalid principal) so using this option will not lead to account lockouts.
+.TP
 \fB\-d\fR, \fB\-\-debug\fR
 Print debugging information to stdout
 .TP
-- 
2.1.0

From 2412cf2b8e1f77b4b17a9bea31aa879c6934da14 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Mon, 16 Mar 2015 16:43:10 +0100
Subject: [PATCH 3/3] Adopted kinit_keytab and kinit_password for kerberos auth

Calls to ipautil.run using kinit were replaced with calls
kinit_keytab/kinit_password functions implemented in the PATCH 0015.
---
 daemons/dnssec/ipa-dnskeysync-replica              |  6 ++-
 daemons/dnssec/ipa-dnskeysyncd                     |  4 +-
 daemons/dnssec/ipa-ods-exporter                    |  6 ++-
 .../certmonger/dogtag-ipa-ca-renew-agent-submit    |  4 +-
 install/restart_scripts/renew_ca_cert              |  8 ++--
 install/restart_scripts/renew_ra_cert              |  7 +++-
 ipa-client/ipa-install/ipa-client-automount        |  8 ++--
 ipa-client/ipaclient/ipa_certupdate.py             |  4 +-
 ipaserver/rpcserver.py                             | 46 ++++++++++------------
 9 files changed, 53 insertions(+), 40 deletions(-)

diff --git a/daemons/dnssec/ipa-dnskeysync-replica b/daemons/dnssec/ipa-dnskeysync-replica
index 8a0ae8a9aedf128e85e1a666cdb25b7dfe23c475..bcf9282153c9d105179d21237442598c1db530b5 100755
--- a/daemons/dnssec/ipa-dnskeysync-replica
+++ b/daemons/dnssec/ipa-dnskeysync-replica
@@ -139,14 +139,16 @@ log.setLevel(level=logging.DEBUG)
 # Kerberos initialization
 PRINCIPAL = str('%s/%s' % (DAEMONNAME, ipalib.api.env.host))
 log.debug('Kerberos principal: %s', PRINCIPAL)
-ipautil.kinit_hostprincipal(paths.IPA_DNSKEYSYNCD_KEYTAB, WORKDIR, PRINCIPAL)
+ccache_filename = os.path.join(WORKDIR, 'ccache')
+ipautil.kinit_keytab(PRINCIPAL, paths.IPA_DNSKEYSYNCD_KEYTAB, ccache_filename)
+os.environ['KRB5CCNAME'] = ccache_filename
 log.debug('Got TGT')
 
 # LDAP initialization
 ldap = ipalib.api.Backend[ldap2]
 # fixme
 log.debug('Connecting to LDAP')
-ldap.connect(ccache="%s/ccache" % WORKDIR)
+ldap.connect(ccache=ccache_filename)
 log.debug('Connected')
 
 
diff --git a/daemons/dnssec/ipa-dnskeysyncd b/daemons/dnssec/ipa-dnskeysyncd
index 9191303438dd6419902a94b43043e46304c9c397..b17c8d94e8a3c35a2aa29a1ce697ffdef654eeda 100755
--- a/daemons/dnssec/ipa-dnskeysyncd
+++ b/daemons/dnssec/ipa-dnskeysyncd
@@ -65,7 +65,9 @@ log = root_logger
 # Kerberos initialization
 PRINCIPAL = str('%s/%s' % (DAEMONNAME, api.env.host))
 log.debug('Kerberos principal: %s', PRINCIPAL)
-ipautil.kinit_hostprincipal(KEYTAB_FB, WORKDIR, PRINCIPAL)
+ccache_filename = os.path.join(WORKDIR, 'ccache')
+ipautil.kinit_keytab(PRINCIPAL, KEYTAB_FB, ccache_filename)
+os.environ['KRB5CCNAME'] = ccache_filename
 
 # LDAP initialization
 basedn = DN(api.env.container_dns, api.env.basedn)
diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter
index 401f350878a980588cf6a36067335daae66ffc9c..6d33b79bbddb59a8194107a7f2455e56637bad17 100755
--- a/daemons/dnssec/ipa-ods-exporter
+++ b/daemons/dnssec/ipa-ods-exporter
@@ -399,7 +399,9 @@ ipalib.api.finalize()
 # Kerberos initialization
 PRINCIPAL = str('%s/%s' % (DAEMONNAME, ipalib.api.env.host))
 log.debug('Kerberos principal: %s', PRINCIPAL)
-ipautil.kinit_hostprincipal(paths.IPA_ODS_EXPORTER_KEYTAB, WORKDIR, PRINCIPAL)
+ccache_name = os.path.join(WORKDIR, 'ccache')
+ipautil.kinit_keytab(PRINCIPAL, paths.IPA_ODS_EXPORTER_KEYTAB, ccache_name)
+os.environ['KRB5CCNAME'] = ccache_name
 log.debug('Got TGT')
 
 # LDAP initialization
@@ -407,7 +409,7 @@ dns_dn = DN(ipalib.api.env.container_dns, ipalib.api.env.basedn)
 ldap = ipalib.api.Backend[ldap2]
 # fixme
 log.debug('Connecting to LDAP')
-ldap.connect(ccache="%s/ccache" % WORKDIR)
+ldap.connect(ccache=ccache_name)
 log.debug('Connected')
 
 
diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
index 7b91fc61148912c77d0ae962b3847d73e8d0720e..66f3bf742198a4793f8004b37e97b17bebe8f1b5 100755
--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit
+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
@@ -440,7 +440,9 @@ def main():
     certs.renewal_lock.acquire()
     try:
         principal = str('host/%s@%s' % (api.env.host, api.env.realm))
-        ipautil.kinit_hostprincipal(paths.KRB5_KEYTAB, tmpdir, principal)
+        ccache_filename = os.path.join(tmpdir, 'ccache')
+        os.environ['KRB5CCNAME'] = ccache_filename
+        ipautil.kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_filename)
 
         profile = os.environ.get('CERTMONGER_CA_PROFILE')
         if profile:
diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert
index c7bd5d74c5b4659b3ad66d630653ff6419868d99..95205e4481830817dfe5c3f0f8b4f3ea40af7a4b 100644
--- a/install/restart_scripts/renew_ca_cert
+++ b/install/restart_scripts/renew_ca_cert
@@ -21,6 +21,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import sys
+import os
 import syslog
 import tempfile
 import shutil
@@ -73,8 +74,9 @@ def _main():
     tmpdir = tempfile.mkdtemp(prefix="tmp-")
     try:
         principal = str('host/%s@%s' % (api.env.host, api.env.realm))
-        ccache = ipautil.kinit_hostprincipal(paths.KRB5_KEYTAB, tmpdir,
-                                             principal)
+        ccache_filename = os.path.join(tmpdir, 'ccache')
+        ipautil.kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_filename)
+        os.environ['KRB5CCNAME'] = ccache_filename
 
         ca = cainstance.CAInstance(host_name=api.env.host, ldapi=False)
         ca.update_cert_config(nickname, cert, configured_constants)
@@ -139,7 +141,7 @@ def _main():
             conn = None
             try:
                 conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri)
-                conn.connect(ccache=ccache)
+                conn.connect(ccache=ccache_filename)
             except Exception, e:
                 syslog.syslog(
                     syslog.LOG_ERR, "Failed to connect to LDAP: %s" % e)
diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert
index 7dae3562380e919b2cc5f53825820291fc93fdc5..1f8fcae6fa09033f7a5c6448e0bbef14a5f76844 100644
--- a/install/restart_scripts/renew_ra_cert
+++ b/install/restart_scripts/renew_ra_cert
@@ -21,6 +21,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import sys
+import os
 import syslog
 import tempfile
 import shutil
@@ -42,8 +43,10 @@ def _main():
     tmpdir = tempfile.mkdtemp(prefix="tmp-")
     try:
         principal = str('host/%s@%s' % (api.env.host, api.env.realm))
-        ccache = ipautil.kinit_hostprincipal(paths.KRB5_KEYTAB, tmpdir,
-                                             principal)
+        ccache_filename = os.path.join(tmpdir, 'ccache')
+        ipautil.kinit_keytab(principal, paths.KRB5_KEYTAB,
+                             ccache_filename)
+        os.environ['KRB5CCNAME'] = ccache_filename
 
         ca = cainstance.CAInstance(host_name=api.env.host, ldapi=False)
         if ca.is_renewal_master():
diff --git a/ipa-client/ipa-install/ipa-client-automount b/ipa-client/ipa-install/ipa-client-automount
index ca56f97832159c55cb7010db1b406b52c206462f..eee141812cace38ed795c3f3b4120bded2257d1b 100755
--- a/ipa-client/ipa-install/ipa-client-automount
+++ b/ipa-client/ipa-install/ipa-client-automount
@@ -26,6 +26,7 @@ import os
 import urlparse
 import time
 import tempfile
+from krbV import Krb5Error
 
 import SSSDConfig
 
@@ -431,10 +432,11 @@ def main():
     os.close(ccache_fd)
     try:
         try:
+            host_princ = str('host/%s@%s' % (api.env.host, api.env.realm))
+            ipautil.kinit_keytab(host_princ, paths.KRB5_KEYTAB, ccache_name)
             os.environ['KRB5CCNAME'] = ccache_name
-            ipautil.run([paths.KINIT, '-k', '-t', paths.KRB5_KEYTAB, 'host/%s@%s' % (api.env.host, api.env.realm)])
-        except ipautil.CalledProcessError, e:
-            sys.exit("Failed to obtain host TGT.")
+        except Krb5Error as e:
+            sys.exit("Failed to obtain host TGT: %s" % e)
         # Now we have a TGT, connect to IPA
         try:
             api.Backend.rpcclient.connect()
diff --git a/ipa-client/ipaclient/ipa_certupdate.py b/ipa-client/ipaclient/ipa_certupdate.py
index 5ec5026f5ff7bf93227ce0a551fbf5cf60b9175d..a9530674cc389d752bc10f8497cde6d99abd0a25 100644
--- a/ipa-client/ipaclient/ipa_certupdate.py
+++ b/ipa-client/ipaclient/ipa_certupdate.py
@@ -55,9 +55,11 @@ class CertUpdate(admintool.AdminTool):
         ldap = ipaldap.IPAdmin(server)
 
         tmpdir = tempfile.mkdtemp(prefix="tmp-")
+        ccache_name = os.path.join(tmpdir, 'ccache')
         try:
             principal = str('host/%s@%s' % (api.env.host, api.env.realm))
-            ipautil.kinit_hostprincipal(paths.KRB5_KEYTAB, tmpdir, principal)
+            ipautil.kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_name)
+            os.environ['KRB5CCNAME'] = ccache_name
 
             api.Backend.rpcclient.connect()
             try:
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index 4173ed918d2ce992aa79d18b2ac3338b35388918..2f771a0d15a68f17498a617bdeb44f89a3a3faee 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -30,6 +30,7 @@ import datetime
 import urlparse
 import json
 import traceback
+from krbV import Krb5Error
 
 import ldap.controls
 from pyasn1.type import univ, namedtype
@@ -958,8 +959,8 @@ class login_password(Backend, KerberosSession, HTTP_Status):
 
     def kinit(self, user, realm, password, ccache_name):
         # get http service ccache as an armor for FAST to enable OTP authentication
-        armor_principal = krb5_format_service_principal_name(
-            'HTTP', self.api.env.host, realm)
+        armor_principal = str(krb5_format_service_principal_name(
+            'HTTP', self.api.env.host, realm))
         keytab = paths.IPA_KEYTAB
         armor_name = "%sA_%s" % (krbccache_prefix, user)
         armor_path = os.path.join(krbccache_dir, armor_name)
@@ -967,34 +968,29 @@ class login_password(Backend, KerberosSession, HTTP_Status):
         self.debug('Obtaining armor ccache: principal=%s keytab=%s ccache=%s',
                    armor_principal, keytab, armor_path)
 
-        (stdout, stderr, returncode) = ipautil.run(
-            [paths.KINIT, '-kt', keytab, armor_principal],
-            env={'KRB5CCNAME': armor_path}, raiseonerr=False)
-
-        if returncode != 0:
-            raise CCacheError()
+        try:
+            ipautil.kinit_keytab(armor_principal, paths.IPA_KEYTAB, armor_path)
+        except Krb5Error as e:
+            raise CCacheError(str(e))
 
         # Format the user as a kerberos principal
         principal = krb5_format_principal_name(user, realm)
 
-        (stdout, stderr, returncode) = ipautil.run(
-            [paths.KINIT, principal, '-T', armor_path],
-            env={'KRB5CCNAME': ccache_name, 'LC_ALL': 'C'},
-            stdin=password, raiseonerr=False)
+        try:
+            ipautil.kinit_password(principal, password, ccache_name,
+                                   armor_ccache_name=armor_path)
 
-        self.debug('kinit: principal=%s returncode=%s, stderr="%s"',
-                   principal, returncode, stderr)
-
-        self.debug('Cleanup the armor ccache')
-        ipautil.run(
-            [paths.KDESTROY, '-A', '-c', armor_path],
-            env={'KRB5CCNAME': armor_path},
-            raiseonerr=False)
-
-        if returncode != 0:
-            if stderr.strip() == 'kinit: Cannot read password while getting initial credentials':
-                raise PasswordExpired(principal=principal, message=unicode(stderr))
-            raise InvalidSessionPassword(principal=principal, message=unicode(stderr))
+            self.debug('Cleanup the armor ccache')
+            ipautil.run(
+                [paths.KDESTROY, '-A', '-c', armor_path],
+                env={'KRB5CCNAME': armor_path},
+                raiseonerr=False)
+        except RuntimeError as e:
+            if ('kinit: Cannot read password while '
+                    'getting initial credentials') in str(e):
+                raise PasswordExpired(principal=principal, message=unicode(e))
+            raise InvalidSessionPassword(principal=principal,
+                                         message=unicode(e))
 
 class change_password(Backend, HTTP_Status):
 
-- 
2.1.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to