On 03/23/2015 03:13 PM, Simo Sorce wrote:
On Mon, 2015-03-23 at 14:22 +0100, Petr Spacek wrote:
On 23.3.2015 14:08, Simo Sorce wrote:
On Mon, 2015-03-23 at 12:48 +0100, Martin Babinsky wrote:
On 03/17/2015 06:00 PM, Simo Sorce wrote:
On Mon, 2015-03-16 at 13:30 +0100, Martin Babinsky wrote:
On 03/16/2015 12:15 PM, Martin Kosek wrote:
On 03/13/2015 05:37 PM, Martin Babinsky wrote:
Attaching the next iteration of patches.

I have tried my best to reword the ipa-client-install man page bit about the
new option. Any suggestions to further improve it are welcome.

I have also slightly modified the 'kinit_keytab' function so that in Kerberos
errors are reported for each attempt and the text of the last error is retained
when finally raising exception.

The approach looks very good. I think that my only concern with this patch is
this part:

+            ccache.init_creds_keytab(keytab=ktab, principal=princ)
...
+        except krbV.Krb5Error as e:
+            last_exc = str(e)
+            root_logger.debug("Attempt %d/%d: failed: %s"
+                              % (attempt, attempts, last_exc))
+            time.sleep(1)
+
+    root_logger.debug("Maximum number of attempts (%d) reached"
+                      % attempts)
+    raise StandardError("Error initializing principal %s: %s"
+                        % (principal, last_exc))

The problem here is that this function will raise the super-generic
StandardError instead of the proper with all the context and information about
the error that the caller can then process.

I think that

       except krbV.Krb5Error as e:
           if attempt == max_attempts:
               log something
               raise

would be better.


Yes that seems reasonable. I'm just thinking whether we should re-raise
Krb5Error or raise ipalib.errors.KerberosError? the latter options makes
more sense to me as we would not have to additionally import Krb5Error
everywhere and it would also make the resulting errors more consistent.

I am thinking about someting like this:

       except krbV.Krb5Error as e:
          if attempt == attempts:
              # log that we have reaches maximum number of attempts
              raise KerberosError(minor=str(e))

What do you think?

Are you retrying on any error ?
Please do *not* do that, if you retry many times on an error that
indicates the password is wrong you may end up locking an administrative
account. If you want to retry you should do it only for very specific
timeout errors.

Simo.


I have taken a look at the logs attached to the original BZ
(https://bugzilla.redhat.com/show_bug.cgi?id=1161722).

In ipaclient-install.log the kinit error is:

"Cannot contact any KDC for realm 'ITW.USPTO.GOV' while getting initial
credentials"

which can be translated to krbV.KRB5_KDC_UNREACH error. However,
krb5kdc.log (http://pastebin.test.redhat.com/271394) reports errors
which are seemingly unrelated to the root cause (kinit timing out on
getting host TGT).

Thus I'm not quite sure which errors should we chceck against in this
case, anyone care to advise? These are potential candidates:

KRB5KDC_ERR_SVC_UNAVAILABLE, "A service is not available that is
required to process the request"
KRB5KRB_ERR_RESPONSE_TOO_BIG,    "Response too big for UDP, retry with TCP"
KRB5_REALM_UNKNOWN,      "Cannot find KDC for requested realm"
KRB5_KDC_UNREACH,        "Cannot contact any KDC for requested realm"


The only ones that you should retry on, at first glance are
KRB5_KDC_UNREACH, KRB5KDC_ERR_SVC_UNAVAILABLE.

You should never see KRB5KRB_ERR_RESPONSE_TOO_BIG in the script as it
should be handled automatically by the library, and if you get
KRB5_REALM_UNKNOWN I do not think that retrying will make any
difference.

I might be wrong but I was under the impression that this feature was also for
workarounding replication delay - service is not available / key is not
present / something like that.

(This could happen if host/principal was added to one server but then the
client connected to another server or so.)

If we have that problem we should instead use a temporary krb5.conf file
that lists explicitly only the server we are joining.

Simo.


This is already done since ipa-3-0: by default only one server/KDC is used during client install so there are actually no problems with replication delay, only with KDC timeouts.

Anyway I'm sending updated patches.

--
Martin^3 Babinsky
From a3ff82d4ec311b056470905145f9d95f1c679c89 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
when KDC is unreachable for some reason.

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

---
 ipapython/ipautil.py | 67 ++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 52 insertions(+), 15 deletions(-)

diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 6a06a8e956552597dfd48128b60a1dd6a4cc92f6..f6b86538125f64069abac92630bbe5092be9a7d7 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(keytab, ccache_path, principal, attempts=1):
     """
-    Given a ccache directory and a principal kinit as that user.
+    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.
 
     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.
+    This function is also not thread-safe since it modifies environment
+    variables.
     """
-    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)))
+    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 path %s" % ccache_path)
+    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)
+            os.environ['KRB5CCNAME'] = ccache_path
+            ccache = krbV.CCache(name=ccache_path, 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)
+
+
+def kinit_password(principal, password, env={}, armor_ccache=""):
+    """perform interactive kinit as principal using password. Additional
+    enviroment variables can be specified using env. If using FAST for
+    web-based authentication, use armor_ccache to specify http service ccache.
+    """
+    root_logger.debug("Initializing principal %s using password" % principal)
+    args = [paths.KINIT, principal]
+    if armor_ccache:
+        root_logger.debug("Using armor ccache %s for FAST webauth"
+                          % armor_ccache)
+        args.extend(['-T', armor_ccache])
+    run(args, env=env, stdin=password)
+
 
 def dn_attribute_property(private_name):
     '''
-- 
2.1.0

From 01a3c7031a52aaa216c0745f93a12a5798ce6f9c 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 | 66 +++++++++++++++++--------------
 ipa-client/man/ipa-client-install.1       |  8 ++++
 2 files changed, 45 insertions(+), 29 deletions(-)

diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index 711fa06e8dea50e263f94d0d83b2b1c1be4e88d9..b13202c5c0d6520f1531d044bb224d88fc6845d8 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 validate_kinit_attempts_option(option, opt, value, parser):
+        if value < 1 or value > sys.maxint:
+            raise OptionValueError(
+                "Option %s expects an integer in range <1,%d>"
+                % (opt, sys.maxint))
+
+        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=validate_kinit_attempts_option,
+                           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",
@@ -2351,6 +2365,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
@@ -2371,7 +2386,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)),
@@ -2409,29 +2423,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, env)
+                except CalledProcessError 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(options.keytab, ccache_name,
+                                             host_principal,
+                                             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"
@@ -2501,12 +2509,13 @@ 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(paths.KRB5_KEYTAB, CCACHE_FILE,
+                                     host_principal,
+                                     attempts=options.kinit_attempts)
+            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
@@ -2543,16 +2552,15 @@ 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(paths.KRB5_KEYTAB, CCACHE_FILE,
+                                 host_principal,
+                                 attempts=options.kinit_attempts)
+        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 f036ddfa2f387c064c1a377d1f2540e162655366 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                     |  3 +-
 daemons/dnssec/ipa-ods-exporter                    |  5 ++-
 .../certmonger/dogtag-ipa-ca-renew-agent-submit    |  3 +-
 install/restart_scripts/renew_ca_cert              |  7 +--
 install/restart_scripts/renew_ra_cert              |  4 +-
 ipa-client/ipa-install/ipa-client-automount        | 10 +++--
 ipa-client/ipaclient/ipa_certupdate.py             |  3 +-
 ipaserver/rpcserver.py                             | 50 +++++++++++-----------
 9 files changed, 50 insertions(+), 41 deletions(-)

diff --git a/daemons/dnssec/ipa-dnskeysync-replica b/daemons/dnssec/ipa-dnskeysync-replica
index d04f360e04ee018dcdd1ba9b2ca42b1844617af9..f22be9b09978ac292ea584d4c7081020b2097dda 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, 'ipa-dnskeysync-replica.ccache')
+ipautil.kinit_keytab(paths.IPA_DNSKEYSYNCD_KEYTAB, ccache_filename,
+                     PRINCIPAL)
 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 54a08a1e6307e89b3f52e78bddbe28cda8ac1345..cf3ecc5a5f7ac40b7f52e1dfc42367130dac926e 100755
--- a/daemons/dnssec/ipa-dnskeysyncd
+++ b/daemons/dnssec/ipa-dnskeysyncd
@@ -65,7 +65,8 @@ 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_name = os.path.join(WORKDIR, 'ipa-dnskeysyncd.ccache')
+ipautil.kinit_keytab(KEYTAB_FB, ccache_name, PRINCIPAL)
 
 # 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 dc1851d3a34bb09c1a87c86d101b11afe35e49fe..4a6d387392146ea2cb48e6582bac513a36965d77 100755
--- a/daemons/dnssec/ipa-ods-exporter
+++ b/daemons/dnssec/ipa-ods-exporter
@@ -399,7 +399,8 @@ 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, 'ipa-ods-exporter.ccache')
+ipautil.kinit_keytab(paths.IPA_ODS_EXPORTER_KEYTAB, ccache_name, PRINCIPAL)
 log.debug('Got TGT')
 
 # LDAP initialization
@@ -407,7 +408,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..13d2c2a912d2fcf84053d36da5e07fc834f9cf25 100755
--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit
+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
@@ -440,7 +440,8 @@ 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)
+        ipautil.kinit_keytab(paths.KRB5_KEYTAB, os.path.join(tmpdir, 'ccache'),
+                             principal)
 
         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..67156122bb75f00a4c3f612697092e5bab3723fb 100644
--- a/install/restart_scripts/renew_ca_cert
+++ b/install/restart_scripts/renew_ca_cert
@@ -73,8 +73,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 = '%s/ccache' % tmpdir
+        ipautil.kinit_keytab(paths.KRB5_KEYTAB, ccache_filename,
+                             principal)
 
         ca = cainstance.CAInstance(host_name=api.env.host, ldapi=False)
         ca.update_cert_config(nickname, cert, configured_constants)
@@ -139,7 +140,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..6276de78e4528dc1caa39be6628094a9d00e5988 100644
--- a/install/restart_scripts/renew_ra_cert
+++ b/install/restart_scripts/renew_ra_cert
@@ -42,8 +42,8 @@ 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)
+        ipautil.kinit_keytab(paths.KRB5_KEYTAB, '%s/ccache' % tmpdir,
+                             principal)
 
         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..0edd768f437c709a553094a361c79b5c317ef8b6 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:
-            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.")
+            host_princ = str('host/%s@%s' % (api.env.host, api.env.realm))
+            ipautil.kinit_keytab(paths.KRB5_KEYTAB, ccache_name,
+                                 host_princ)
+        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..c2f0a53cf822c00e7804a7f340060b5c18b1b400 100644
--- a/ipa-client/ipaclient/ipa_certupdate.py
+++ b/ipa-client/ipaclient/ipa_certupdate.py
@@ -57,7 +57,8 @@ class CertUpdate(admintool.AdminTool):
         tmpdir = tempfile.mkdtemp(prefix="tmp-")
         try:
             principal = str('host/%s@%s' % (api.env.host, api.env.realm))
-            ipautil.kinit_hostprincipal(paths.KRB5_KEYTAB, tmpdir, principal)
+            ipautil.kinit_keytab(paths.KRB5_KEYTAB,
+                                 os.path.join(tmpdir, 'ccache'), principal)
 
             api.Backend.rpcclient.connect()
             try:
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index d6bc955b9d9910a24eec5df1def579310eb54786..6505d8a2fef133dfdb4e8a69d9a2d1f18445151e 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,33 @@ 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(paths.IPA_KEYTAB, armor_path,
+                                 armor_principal)
+        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,
+                                   env={'KRB5CCNAME': ccache_name,
+                                        'LC_ALL': 'C'},
+                                   armor_ccache=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 ipautil.CalledProcessError, e:
+            if ('kinit: Cannot read password while '
+                    'getting initial credentials') in e.output:
+                raise PasswordExpired(principal=principal,
+                                      message=unicode(e.output))
+            raise InvalidSessionPassword(principal=principal,
+                                         message=unicode(e.output))
 
 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