diff --git a/SOURCES/Add-KDC-policy-pluggable-interface.patch b/SOURCES/Add-KDC-policy-pluggable-interface.patch
new file mode 100644
index 0000000..19cb799
--- /dev/null
+++ b/SOURCES/Add-KDC-policy-pluggable-interface.patch
@@ -0,0 +1,995 @@
+From f12b57979012f93b339982ba335093d7c0d364f7 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 27 Jun 2017 17:15:39 -0400
+Subject: [PATCH] Add KDC policy pluggable interface
+
+Add the header include/krb5/kdcpolicy_plugin.h, defining a pluggable
+interface for modules to deny AS and TGS requests and set maximum
+ticket lifetimes.  This interface replaces the policy.c stub functions.
+
+Add check_kdcpolicy_as() and check_kdcpolicy_tgs() as entry functions.
+Call them after auth indicators and ticket lifetimes have been
+determined.
+
+Add a test module and a test script with basic kdcpolicy tests.  Add
+plugin interface documentation in doc/plugindev/policy.rst.
+
+Also authored by Matt Rogers <mrogers@redhat.com>.
+
+ticket: 8606 (new)
+(cherry picked from commit d0969f6a8170344031ef58fd2a161190f1edfb96)
+[rharwood@redhat.com: mention but do not use kadm_auth]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ doc/plugindev/index.rst                        |   1 +
+ doc/plugindev/kdcpolicy.rst                    |  24 +++
+ src/Makefile.in                                |   1 +
+ src/configure.in                               |   1 +
+ src/include/Makefile.in                        |   1 +
+ src/include/k5-int.h                           |   4 +-
+ src/include/k5-trace.h                         |   5 +
+ src/include/krb5/kdcpolicy_plugin.h            | 128 ++++++++++++
+ src/kdc/do_as_req.c                            |   7 +
+ src/kdc/do_tgs_req.c                           |   6 +
+ src/kdc/kdc_util.c                             |   7 -
+ src/kdc/kdc_util.h                             |  11 -
+ src/kdc/main.c                                 |   8 +
+ src/kdc/policy.c                               | 267 +++++++++++++++++++++----
+ src/kdc/policy.h                               |  19 +-
+ src/kdc/tgs_policy.c                           |   6 -
+ src/lib/krb5/krb/plugin.c                      |   4 +-
+ src/plugins/kdcpolicy/test/Makefile.in         |  20 ++
+ src/plugins/kdcpolicy/test/deps                |   0
+ src/plugins/kdcpolicy/test/main.c              | 111 ++++++++++
+ src/plugins/kdcpolicy/test/policy_test.exports |   1 +
+ src/tests/Makefile.in                          |   1 +
+ src/tests/t_kdcpolicy.py                       |  57 ++++++
+ 23 files changed, 616 insertions(+), 74 deletions(-)
+ create mode 100644 doc/plugindev/kdcpolicy.rst
+ create mode 100644 src/include/krb5/kdcpolicy_plugin.h
+ create mode 100644 src/plugins/kdcpolicy/test/Makefile.in
+ create mode 100644 src/plugins/kdcpolicy/test/deps
+ create mode 100644 src/plugins/kdcpolicy/test/main.c
+ create mode 100644 src/plugins/kdcpolicy/test/policy_test.exports
+ create mode 100644 src/tests/t_kdcpolicy.py
+
+diff --git a/doc/plugindev/index.rst b/doc/plugindev/index.rst
+index 67dbc2790..0a012b82b 100644
+--- a/doc/plugindev/index.rst
++++ b/doc/plugindev/index.rst
+@@ -32,5 +32,6 @@ Contents
+    gssapi.rst
+    internal.rst
+    certauth.rst
++   kdcpolicy.rst
+ 
+ .. TODO: GSSAPI mechanism plugins
+diff --git a/doc/plugindev/kdcpolicy.rst b/doc/plugindev/kdcpolicy.rst
+new file mode 100644
+index 000000000..74f21f08f
+--- /dev/null
++++ b/doc/plugindev/kdcpolicy.rst
+@@ -0,0 +1,24 @@
++.. _kdcpolicy_plugin:
++
++KDC policy interface (kdcpolicy)
++================================
++
++The kdcpolicy interface was first introduced in release 1.16.  It
++allows modules to veto otherwise valid AS and TGS requests or restrict
++the lifetime and renew time of the resulting ticket.  For a detailed
++description of the kdcpolicy interface, see the header file
++``<krb5/kdcpolicy_plugin.h>``.
++
++The optional **check_as** and **check_tgs** functions allow the module
++to perform access control.  Additionally, a module can create and
++destroy module data with the **init** and **fini** methods.  Module
++data objects last for the lifetime of the KDC process, and are
++provided to all other methods.  The data has the type
++krb5_kdcpolicy_moddata, which should be cast to the appropriate
++internal type.
++
++kdcpolicy modules can optionally inspect principal entries.  To do
++this, the module must also include ``<kdb.h>`` to gain access to the
++principal entry structure definition.  As the KDB interface is
++explicitly not as stable as other public interfaces, modules which do
++this may not retain compatibility across releases.
+diff --git a/src/Makefile.in b/src/Makefile.in
+index ad8565056..e47bddcb1 100644
+--- a/src/Makefile.in
++++ b/src/Makefile.in
+@@ -21,6 +21,7 @@ SUBDIRS=util include lib \
+ 	plugins/kdb/db2 \
+ 	@ldap_plugin_dir@ \
+ 	plugins/kdb/test \
++	plugins/kdcpolicy/test \
+ 	plugins/preauth/otp \
+ 	plugins/preauth/pkinit \
+ 	plugins/preauth/test \
+diff --git a/src/configure.in b/src/configure.in
+index 4ae2c07d5..ee1983043 100644
+--- a/src/configure.in
++++ b/src/configure.in
+@@ -1470,6 +1470,7 @@ dnl	ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test
+ 	plugins/kdb/db2/libdb2/recno
+ 	plugins/kdb/db2/libdb2/test
+ 	plugins/kdb/test
++	plugins/kdcpolicy/test
+ 	plugins/preauth/otp
+ 	plugins/preauth/test
+ 	plugins/authdata/greet_client
+diff --git a/src/include/Makefile.in b/src/include/Makefile.in
+index 0239338a1..6a3fa8242 100644
+--- a/src/include/Makefile.in
++++ b/src/include/Makefile.in
+@@ -144,6 +144,7 @@ install-headers-unix install: krb5/krb5.h profile.h
+ 	$(INSTALL_DATA) $(srcdir)/krb5/ccselect_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)ccselect_plugin.h
+ 	$(INSTALL_DATA) $(srcdir)/krb5/clpreauth_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)clpreauth_plugin.h
+ 	$(INSTALL_DATA) $(srcdir)/krb5/hostrealm_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)hostrealm_plugin.h
++	$(INSTALL_DATA) $(srcdir)/krb5/kdcpolicy_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)kdcpolicy_plugin.h
+ 	$(INSTALL_DATA) $(srcdir)/krb5/kdcpreauth_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)kdcpreauth_plugin.h
+ 	$(INSTALL_DATA) $(srcdir)/krb5/localauth_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)localauth_plugin.h
+ 	$(INSTALL_DATA) $(srcdir)/krb5/locate_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)locate_plugin.h
+diff --git a/src/include/k5-int.h b/src/include/k5-int.h
+index ed9c7bf75..39ffb9568 100644
+--- a/src/include/k5-int.h
++++ b/src/include/k5-int.h
+@@ -1157,7 +1157,9 @@ struct plugin_interface {
+ #define PLUGIN_INTERFACE_TLS         8
+ #define PLUGIN_INTERFACE_KDCAUTHDATA 9
+ #define PLUGIN_INTERFACE_CERTAUTH    10
+-#define PLUGIN_NUM_INTERFACES        11
++#define PLUGIN_INTERFACE_KADM5_AUTH  11
++#define PLUGIN_INTERFACE_KDCPOLICY   12
++#define PLUGIN_NUM_INTERFACES        13
+ 
+ /* Retrieve the plugin module of type interface_id and name modname,
+  * storing the result into module. */
+diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h
+index c75e264e0..2885408a2 100644
+--- a/src/include/k5-trace.h
++++ b/src/include/k5-trace.h
+@@ -454,4 +454,9 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
+ #define TRACE_GET_CRED_VIA_TKT_EXT_RETURN(c, ret) \
+     TRACE(c, "Got cred; {kerr}", ret)
+ 
++#define TRACE_KDCPOLICY_VTINIT_FAIL(c, ret)                             \
++    TRACE(c, "KDC policy module failed to init vtable: {kerr}", ret)
++#define TRACE_KDCPOLICY_INIT_SKIP(c, name)                              \
++    TRACE(c, "kadm5_auth module {str} declined to initialize", name)
++
+ #endif /* K5_TRACE_H */
+diff --git a/src/include/krb5/kdcpolicy_plugin.h b/src/include/krb5/kdcpolicy_plugin.h
+new file mode 100644
+index 000000000..c7592c5db
+--- /dev/null
++++ b/src/include/krb5/kdcpolicy_plugin.h
+@@ -0,0 +1,128 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* include/krb5/kdcpolicy_plugin.h - KDC policy plugin interface */
++/*
++ * Copyright (C) 2017 by Red Hat, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ *
++ * * Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in
++ *   the documentation and/or other materials provided with the
++ *   distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
++ * OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ * Declarations for kdcpolicy plugin module implementors.
++ *
++ * The kdcpolicy pluggable interface currently has only one supported major
++ * version, which is 1.  Major version 1 has a current minor version number of
++ * 1.
++ *
++ * kdcpolicy plugin modules should define a function named
++ * kdcpolicy_<modulename>_initvt, matching the signature:
++ *
++ *   krb5_error_code
++ *   kdcpolicy_modname_initvt(krb5_context context, int maj_ver, int min_ver,
++ *                            krb5_plugin_vtable vtable);
++ *
++ * The initvt function should:
++ *
++ * - Check that the supplied maj_ver number is supported by the module, or
++ *   return KRB5_PLUGIN_VER_NOTSUPP if it is not.
++ *
++ * - Cast the vtable pointer as appropriate for maj_ver:
++ *   maj_ver == 1: Cast to krb5_kdcpolicy_vtable
++ *
++ * - Initialize the methods of the vtable, stopping as appropriate for the
++ *   supplied min_ver.  Optional methods may be left uninitialized.
++ *
++ * Memory for the vtable is allocated by the caller, not by the module.
++ */
++
++#ifndef KRB5_POLICY_PLUGIN_H
++#define KRB5_POLICY_PLUGIN_H
++
++#include <krb5/krb5.h>
++
++/* Abstract module datatype. */
++typedef struct krb5_kdcpolicy_moddata_st *krb5_kdcpolicy_moddata;
++
++/* A module can optionally include kdb.h to inspect principal entries when
++ * authorizing requests. */
++struct _krb5_db_entry_new;
++
++/*
++ * Optional: Initialize module data.  Return 0 on success,
++ * KRB5_PLUGIN_NO_HANDLE if the module is inoperable (due to configuration, for
++ * example), and any other error code to abort KDC startup.  Optionally set
++ * *data_out to a module data object to be passed to future calls.
++ */
++typedef krb5_error_code
++(*krb5_kdcpolicy_init_fn)(krb5_context context,
++                          krb5_kdcpolicy_moddata *data_out);
++
++/* Optional: Clean up module data. */
++typedef krb5_error_code
++(*krb5_kdcpolicy_fini_fn)(krb5_context context,
++                          krb5_kdcpolicy_moddata moddata);
++
++/*
++ * Optional: return an error code and set status to an appropriate string
++ * literal to deny an AS request; otherwise return 0.  lifetime_out, if set,
++ * restricts the ticket lifetime.  renew_lifetime_out, if set, restricts the
++ * ticket renewable lifetime.
++ */
++typedef krb5_error_code
++(*krb5_kdcpolicy_check_as_fn)(krb5_context context,
++                              krb5_kdcpolicy_moddata moddata,
++                              const krb5_kdc_req *request,
++                              const struct _krb5_db_entry_new *client,
++                              const struct _krb5_db_entry_new *server,
++                              const char *const *auth_indicators,
++                              const char **status, krb5_deltat *lifetime_out,
++                              krb5_deltat *renew_lifetime_out);
++
++/*
++ * Optional: return an error code and set status to an appropriate string
++ * literal to deny a TGS request; otherwise return 0.  lifetime_out, if set,
++ * restricts the ticket lifetime.  renew_lifetime_out, if set, restricts the
++ * ticket renewable lifetime.
++ */
++typedef krb5_error_code
++(*krb5_kdcpolicy_check_tgs_fn)(krb5_context context,
++                               krb5_kdcpolicy_moddata moddata,
++                               const krb5_kdc_req *request,
++                               const struct _krb5_db_entry_new *server,
++                               const krb5_ticket *ticket,
++                               const char *const *auth_indicators,
++                               const char **status, krb5_deltat *lifetime_out,
++                               krb5_deltat *renew_lifetime_out);
++
++typedef struct krb5_kdcpolicy_vtable_st {
++    const char *name;
++    krb5_kdcpolicy_init_fn init;
++    krb5_kdcpolicy_fini_fn fini;
++    krb5_kdcpolicy_check_as_fn check_as;
++    krb5_kdcpolicy_check_tgs_fn check_tgs;
++} *krb5_kdcpolicy_vtable;
++
++#endif /* KRB5_POLICY_PLUGIN_H */
+diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
+index 59a39cd30..241b05b40 100644
+--- a/src/kdc/do_as_req.c
++++ b/src/kdc/do_as_req.c
+@@ -207,6 +207,13 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
+ 
+     state->ticket_reply.enc_part2 = &state->enc_tkt_reply;
+ 
++    errcode = check_kdcpolicy_as(kdc_context, state->request, state->client,
++                                 state->server, state->auth_indicators,
++                                 state->kdc_time, &state->enc_tkt_reply.times,
++                                 &state->status);
++    if (errcode)
++        goto egress;
++
+     /*
+      * Find the server key
+      */
+diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
+index aacd2f20d..4c722a4a3 100644
+--- a/src/kdc/do_tgs_req.c
++++ b/src/kdc/do_tgs_req.c
+@@ -518,6 +518,12 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt,
+     kdc_get_ticket_renewtime(kdc_active_realm, request, header_enc_tkt, client,
+                              server, &enc_tkt_reply);
+ 
++    errcode = check_kdcpolicy_tgs(kdc_context, request, server, header_ticket,
++                                  auth_indicators, kdc_time,
++                                  &enc_tkt_reply.times, &status);
++    if (errcode)
++        goto cleanup;
++
+     /*
+      * Set authtime to be the same as header or evidence ticket's
+      */
+diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
+index 778a629e5..8cbdf2c5b 100644
+--- a/src/kdc/kdc_util.c
++++ b/src/kdc/kdc_util.c
+@@ -642,7 +642,6 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
+                     krb5_db_entry server, krb5_timestamp kdc_time,
+                     const char **status, krb5_pa_data ***e_data)
+ {
+-    int errcode;
+     krb5_error_code ret;
+ 
+     /*
+@@ -750,12 +749,6 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
+     if (ret && ret != KRB5_PLUGIN_OP_NOTSUPP)
+         return errcode_to_protocol(ret);
+ 
+-    /* Check against local policy. */
+-    errcode = against_local_policy_as(request, client, server,
+-                                      kdc_time, status, e_data);
+-    if (errcode)
+-        return errcode;
+-
+     return 0;
+ }
+ 
+diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
+index 672f94380..dcedfd538 100644
+--- a/src/kdc/kdc_util.h
++++ b/src/kdc/kdc_util.h
+@@ -166,17 +166,6 @@ kdc_err(krb5_context call_context, errcode_t code, const char *fmt, ...)
+ #endif
+     ;
+ 
+-/* policy.c */
+-int
+-against_local_policy_as (krb5_kdc_req *, krb5_db_entry,
+-                         krb5_db_entry, krb5_timestamp,
+-                         const char **, krb5_pa_data ***);
+-
+-int
+-against_local_policy_tgs (krb5_kdc_req *, krb5_db_entry,
+-                          krb5_ticket *, const char **,
+-                          krb5_pa_data ***);
+-
+ /* kdc_preauth.c */
+ krb5_boolean
+ enctype_requires_etype_info_2(krb5_enctype enctype);
+diff --git a/src/kdc/main.c b/src/kdc/main.c
+index a4dffb29a..ccac3a759 100644
+--- a/src/kdc/main.c
++++ b/src/kdc/main.c
+@@ -31,6 +31,7 @@
+ #include "kdc_util.h"
+ #include "kdc_audit.h"
+ #include "extern.h"
++#include "policy.h"
+ #include "kdc5_err.h"
+ #include "kdb_kt.h"
+ #include "net-server.h"
+@@ -986,6 +987,12 @@ int main(int argc, char **argv)
+ 
+     load_preauth_plugins(&shandle, kcontext, ctx);
+     load_authdata_plugins(kcontext);
++    retval = load_kdcpolicy_plugins(kcontext);
++    if (retval) {
++        kdc_err(kcontext, retval, _("while loading KDC policy plugin"));
++        finish_realms();
++        return 1;
++    }
+ 
+     retval = setup_sam();
+     if (retval) {
+@@ -1068,6 +1075,7 @@ int main(int argc, char **argv)
+     krb5_klog_syslog(LOG_INFO, _("shutting down"));
+     unload_preauth_plugins(kcontext);
+     unload_authdata_plugins(kcontext);
++    unload_kdcpolicy_plugins(kcontext);
+     unload_audit_modules(kcontext);
+     krb5_klog_close(kcontext);
+     finish_realms();
+diff --git a/src/kdc/policy.c b/src/kdc/policy.c
+index 6cba4303f..e49644e06 100644
+--- a/src/kdc/policy.c
++++ b/src/kdc/policy.c
+@@ -1,67 +1,246 @@
+ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+ /* kdc/policy.c - Policy decision routines for KDC */
+ /*
+- * Copyright 1990 by the Massachusetts Institute of Technology.
++ * Copyright (C) 2017 by Red Hat, Inc.
++ * All rights reserved.
+  *
+- * Export of this software from the United States of America may
+- *   require a specific license from the United States Government.
+- *   It is the responsibility of any person or organization contemplating
+- *   export to obtain such a license before exporting.
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
+  *
+- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+- * distribute this software and its documentation for any purpose and
+- * without fee is hereby granted, provided that the above copyright
+- * notice appear in all copies and that both that copyright notice and
+- * this permission notice appear in supporting documentation, and that
+- * the name of M.I.T. not be used in advertising or publicity pertaining
+- * to distribution of the software without specific, written prior
+- * permission.  Furthermore if you modify this software you must label
+- * your software as modified software and not distribute it in such a
+- * fashion that it might be confused with the original M.I.T. software.
+- * M.I.T. makes no representations about the suitability of
+- * this software for any purpose.  It is provided "as is" without express
+- * or implied warranty.
++ * * Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ *
++ * * Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in
++ *   the documentation and/or other materials provided with the
++ *   distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
++ * OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+ #include "k5-int.h"
+ #include "kdc_util.h"
+ #include "extern.h"
++#include "policy.h"
++#include "adm_proto.h"
++#include <krb5/kdcpolicy_plugin.h>
++#include <syslog.h>
+ 
+-int
+-against_local_policy_as(register krb5_kdc_req *request, krb5_db_entry client,
+-                        krb5_db_entry server, krb5_timestamp kdc_time,
+-                        const char **status, krb5_pa_data ***e_data)
++typedef struct kdcpolicy_handle_st {
++    struct krb5_kdcpolicy_vtable_st vt;
++    krb5_kdcpolicy_moddata moddata;
++} *kdcpolicy_handle;
++
++static kdcpolicy_handle *handles;
++
++static void
++free_indicators(char **ais)
+ {
+-#if 0
+-    /* An AS request must include the addresses field */
+-    if (request->addresses == 0) {
+-        *status = "NO ADDRESS";
+-        return KRB5KDC_ERR_POLICY;
+-    }
+-#endif
++    size_t i;
+ 
+-    return 0;                   /* not against policy */
++    if (ais == NULL)
++        return;
++    for (i = 0; ais[i] != NULL; i++)
++        free(ais[i]);
++    free(ais);
++}
++
++/* Convert inds to a null-terminated list of C strings. */
++static krb5_error_code
++authind_strings(krb5_data *const *inds, char ***strs_out)
++{
++    krb5_error_code ret;
++    char **list = NULL;
++    size_t i, count;
++
++    *strs_out = NULL;
++
++    for (count = 0; inds != NULL && inds[count] != NULL; count++);
++    list = k5calloc(count + 1, sizeof(*list), &ret);
++    if (list == NULL)
++        goto error;
++
++    for (i = 0; i < count; i++) {
++        list[i] = k5memdup0(inds[i]->data, inds[i]->length, &ret);
++        if (list[i] == NULL)
++            goto error;
++    }
++
++    *strs_out = list;
++    return 0;
++
++error:
++    free_indicators(list);
++    return ret;
++}
++
++/* Constrain times->endtime to life and times->renew_till to rlife, relative to
++ * now. */
++static void
++update_ticket_times(krb5_ticket_times *times, krb5_timestamp now,
++                    krb5_deltat life, krb5_deltat rlife)
++{
++    if (life)
++        times->endtime = ts_min(ts_incr(now, life), times->endtime);
++    if (rlife)
++        times->renew_till = ts_min(ts_incr(now, rlife), times->renew_till);
++}
++
++/* Check an AS request against kdcpolicy modules, updating times with any
++ * module endtime constraints.  Set an appropriate status string on error. */
++krb5_error_code
++check_kdcpolicy_as(krb5_context context, const krb5_kdc_req *request,
++                   const krb5_db_entry *client, const krb5_db_entry *server,
++                   krb5_data *const *auth_indicators, krb5_timestamp kdc_time,
++                   krb5_ticket_times *times, const char **status)
++{
++    krb5_deltat life, rlife;
++    krb5_error_code ret;
++    kdcpolicy_handle *hp, h;
++    char **ais = NULL;
++
++    *status = NULL;
++
++    ret = authind_strings(auth_indicators, &ais);
++    if (ret)
++        goto done;
++
++    for (hp = handles; *hp != NULL; hp++) {
++        h = *hp;
++        if (h->vt.check_as == NULL)
++            continue;
++
++        ret = h->vt.check_as(context, h->moddata, request, client, server,
++                             (const char **)ais, status, &life, &rlife);
++        if (ret)
++            goto done;
++
++        update_ticket_times(times, kdc_time, life, rlife);
++    }
++
++done:
++    free_indicators(ais);
++    return ret;
+ }
+ 
+ /*
+- * This is where local policy restrictions for the TGS should placed.
++ * Check the TGS request against the local TGS policy.  Accepts an
++ * authentication indicator for the module policy decisions.  Returns 0 and a
++ * NULL status string on success.
+  */
+ krb5_error_code
+-against_local_policy_tgs(register krb5_kdc_req *request, krb5_db_entry server,
+-                         krb5_ticket *ticket, const char **status,
+-                         krb5_pa_data ***e_data)
++check_kdcpolicy_tgs(krb5_context context, const krb5_kdc_req *request,
++                    const krb5_db_entry *server, const krb5_ticket *ticket,
++                    krb5_data *const *auth_indicators, krb5_timestamp kdc_time,
++                    krb5_ticket_times *times, const char **status)
+ {
+-#if 0
+-    /*
+-     * For example, if your site wants to disallow ticket forwarding,
+-     * you might do something like this:
+-     */
++    krb5_deltat life, rlife;
++    krb5_error_code ret;
++    kdcpolicy_handle *hp, h;
++    char **ais = NULL;
+ 
+-    if (isflagset(request->kdc_options, KDC_OPT_FORWARDED)) {
+-        *status = "FORWARD POLICY";
+-        return KRB5KDC_ERR_POLICY;
++    *status = NULL;
++
++    ret = authind_strings(auth_indicators, &ais);
++    if (ret)
++        goto done;
++
++    for (hp = handles; *hp != NULL; hp++) {
++        h = *hp;
++        if (h->vt.check_tgs == NULL)
++            continue;
++
++        ret = h->vt.check_tgs(context, h->moddata, request, server, ticket,
++                              (const char **)ais, status, &life, &rlife);
++        if (ret)
++            goto done;
++
++        update_ticket_times(times, kdc_time, life, rlife);
+     }
+-#endif
+ 
+-    return 0;                           /* not against policy */
++done:
++    free_indicators(ais);
++    return ret;
++}
++
++void
++unload_kdcpolicy_plugins(krb5_context context)
++{
++    kdcpolicy_handle *hp, h;
++
++    for (hp = handles; *hp != NULL; hp++) {
++        h = *hp;
++        if (h->vt.fini != NULL)
++            h->vt.fini(context, h->moddata);
++        free(h);
++    }
++    free(handles);
++    handles = NULL;
++}
++
++krb5_error_code
++load_kdcpolicy_plugins(krb5_context context)
++{
++    krb5_error_code ret;
++    krb5_plugin_initvt_fn *modules = NULL, *mod;
++    kdcpolicy_handle h;
++    size_t count;
++
++    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_KDCPOLICY, &modules);
++    if (ret)
++        goto cleanup;
++
++    for (count = 0; modules[count] != NULL; count++);
++    handles = k5calloc(count + 1, sizeof(*handles), &ret);
++    if (handles == NULL)
++        goto cleanup;
++
++    count = 0;
++    for (mod = modules; *mod != NULL; mod++) {
++        h = k5calloc(1, sizeof(*h), &ret);
++        if (h == NULL)
++            goto cleanup;
++
++        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&h->vt);
++        if (ret) {              /* Version mismatch. */
++            TRACE_KDCPOLICY_VTINIT_FAIL(context, ret);
++            free(h);
++            continue;
++        }
++        if (h->vt.init != NULL) {
++            ret = h->vt.init(context, &h->moddata);
++            if (ret == KRB5_PLUGIN_NO_HANDLE) {
++                TRACE_KADM5_AUTH_INIT_SKIP(context, h->vt.name);
++                free(h);
++                continue;
++            }
++            if (ret) {
++                kdc_err(context, ret, _("while loading policy module %s"),
++                        h->vt.name);
++                free(h);
++                goto cleanup;
++            }
++        }
++        handles[count++] = h;
++    }
++
++    ret = 0;
++
++cleanup:
++    if (ret)
++        unload_kdcpolicy_plugins(context);
++    k5_plugin_free_modules(context, modules);
++    return ret;
+ }
+diff --git a/src/kdc/policy.h b/src/kdc/policy.h
+index 6b000dc90..2a57b0a01 100644
+--- a/src/kdc/policy.h
++++ b/src/kdc/policy.h
+@@ -26,11 +26,22 @@
+ #ifndef __KRB5_KDC_POLICY__
+ #define __KRB5_KDC_POLICY__
+ 
+-extern int against_postdate_policy (krb5_timestamp);
++krb5_error_code
++load_kdcpolicy_plugins(krb5_context context);
+ 
+-extern int against_flag_policy_as (const krb5_kdc_req *);
++void
++unload_kdcpolicy_plugins(krb5_context context);
+ 
+-extern int against_flag_policy_tgs (const krb5_kdc_req *,
+-                                    const krb5_ticket *);
++krb5_error_code
++check_kdcpolicy_as(krb5_context context, const krb5_kdc_req *request,
++                   const krb5_db_entry *client, const krb5_db_entry *server,
++                   krb5_data *const *auth_indicators, krb5_timestamp kdc_time,
++                   krb5_ticket_times *times, const char **status);
++
++krb5_error_code
++check_kdcpolicy_tgs(krb5_context context, const krb5_kdc_req *request,
++                    const krb5_db_entry *server, const krb5_ticket *ticket,
++                    krb5_data *const *auth_indicators, krb5_timestamp kdc_time,
++                    krb5_ticket_times *times, const char **status);
+ 
+ #endif /* __KRB5_KDC_POLICY__ */
+diff --git a/src/kdc/tgs_policy.c b/src/kdc/tgs_policy.c
+index d0f25d1b7..33cfbcd81 100644
+--- a/src/kdc/tgs_policy.c
++++ b/src/kdc/tgs_policy.c
+@@ -375,11 +375,5 @@ validate_tgs_request(kdc_realm_t *kdc_active_realm,
+     if (ret && ret != KRB5_PLUGIN_OP_NOTSUPP)
+         return errcode_to_protocol(ret);
+ 
+-    /* Check local policy. */
+-    errcode = against_local_policy_tgs(request, server, ticket,
+-                                       status, e_data);
+-    if (errcode)
+-        return errcode;
+-
+     return 0;
+ }
+diff --git a/src/lib/krb5/krb/plugin.c b/src/lib/krb5/krb/plugin.c
+index 17dd6bd30..31aaf661d 100644
+--- a/src/lib/krb5/krb/plugin.c
++++ b/src/lib/krb5/krb/plugin.c
+@@ -58,7 +58,9 @@ const char *interface_names[] = {
+     "audit",
+     "tls",
+     "kdcauthdata",
+-    "certauth"
++    "certauth",
++    "kadm5_auth",
++    "kdcpolicy",
+ };
+ 
+ /* Return the context's interface structure for id, or NULL if invalid. */
+diff --git a/src/plugins/kdcpolicy/test/Makefile.in b/src/plugins/kdcpolicy/test/Makefile.in
+new file mode 100644
+index 000000000..b81f1a7ce
+--- /dev/null
++++ b/src/plugins/kdcpolicy/test/Makefile.in
+@@ -0,0 +1,20 @@
++mydir=plugins$(S)policy$(S)test
++BUILDTOP=$(REL)..$(S)..$(S)..
++
++LIBBASE=policy_test
++LIBMAJOR=0
++LIBMINOR=0
++RELDIR=../plugins/kdcpolicy/test
++SHLIB_EXPDEPS=$(KRB5_BASE_DEPLIBS)
++SHLIB_EXPLIBS=$(KRB5_BASE_LIBS)
++
++STLIBOBJS=main.o
++
++SRCS=$(srcdir)/main.c
++
++all-unix: all-libs
++install-unix:
++clean-unix:: clean-libs clean-libobjs
++
++@libnover_frag@
++@libobj_frag@
+diff --git a/src/plugins/kdcpolicy/test/deps b/src/plugins/kdcpolicy/test/deps
+new file mode 100644
+index 000000000..e69de29bb
+diff --git a/src/plugins/kdcpolicy/test/main.c b/src/plugins/kdcpolicy/test/main.c
+new file mode 100644
+index 000000000..eb8fde053
+--- /dev/null
++++ b/src/plugins/kdcpolicy/test/main.c
+@@ -0,0 +1,111 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* include/krb5/kdcpolicy_plugin.h - KDC policy plugin interface */
++/*
++ * Copyright (C) 2017 by Red Hat, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ *
++ * * Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in
++ *   the documentation and/or other materials provided with the
++ *   distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
++ * OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "k5-int.h"
++#include "kdb.h"
++#include <krb5/kdcpolicy_plugin.h>
++
++static krb5_error_code
++output_from_indicator(const char *const *auth_indicators,
++                      krb5_deltat *lifetime_out,
++                      krb5_deltat *renew_lifetime_out,
++                      const char **status)
++{
++    if (auth_indicators[0] == NULL) {
++        *status = NULL;
++        return 0;
++    }
++
++    if (strcmp(auth_indicators[0], "ONE_HOUR") == 0) {
++        *lifetime_out = 3600;
++        *renew_lifetime_out = *lifetime_out * 2;
++        return 0;
++    } else if (strcmp(auth_indicators[0], "SEVEN_HOURS") == 0) {
++        *lifetime_out = 7 * 3600;
++        *renew_lifetime_out = *lifetime_out * 2;
++        return 0;
++    }
++
++    *status = "LOCAL_POLICY";
++    return KRB5KDC_ERR_POLICY;
++}
++
++static krb5_error_code
++test_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
++              const krb5_kdc_req *request, const krb5_db_entry *client,
++              const krb5_db_entry *server, const char *const *auth_indicators,
++              const char **status, krb5_deltat *lifetime_out,
++              krb5_deltat *renew_lifetime_out)
++{
++    if (request->client != NULL && request->client->length >= 1 &&
++        data_eq_string(request->client->data[0], "fail")) {
++        *status = "LOCAL_POLICY";
++        return KRB5KDC_ERR_POLICY;
++    }
++    return output_from_indicator(auth_indicators, lifetime_out,
++                                 renew_lifetime_out, status);
++}
++
++static krb5_error_code
++test_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
++               const krb5_kdc_req *request, const krb5_db_entry *server,
++               const krb5_ticket *ticket, const char *const *auth_indicators,
++               const char **status, krb5_deltat *lifetime_out,
++               krb5_deltat *renew_lifetime_out)
++{
++    if (request->server != NULL && request->server->length >= 1 &&
++        data_eq_string(request->server->data[0], "fail")) {
++        *status = "LOCAL_POLICY";
++        return KRB5KDC_ERR_POLICY;
++    }
++    return output_from_indicator(auth_indicators, lifetime_out,
++                                 renew_lifetime_out, status);
++}
++
++krb5_error_code
++kdcpolicy_test_initvt(krb5_context context, int maj_ver, int min_ver,
++                      krb5_plugin_vtable vtable);
++krb5_error_code
++kdcpolicy_test_initvt(krb5_context context, int maj_ver, int min_ver,
++                      krb5_plugin_vtable vtable)
++{
++    krb5_kdcpolicy_vtable vt;
++
++    if (maj_ver != 1)
++        return KRB5_PLUGIN_VER_NOTSUPP;
++
++    vt = (krb5_kdcpolicy_vtable)vtable;
++    vt->name = "test";
++    vt->check_as = test_check_as;
++    vt->check_tgs = test_check_tgs;
++    return 0;
++}
+diff --git a/src/plugins/kdcpolicy/test/policy_test.exports b/src/plugins/kdcpolicy/test/policy_test.exports
+new file mode 100644
+index 000000000..9682ec74f
+--- /dev/null
++++ b/src/plugins/kdcpolicy/test/policy_test.exports
+@@ -0,0 +1 @@
++kdcpolicy_test_initvt
+diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
+index 2b3112537..a2093108b 100644
+--- a/src/tests/Makefile.in
++++ b/src/tests/Makefile.in
+@@ -169,6 +169,7 @@ check-pytests: localauth plugorder rdreq responder s2p s4u2proxy unlockiter
+ 	$(RUNPYTEST) $(srcdir)/t_tabdump.py $(PYTESTFLAGS)
+ 	$(RUNPYTEST) $(srcdir)/t_certauth.py $(PYTESTFLAGS)
+ 	$(RUNPYTEST) $(srcdir)/t_y2038.py $(PYTESTFLAGS)
++	$(RUNPYTEST) $(srcdir)/t_kdcpolicy.py $(PYTESTFLAGS)
+ 
+ clean:
+ 	$(RM) adata etinfo forward gcred hist hooks hrealm icred kdbtest
+diff --git a/src/tests/t_kdcpolicy.py b/src/tests/t_kdcpolicy.py
+new file mode 100644
+index 000000000..6a745b959
+--- /dev/null
++++ b/src/tests/t_kdcpolicy.py
+@@ -0,0 +1,57 @@
++#!/usr/bin/python
++from k5test import *
++from datetime import datetime
++import re
++
++testpreauth = os.path.join(buildtop, 'plugins', 'preauth', 'test', 'test.so')
++testpolicy = os.path.join(buildtop, 'plugins', 'kdcpolicy', 'test',
++                          'policy_test.so')
++krb5_conf = {'plugins': {'kdcpreauth': {'module': 'test:' + testpreauth},
++                         'clpreauth': {'module': 'test:' + testpreauth},
++                         'kdcpolicy': {'module': 'test:' + testpolicy}}}
++kdc_conf = {'realms': {'$realm': {'default_principal_flags': '+preauth',
++                                  'max_renewable_life': '1d'}}}
++realm = K5Realm(krb5_conf=krb5_conf, kdc_conf=kdc_conf)
++
++realm.run([kadminl, 'addprinc', '-pw', password('fail'), 'fail'])
++
++def verify_time(out, target_time):
++    times = re.findall(r'\d\d/\d\d/\d\d \d\d:\d\d:\d\d', out)
++    times = [datetime.strptime(t, '%m/%d/%y %H:%M:%S') for t in times]
++    while len(times) > 0:
++        starttime = times.pop(0)
++        endtime = times.pop(0)
++        renewtime = times.pop(0)
++
++        if str(endtime - starttime) != target_time:
++            fail('unexpected lifetime value')
++        if str(renewtime - endtime) != target_time:
++            fail('unexpected renewable value')
++
++rflags = ['-r', '1d', '-l', '12h']
++
++# Test AS+TGS success path.
++realm.kinit(realm.user_princ, password('user'),
++            rflags + ['-X', 'indicators=SEVEN_HOURS'])
++realm.run([kvno, realm.host_princ])
++realm.run(['./adata', realm.host_princ], expected_msg='+97: [SEVEN_HOURS]')
++out = realm.run([klist, realm.ccache, '-e'])
++verify_time(out, '7:00:00')
++
++# Test AS+TGS success path with different values.
++realm.kinit(realm.user_princ, password('user'),
++            rflags + ['-X', 'indicators=ONE_HOUR'])
++realm.run([kvno, realm.host_princ])
++realm.run(['./adata', realm.host_princ], expected_msg='+97: [ONE_HOUR]')
++out = realm.run([klist, realm.ccache, '-e'])
++verify_time(out, '1:00:00')
++
++# Test TGS failure path (using previous creds).
++realm.run([kvno, 'fail@%s' % realm.realm], expected_code=1,
++          expected_msg='KDC policy rejects request')
++
++# Test AS failure path.
++realm.kinit('fail@%s' % realm.realm, password('fail'),
++            expected_code=1, expected_msg='KDC policy rejects request')
++
++success('kdcpolicy tests')
diff --git a/SOURCES/Add-PKINIT-UPN-tests-to-t_pkinit.py.patch b/SOURCES/Add-PKINIT-UPN-tests-to-t_pkinit.py.patch
new file mode 100644
index 0000000..5d43ea7
--- /dev/null
+++ b/SOURCES/Add-PKINIT-UPN-tests-to-t_pkinit.py.patch
@@ -0,0 +1,102 @@
+From f726fe232a16a51ca277b660c61aa9cfc2f512f1 Mon Sep 17 00:00:00 2001
+From: Matt Rogers <mrogers@redhat.com>
+Date: Fri, 9 Dec 2016 11:43:27 -0500
+Subject: [PATCH] Add PKINIT UPN tests to t_pkinit.py
+
+[ghudson@mit.edu: simplify and explain tests; add test for
+id-pkinit-san match against canonicalized client principal]
+
+ticket: 8528
+(cherry picked from commit d520fd3f032121b61b22681838af96ee505fe44d)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/tests/t_pkinit.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 57 insertions(+)
+
+diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
+index 526473b42..ac4d326b6 100755
+--- a/src/tests/t_pkinit.py
++++ b/src/tests/t_pkinit.py
+@@ -23,6 +23,9 @@ privkey_pem = os.path.join(certs, 'privkey.pem')
+ privkey_enc_pem = os.path.join(certs, 'privkey-enc.pem')
+ user_p12 = os.path.join(certs, 'user.p12')
+ user_enc_p12 = os.path.join(certs, 'user-enc.p12')
++user_upn_p12 = os.path.join(certs, 'user-upn.p12')
++user_upn2_p12 = os.path.join(certs, 'user-upn2.p12')
++user_upn3_p12 = os.path.join(certs, 'user-upn3.p12')
+ path = os.path.join(os.getcwd(), 'testdir', 'tmp-pkinit-certs')
+ path_enc = os.path.join(os.getcwd(), 'testdir', 'tmp-pkinit-certs-enc')
+ 
+@@ -36,6 +39,20 @@ pkinit_kdc_conf = {'realms': {'$realm': {
+ restrictive_kdc_conf = {'realms': {'$realm': {
+             'restrict_anonymous_to_tgt': 'true' }}}
+ 
++testprincs = {'krbtgt/KRBTEST.COM': {'keys': 'aes128-cts'},
++              'user': {'keys': 'aes128-cts', 'flags': '+preauth'},
++              'user2': {'keys': 'aes128-cts', 'flags': '+preauth'}}
++alias_kdc_conf = {'realms': {'$realm': {
++            'default_principal_flags': '+preauth',
++            'pkinit_eku_checking': 'none',
++            'pkinit_allow_upn': 'true',
++            'pkinit_identity': 'FILE:%s,%s' % (kdc_pem, privkey_pem),
++            'database_module': 'test'}},
++                  'dbmodules': {'test': {
++                      'db_library': 'test',
++                      'alias': {'user@krbtest.com': 'user'},
++                      'princs': testprincs}}}
++
+ file_identity = 'FILE:%s,%s' % (user_pem, privkey_pem)
+ file_enc_identity = 'FILE:%s,%s' % (user_pem, privkey_enc_pem)
+ dir_identity = 'DIR:%s' % path
+@@ -45,11 +62,51 @@ dir_file_identity = 'FILE:%s,%s' % (os.path.join(path, 'user.crt'),
+ dir_file_enc_identity = 'FILE:%s,%s' % (os.path.join(path_enc, 'user.crt'),
+                                         os.path.join(path_enc, 'user.key'))
+ p12_identity = 'PKCS12:%s' % user_p12
++p12_upn_identity = 'PKCS12:%s' % user_upn_p12
++p12_upn2_identity = 'PKCS12:%s' % user_upn2_p12
++p12_upn3_identity = 'PKCS12:%s' % user_upn3_p12
+ p12_enc_identity = 'PKCS12:%s' % user_enc_p12
+ p11_identity = 'PKCS11:soft-pkcs11.so'
+ p11_token_identity = ('PKCS11:module_name=soft-pkcs11.so:'
+                       'slotid=1:token=SoftToken (token)')
+ 
++# Start a realm with the test kdb module for the following UPN SAN tests.
++realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=alias_kdc_conf,
++                create_kdb=False)
++realm.start_kdc()
++
++# Compatibility check: cert contains UPN "user", which matches the
++# request principal user@KRBTEST.COM if parsed as a normal principal.
++realm.kinit(realm.user_princ,
++            flags=['-X', 'X509_user_identity=%s' % p12_upn2_identity])
++
++# Compatibility check: cert contains UPN "user@KRBTEST.COM", which matches
++# the request principal user@KRBTEST.COM if parsed as a normal principal.
++realm.kinit(realm.user_princ,
++            flags=['-X', 'X509_user_identity=%s' % p12_upn3_identity])
++
++# Cert contains UPN "user@krbtest.com" which is aliased to the request
++# principal.
++realm.kinit(realm.user_princ,
++            flags=['-X', 'X509_user_identity=%s' % p12_upn_identity])
++
++# Test an id-pkinit-san match to a post-canonical principal.
++realm.kinit('user@krbtest.com',
++            flags=['-E', '-X', 'X509_user_identity=%s' % p12_identity])
++
++# Test a UPN match to a post-canonical principal.  (This only works
++# for the cert with the UPN containing just "user", as we don't allow
++# UPN reparsing when comparing to the canonicalized client principal.)
++realm.kinit('user@krbtest.com',
++            flags=['-E', '-X', 'X509_user_identity=%s' % p12_upn2_identity])
++
++# Test a mismatch.
++out = realm.run([kinit, '-X', 'X509_user_identity=%s' % p12_upn2_identity,
++                 'user2'], expected_code=1)
++if 'kinit: Client name mismatch while getting initial credentials' not in out:
++    fail('Wrong error for UPN SAN mismatch')
++realm.stop()
++
+ realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=pkinit_kdc_conf,
+                 get_creds=False)
+ 
diff --git a/SOURCES/Add-certauth-pluggable-interface.patch b/SOURCES/Add-certauth-pluggable-interface.patch
index 30a25ca..79bd718 100644
--- a/SOURCES/Add-certauth-pluggable-interface.patch
+++ b/SOURCES/Add-certauth-pluggable-interface.patch
@@ -1,4 +1,4 @@
-From c206d6f3351d51ef3a916ef8522ab58c1a8572f7 Mon Sep 17 00:00:00 2001
+From 5a0b9b43a070c273ae4ee39ee460fa759ff9d934 Mon Sep 17 00:00:00 2001
 From: Matt Rogers <mrogers@redhat.com>
 Date: Tue, 28 Feb 2017 15:55:24 -0500
 Subject: [PATCH] Add certauth pluggable interface
@@ -22,6 +22,7 @@ doc/plugindev/certauth.rst and doc/admin/krb5_conf.rst.
 
 ticket: 8561 (new)
 (cherry picked from commit b619ce84470519bea65470be3263cd85fba94f57)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  doc/admin/conf_files/krb5_conf.rst                 |  21 ++
  doc/plugindev/certauth.rst                         |  27 ++
diff --git a/SOURCES/Add-k5test-expected_msg-expected_trace.patch b/SOURCES/Add-k5test-expected_msg-expected_trace.patch
new file mode 100644
index 0000000..c07c519
--- /dev/null
+++ b/SOURCES/Add-k5test-expected_msg-expected_trace.patch
@@ -0,0 +1,97 @@
+From c099e896f28d8c5ccacc9df086a8f4297c6b484e Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Tue, 17 Jan 2017 11:24:41 -0500
+Subject: [PATCH] Add k5test expected_msg, expected_trace
+
+In k5test.py, add the optional keyword argument "expected_msg" to
+methods that run commands, to make it easier to look for substrings in
+the command output.  Add the optional keyword "expected_trace" to run
+the command with KRB5_TRACE enabled and look for an ordered series of
+substrings in the trace output.
+
+(cherry picked from commit 8bb5fce69a4aa6c3082fa7def66a93974e10e17a)
+[rharwood@redhat.com: back out .gitignore]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/config/post.in |  2 +-
+ src/util/k5test.py | 37 ++++++++++++++++++++++++++++++++++---
+ 2 files changed, 35 insertions(+), 4 deletions(-)
+
+diff --git a/src/config/post.in b/src/config/post.in
+index 77a9bffdf..aecac9d3b 100644
+--- a/src/config/post.in
++++ b/src/config/post.in
+@@ -156,7 +156,7 @@ clean: clean-$(WHAT)
+ 
+ clean-unix::
+ 	$(RM) $(OBJS) $(DEPTARGETS_CLEAN) $(EXTRA_FILES)
+-	$(RM) et-[ch]-*.et et-[ch]-*.[ch] testlog
++	$(RM) et-[ch]-*.et et-[ch]-*.[ch] testlog testtrace
+ 	-$(RM) -r testdir
+ 
+ clean-windows::
+diff --git a/src/util/k5test.py b/src/util/k5test.py
+index c3d026377..4d30baf40 100644
+--- a/src/util/k5test.py
++++ b/src/util/k5test.py
+@@ -223,8 +223,11 @@ Scripts may use the following realm methods and attributes:
+   command-line debugging options.  Fail if the command does not return
+   0.  Log the command output appropriately, and return it as a single
+   multi-line string.  Keyword arguments can contain input='string' to
+-  send an input string to the command, and expected_code=N to expect a
+-  return code other than 0.
++  send an input string to the command, expected_code=N to expect a
++  return code other than 0, expected_msg=MSG to expect a substring in
++  the command output, and expected_trace=('a', 'b', ...) to expect an
++  ordered series of line substrings in the command's KRB5_TRACE
++  output.
+ 
+ * realm.kprop_port(): Returns a port number based on realm.portbase
+   intended for use by kprop and kpropd.
+@@ -647,10 +650,31 @@ def _stop_or_shell(stop, shell, env, ind):
+         subprocess.call(os.getenv('SHELL'), env=env)
+ 
+ 
+-def _run_cmd(args, env, input=None, expected_code=0):
++# Read tracefile and look for the expected strings in successive lines.
++def _check_trace(tracefile, expected):
++    output('*** Trace output for previous command:\n')
++    i = 0
++    with open(tracefile, 'r') as f:
++        for line in f:
++            output(line)
++            if i < len(expected) and expected[i] in line:
++                i += 1
++    if i < len(expected):
++        fail('Expected string not found in trace output: ' + expected[i])
++
++
++def _run_cmd(args, env, input=None, expected_code=0, expected_msg=None,
++             expected_trace=None):
+     global null_input, _cmd_index, _last_cmd, _last_cmd_output, _debug
+     global _stop_before, _stop_after, _shell_before, _shell_after
+ 
++    if expected_trace is not None:
++        tracefile = 'testtrace'
++        if os.path.exists(tracefile):
++            os.remove(tracefile)
++        env = env.copy()
++        env['KRB5_TRACE'] = tracefile
++
+     if (_match_cmdnum(_debug, _cmd_index)):
+         return _debug_cmd(args, env, input)
+ 
+@@ -679,6 +703,13 @@ def _run_cmd(args, env, input=None, expected_code=0):
+     # Check the return code and return the output.
+     if code != expected_code:
+         fail('%s failed with code %d.' % (args[0], code))
++
++    if expected_msg is not None and expected_msg not in outdata:
++        fail('Expected string not found in command output: ' + expected_msg)
++
++    if expected_trace is not None:
++        _check_trace(tracefile, expected_trace)
++
+     return outdata
+ 
+ 
diff --git a/SOURCES/Add-support-to-query-the-SSF-of-a-GSS-context.patch b/SOURCES/Add-support-to-query-the-SSF-of-a-GSS-context.patch
new file mode 100644
index 0000000..cc0ddb3
--- /dev/null
+++ b/SOURCES/Add-support-to-query-the-SSF-of-a-GSS-context.patch
@@ -0,0 +1,420 @@
+From 1f7d42707585e552842455857070fff8957fcb7c Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo@redhat.com>
+Date: Thu, 30 Mar 2017 11:27:09 -0400
+Subject: [PATCH] Add support to query the SSF of a GSS context
+
+Cyrus SASL provides a Security Strength Factor number to assess the
+relative "strength" of the negotiated mechanism, and applications
+sometimes make access control decisions based on it.
+
+Add a call that allows us to query the mechanism that established the
+GSS security context to ask what is the current SSF, based on the
+enctype of the session key.
+
+ticket: 8569 (new)
+(cherry picked from commit 7feb7da54c0321b5a3eeb6c3797846a3cf7eda28)
+[rharwood@redhat.com: stub out GSS_KRB5_GET_CRED_IMPERSONATOR]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/include/k5-int.h                    |  1 +
+ src/lib/crypto/krb/crypto_int.h         |  1 +
+ src/lib/crypto/krb/enctype_util.c       | 16 ++++++++++++++++
+ src/lib/crypto/krb/etypes.c             | 33 ++++++++++++++++++---------------
+ src/lib/crypto/libk5crypto.exports      |  1 +
+ src/lib/gssapi/generic/gssapi_ext.h     | 11 +++++++++++
+ src/lib/gssapi/generic/gssapi_generic.c |  9 +++++++++
+ src/lib/gssapi/krb5/gssapiP_krb5.h      |  6 ++++++
+ src/lib/gssapi/krb5/gssapi_krb5.c       |  4 ++++
+ src/lib/gssapi/krb5/inq_context.c       | 27 +++++++++++++++++++++++++++
+ src/lib/gssapi/libgssapi_krb5.exports   |  1 +
+ src/lib/gssapi32.def                    |  3 +++
+ src/lib/krb5_32.def                     |  3 +++
+ src/tests/gssapi/t_enctypes.c           | 14 ++++++++++++++
+ 14 files changed, 115 insertions(+), 15 deletions(-)
+
+diff --git a/src/include/k5-int.h b/src/include/k5-int.h
+index cea644d0a..06ca2b66d 100644
+--- a/src/include/k5-int.h
++++ b/src/include/k5-int.h
+@@ -2114,6 +2114,7 @@ krb5_get_tgs_ktypes(krb5_context, krb5_const_principal, krb5_enctype **);
+ krb5_boolean krb5_is_permitted_enctype(krb5_context, krb5_enctype);
+ 
+ krb5_boolean KRB5_CALLCONV krb5int_c_weak_enctype(krb5_enctype);
++krb5_error_code k5_enctype_to_ssf(krb5_enctype enctype, unsigned int *ssf_out);
+ 
+ krb5_error_code krb5_kdc_rep_decrypt_proc(krb5_context, const krb5_keyblock *,
+                                           krb5_const_pointer, krb5_kdc_rep *);
+diff --git a/src/lib/crypto/krb/crypto_int.h b/src/lib/crypto/krb/crypto_int.h
+index d75b49c69..e5099291e 100644
+--- a/src/lib/crypto/krb/crypto_int.h
++++ b/src/lib/crypto/krb/crypto_int.h
+@@ -111,6 +111,7 @@ struct krb5_keytypes {
+     prf_func prf;
+     krb5_cksumtype required_ctype;
+     krb5_flags flags;
++    unsigned int ssf;
+ };
+ 
+ #define ETYPE_WEAK 1
+diff --git a/src/lib/crypto/krb/enctype_util.c b/src/lib/crypto/krb/enctype_util.c
+index 0ed74bd6e..b1b40e7ec 100644
+--- a/src/lib/crypto/krb/enctype_util.c
++++ b/src/lib/crypto/krb/enctype_util.c
+@@ -131,3 +131,19 @@ krb5_enctype_to_name(krb5_enctype enctype, krb5_boolean shortest,
+         return ENOMEM;
+     return 0;
+ }
++
++/* The security of a mechanism cannot be summarized with a simple integer
++ * value, but we provide a per-enctype value for Cyrus SASL's SSF. */
++krb5_error_code
++k5_enctype_to_ssf(krb5_enctype enctype, unsigned int *ssf_out)
++{
++    const struct krb5_keytypes *ktp;
++
++    *ssf_out = 0;
++
++    ktp = find_enctype(enctype);
++    if (ktp == NULL)
++        return EINVAL;
++    *ssf_out = ktp->ssf;
++    return 0;
++}
+diff --git a/src/lib/crypto/krb/etypes.c b/src/lib/crypto/krb/etypes.c
+index 0e5e977d4..53d4a5c79 100644
+--- a/src/lib/crypto/krb/etypes.c
++++ b/src/lib/crypto/krb/etypes.c
+@@ -42,7 +42,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_des_string_to_key, k5_rand2key_des,
+       krb5int_des_prf,
+       CKSUMTYPE_RSA_MD5_DES,
+-      ETYPE_WEAK },
++      ETYPE_WEAK, 56 },
+     { ENCTYPE_DES_CBC_MD4,
+       "des-cbc-md4", { 0 }, "DES cbc mode with RSA-MD4",
+       &krb5int_enc_des, &krb5int_hash_md4,
+@@ -51,7 +51,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_des_string_to_key, k5_rand2key_des,
+       krb5int_des_prf,
+       CKSUMTYPE_RSA_MD4_DES,
+-      ETYPE_WEAK },
++      ETYPE_WEAK, 56 },
+     { ENCTYPE_DES_CBC_MD5,
+       "des-cbc-md5", { "des" }, "DES cbc mode with RSA-MD5",
+       &krb5int_enc_des, &krb5int_hash_md5,
+@@ -60,7 +60,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_des_string_to_key, k5_rand2key_des,
+       krb5int_des_prf,
+       CKSUMTYPE_RSA_MD5_DES,
+-      ETYPE_WEAK },
++      ETYPE_WEAK, 56 },
+     { ENCTYPE_DES_CBC_RAW,
+       "des-cbc-raw", { 0 }, "DES cbc mode raw",
+       &krb5int_enc_des, NULL,
+@@ -69,7 +69,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_des_string_to_key, k5_rand2key_des,
+       krb5int_des_prf,
+       0,
+-      ETYPE_WEAK },
++      ETYPE_WEAK, 56 },
+     { ENCTYPE_DES3_CBC_RAW,
+       "des3-cbc-raw", { 0 }, "Triple DES cbc mode raw",
+       &krb5int_enc_des3, NULL,
+@@ -78,7 +78,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_dk_string_to_key, k5_rand2key_des3,
+       NULL, /*PRF*/
+       0,
+-      ETYPE_WEAK },
++      ETYPE_WEAK, 112 },
+ 
+     { ENCTYPE_DES3_CBC_SHA1,
+       "des3-cbc-sha1", { "des3-hmac-sha1", "des3-cbc-sha1-kd" },
+@@ -89,7 +89,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_dk_string_to_key, k5_rand2key_des3,
+       krb5int_dk_prf,
+       CKSUMTYPE_HMAC_SHA1_DES3,
+-      0 /*flags*/ },
++      0 /*flags*/, 112 },
+ 
+     { ENCTYPE_DES_HMAC_SHA1,
+       "des-hmac-sha1", { 0 }, "DES with HMAC/sha1",
+@@ -99,7 +99,10 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_dk_string_to_key, k5_rand2key_des,
+       NULL, /*PRF*/
+       0,
+-      ETYPE_WEAK },
++      ETYPE_WEAK, 56 },
++
++    /* rc4-hmac uses a 128-bit key, but due to weaknesses in the RC4 cipher, we
++     * consider its strength degraded and assign it an SSF value of 64. */
+     { ENCTYPE_ARCFOUR_HMAC,
+       "arcfour-hmac", { "rc4-hmac", "arcfour-hmac-md5" },
+       "ArcFour with HMAC/md5",
+@@ -110,7 +113,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_arcfour_decrypt, krb5int_arcfour_string_to_key,
+       k5_rand2key_direct, krb5int_arcfour_prf,
+       CKSUMTYPE_HMAC_MD5_ARCFOUR,
+-      0 /*flags*/ },
++      0 /*flags*/, 64 },
+     { ENCTYPE_ARCFOUR_HMAC_EXP,
+       "arcfour-hmac-exp", { "rc4-hmac-exp", "arcfour-hmac-md5-exp" },
+       "Exportable ArcFour with HMAC/md5",
+@@ -121,7 +124,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_arcfour_decrypt, krb5int_arcfour_string_to_key,
+       k5_rand2key_direct, krb5int_arcfour_prf,
+       CKSUMTYPE_HMAC_MD5_ARCFOUR,
+-      ETYPE_WEAK
++      ETYPE_WEAK, 40
+     },
+ 
+     { ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+@@ -133,7 +136,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_aes_string_to_key, k5_rand2key_direct,
+       krb5int_dk_prf,
+       CKSUMTYPE_HMAC_SHA1_96_AES128,
+-      0 /*flags*/ },
++      0 /*flags*/, 128 },
+     { ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+       "aes256-cts-hmac-sha1-96", { "aes256-cts", "aes256-sha1" },
+       "AES-256 CTS mode with 96-bit SHA-1 HMAC",
+@@ -143,7 +146,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_aes_string_to_key, k5_rand2key_direct,
+       krb5int_dk_prf,
+       CKSUMTYPE_HMAC_SHA1_96_AES256,
+-      0 /*flags*/ },
++      0 /*flags*/, 256 },
+ 
+     { ENCTYPE_CAMELLIA128_CTS_CMAC,
+       "camellia128-cts-cmac", { "camellia128-cts" },
+@@ -155,7 +158,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_camellia_string_to_key, k5_rand2key_direct,
+       krb5int_dk_cmac_prf,
+       CKSUMTYPE_CMAC_CAMELLIA128,
+-      0 /*flags*/ },
++      0 /*flags*/, 128 },
+     { ENCTYPE_CAMELLIA256_CTS_CMAC,
+       "camellia256-cts-cmac", { "camellia256-cts" },
+       "Camellia-256 CTS mode with CMAC",
+@@ -166,7 +169,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_camellia_string_to_key, k5_rand2key_direct,
+       krb5int_dk_cmac_prf,
+       CKSUMTYPE_CMAC_CAMELLIA256,
+-      0 /*flags */ },
++      0 /*flags */, 256 },
+ 
+     { ENCTYPE_AES128_CTS_HMAC_SHA256_128,
+       "aes128-cts-hmac-sha256-128", { "aes128-sha2" },
+@@ -177,7 +180,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_aes2_string_to_key, k5_rand2key_direct,
+       krb5int_aes2_prf,
+       CKSUMTYPE_HMAC_SHA256_128_AES128,
+-      0 /*flags*/ },
++      0 /*flags*/, 128 },
+     { ENCTYPE_AES256_CTS_HMAC_SHA384_192,
+       "aes256-cts-hmac-sha384-192", { "aes256-sha2" },
+       "AES-256 CTS mode with 192-bit SHA-384 HMAC",
+@@ -187,7 +190,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
+       krb5int_aes2_string_to_key, k5_rand2key_direct,
+       krb5int_aes2_prf,
+       CKSUMTYPE_HMAC_SHA384_192_AES256,
+-      0 /*flags*/ },
++      0 /*flags*/, 256 },
+ };
+ 
+ const int krb5int_enctypes_length =
+diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports
+index 447e45644..82eb5f30c 100644
+--- a/src/lib/crypto/libk5crypto.exports
++++ b/src/lib/crypto/libk5crypto.exports
+@@ -108,3 +108,4 @@ krb5int_nfold
+ k5_allow_weak_pbkdf2iter
+ krb5_c_prfplus
+ krb5_c_derive_prfplus
++k5_enctype_to_ssf
+diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h
+index 9ad44216d..9d3a7e736 100644
+--- a/src/lib/gssapi/generic/gssapi_ext.h
++++ b/src/lib/gssapi/generic/gssapi_ext.h
+@@ -575,4 +575,15 @@ gss_import_cred(
+ }
+ #endif
+ 
++/*
++ * When used with gss_inquire_sec_context_by_oid(), return a buffer set with
++ * the first member containing an unsigned 32-bit integer in network byte
++ * order.  This is the Security Strength Factor (SSF) associated with the
++ * secure channel established by the security context.  NOTE: This value is
++ * made available solely as an indication for use by APIs like Cyrus SASL that
++ * classify the strength of a secure channel via this number.  The strength of
++ * a channel cannot necessarily be represented by a simple number.
++ */
++GSS_DLLIMP extern gss_OID GSS_C_SEC_CONTEXT_SASL_SSF;
++
+ #endif /* GSSAPI_EXT_H_ */
+diff --git a/src/lib/gssapi/generic/gssapi_generic.c b/src/lib/gssapi/generic/gssapi_generic.c
+index 5496aa335..fa144c2bf 100644
+--- a/src/lib/gssapi/generic/gssapi_generic.c
++++ b/src/lib/gssapi/generic/gssapi_generic.c
+@@ -157,6 +157,13 @@ static const gss_OID_desc const_oids[] = {
+     {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x19"},
+     {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1a"},
+     {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1b"},
++
++    /*
++     * GSS_SEC_CONTEXT_SASL_SSF_OID 1.2.840.113554.1.2.2.5.15
++     * iso(1) member-body(2) United States(840) mit(113554)
++     * infosys(1) gssapi(2) krb5(2) krb5-gssapi-ext(5) sasl-ssf(15)
++     */
++    {11, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f"},
+ };
+ 
+ /* Here are the constants which point to the static structure above.
+@@ -218,6 +225,8 @@ GSS_DLLIMP gss_const_OID GSS_C_MA_PFS               = oids+33;
+ GSS_DLLIMP gss_const_OID GSS_C_MA_COMPRESS          = oids+34;
+ GSS_DLLIMP gss_const_OID GSS_C_MA_CTX_TRANS         = oids+35;
+ 
++GSS_DLLIMP gss_OID GSS_C_SEC_CONTEXT_SASL_SSF = oids+36;
++
+ static gss_OID_set_desc gss_ma_known_attrs_desc = { 27, oids+9 };
+ gss_OID_set gss_ma_known_attrs = &gss_ma_known_attrs_desc;
+ 
+diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
+index d7bdef7e2..ef030707e 100644
+--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
++++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
+@@ -1144,6 +1144,12 @@ gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *,
+                                               const gss_OID,
+                                               gss_buffer_set_t *);
+ 
++#define GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH 11
++#define GET_SEC_CONTEXT_SASL_SSF_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f"
++OM_uint32
++gss_krb5int_sec_context_sasl_ssf(OM_uint32 *, const gss_ctx_id_t,
++                                 const gss_OID, gss_buffer_set_t *);
++
+ #define GSS_KRB5_IMPORT_CRED_OID_LENGTH 11
+ #define GSS_KRB5_IMPORT_CRED_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0d"
+ 
+diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
+index 99092ccab..de4131980 100644
+--- a/src/lib/gssapi/krb5/gssapi_krb5.c
++++ b/src/lib/gssapi/krb5/gssapi_krb5.c
+@@ -352,6 +352,10 @@ static struct {
+     {
+         {GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID},
+         gss_krb5int_extract_authtime_from_sec_context
++    },
++    {
++        {GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH, GET_SEC_CONTEXT_SASL_SSF_OID},
++        gss_krb5int_sec_context_sasl_ssf
+     }
+ };
+ 
+diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c
+index 9024b3c7e..d2e466e60 100644
+--- a/src/lib/gssapi/krb5/inq_context.c
++++ b/src/lib/gssapi/krb5/inq_context.c
+@@ -310,3 +310,30 @@ gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *minor_status,
+ 
+     return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
+ }
++
++OM_uint32
++gss_krb5int_sec_context_sasl_ssf(OM_uint32 *minor_status,
++                                 const gss_ctx_id_t context_handle,
++                                 const gss_OID desired_object,
++                                 gss_buffer_set_t *data_set)
++{
++    krb5_gss_ctx_id_rec *ctx;
++    krb5_key key;
++    krb5_error_code code;
++    gss_buffer_desc ssfbuf;
++    unsigned int ssf;
++    uint8_t buf[4];
++
++    ctx = (krb5_gss_ctx_id_rec *)context_handle;
++    key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey;
++
++    code = k5_enctype_to_ssf(key->keyblock.enctype, &ssf);
++    if (code)
++        return GSS_S_FAILURE;
++
++    store_32_be(ssf, buf);
++    ssfbuf.value = buf;
++    ssfbuf.length = sizeof(buf);
++
++    return generic_gss_add_buffer_set_member(minor_status, &ssfbuf, data_set);
++}
+diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports
+index 9facb3f42..936540e41 100644
+--- a/src/lib/gssapi/libgssapi_krb5.exports
++++ b/src/lib/gssapi/libgssapi_krb5.exports
+@@ -37,6 +37,7 @@ GSS_C_MA_CBINDINGS
+ GSS_C_MA_PFS
+ GSS_C_MA_COMPRESS
+ GSS_C_MA_CTX_TRANS
++GSS_C_SEC_CONTEXT_SASL_SSF
+ gss_accept_sec_context
+ gss_acquire_cred
+ gss_acquire_cred_with_password
+diff --git a/src/lib/gssapi32.def b/src/lib/gssapi32.def
+index 362b9bce8..dff057754 100644
+--- a/src/lib/gssapi32.def
++++ b/src/lib/gssapi32.def
+@@ -182,3 +182,6 @@ EXPORTS
+ 	gss_verify_mic_iov				@146
+ ; Added in 1.14
+ 	GSS_KRB5_CRED_NO_CI_FLAGS_X			@147	DATA
++; Added in 1.16
++;	GSS_KRB5_GET_CRED_IMPERSONATOR			@148	DATA
++	GSS_C_SEC_CONTEXT_SASL_SSF			@149	DATA
+diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
+index e5b560dfc..f7b428e16 100644
+--- a/src/lib/krb5_32.def
++++ b/src/lib/krb5_32.def
+@@ -470,3 +470,6 @@ EXPORTS
+ 	krb5_get_init_creds_opt_set_pac_request		@435
+ 	krb5int_trace					@436 ; PRIVATE GSSAPI
+ 	krb5_expand_hostname				@437
++
++; new in 1.16
++	k5_enctype_to_ssf				@438 ; PRIVATE GSSAPI
+diff --git a/src/tests/gssapi/t_enctypes.c b/src/tests/gssapi/t_enctypes.c
+index a2ad18f47..3fd31e2f8 100644
+--- a/src/tests/gssapi/t_enctypes.c
++++ b/src/tests/gssapi/t_enctypes.c
+@@ -32,6 +32,7 @@
+ 
+ #include "k5-int.h"
+ #include "common.h"
++#include "gssapi_ext.h"
+ 
+ /*
+  * This test program establishes contexts with the krb5 mech, the default
+@@ -86,6 +87,9 @@ main(int argc, char *argv[])
+     gss_krb5_lucid_context_v1_t *ilucid, *alucid;
+     gss_krb5_rfc1964_keydata_t *i1964, *a1964;
+     gss_krb5_cfx_keydata_t *icfx, *acfx;
++    gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
++    gss_OID ssf_oid = GSS_C_SEC_CONTEXT_SASL_SSF;
++    unsigned int ssf;
+     size_t count;
+     void *lptr;
+     int c;
+@@ -139,6 +143,16 @@ main(int argc, char *argv[])
+     establish_contexts(&mech_krb5, icred, acred, tname, flags, &ictx, &actx,
+                        NULL, NULL, NULL);
+ 
++    /* Query the SSF value and range-check the result. */
++    major = gss_inquire_sec_context_by_oid(&minor, ictx, ssf_oid, &bufset);
++    check_gsserr("gss_inquire_sec_context_by_oid(ssf)", major, minor);
++    if (bufset->elements[0].length != 4)
++        errout("SSF buffer has unexpected length");
++    ssf = load_32_be(bufset->elements[0].value);
++    if (ssf < 56 || ssf > 256)
++        errout("SSF value not within acceptable range (56-256)");
++    (void)gss_release_buffer_set(&minor, &bufset);
++
+     /* Export to lucid contexts. */
+     major = gss_krb5_export_lucid_sec_context(&minor, &ictx, 1, &lptr);
+     check_gsserr("gss_export_lucid_sec_context(initiator)", major, minor);
diff --git a/SOURCES/Add-test-cert-generation-to-make-certs.sh.patch b/SOURCES/Add-test-cert-generation-to-make-certs.sh.patch
new file mode 100644
index 0000000..9c1dcf9
--- /dev/null
+++ b/SOURCES/Add-test-cert-generation-to-make-certs.sh.patch
@@ -0,0 +1,92 @@
+From fd8ce9e1ed7a8d6cf5ac7d27d6acf40b0453c45e Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 5 Sep 2017 15:54:31 -0400
+Subject: [PATCH] Add test cert generation to make-certs.sh
+
+Based on commit 5a1d0388ba2e4ec510ed715ce5fbc7f748941425 but missing
+everything but the make-certs change since infrastructure cannot patch
+binaries.  Plan to run make-certs during build, but this will only
+work with openssl < 1.1.
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/tests/dejagnu/pkinit-certs/make-certs.sh | 53 +++++++++++++++++++++++++++-
+ 1 file changed, 52 insertions(+), 1 deletion(-)
+
+diff --git a/src/tests/dejagnu/pkinit-certs/make-certs.sh b/src/tests/dejagnu/pkinit-certs/make-certs.sh
+index b82ef6f83..0f07709b0 100755
+--- a/src/tests/dejagnu/pkinit-certs/make-certs.sh
++++ b/src/tests/dejagnu/pkinit-certs/make-certs.sh
+@@ -4,7 +4,9 @@ NAMETYPE=1
+ KEYSIZE=2048
+ DAYS=4000
+ REALM=KRBTEST.COM
++LOWREALM=krbtest.com
+ KRB5_PRINCIPAL_SAN=1.3.6.1.5.2.2
++KRB5_UPN_SAN=1.3.6.1.4.1.311.20.2.3
+ PKINIT_KDC_EKU=1.3.6.1.5.2.3.5
+ PKINIT_CLIENT_EKU=1.3.6.1.5.2.3.4
+ TLS_SERVER_EKU=1.3.6.1.5.5.7.3.1
+@@ -85,6 +87,30 @@ keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement
+ basicConstraints = critical,CA:FALSE
+ subjectAltName = otherName:$KRB5_PRINCIPAL_SAN;SEQUENCE:krb5princ_client
+ extendedKeyUsage = $CLIENT_EKU_LIST
++
++[exts_upn_client]
++subjectKeyIdentifier = hash
++authorityKeyIdentifier = keyid:always,issuer:always
++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement
++basicConstraints = critical,CA:FALSE
++subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user@$LOWREALM
++extendedKeyUsage = $CLIENT_EKU_LIST
++
++[exts_upn2_client]
++subjectKeyIdentifier = hash
++authorityKeyIdentifier = keyid:always,issuer:always
++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement
++basicConstraints = critical,CA:FALSE
++subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user
++extendedKeyUsage = $CLIENT_EKU_LIST
++
++[exts_upn3_client]
++subjectKeyIdentifier = hash
++authorityKeyIdentifier = keyid:always,issuer:always
++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement
++basicConstraints = critical,CA:FALSE
++subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user@$REALM
++extendedKeyUsage = $CLIENT_EKU_LIST
+ EOF
+ 
+ # Generate a private key.
+@@ -113,5 +139,30 @@ openssl pkcs12 -export -in user.pem -inkey privkey.pem -out user.p12 \
+ openssl pkcs12 -export -in user.pem -inkey privkey.pem -out user-enc.p12 \
+     -passout pass:encrypted
+ 
++# Generate a client certificate and PKCS#12 bundles with a UPN SAN.
++SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \
++    -key privkey.pem -out user-upn.csr
++SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn_client \
++    -set_serial 4 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
++    -out user-upn.pem -in user-upn.csr
++openssl pkcs12 -export -in user-upn.pem -inkey privkey.pem -out user-upn.p12 \
++    -passout pass:
++
++SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \
++    -key privkey.pem -out user-upn2.csr
++SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn2_client \
++    -set_serial 5 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
++    -out user-upn2.pem -in user-upn2.csr
++openssl pkcs12 -export -in user-upn2.pem -inkey privkey.pem \
++     -out user-upn2.p12 -passout pass:
++
++SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \
++    -key privkey.pem -out user-upn3.csr
++SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn3_client \
++    -set_serial 6 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
++    -out user-upn3.pem -in user-upn3.csr
++openssl pkcs12 -export -in user-upn3.pem -inkey privkey.pem \
++     -out user-upn3.p12 -passout pass:
++
+ # Clean up.
+-rm -f openssl.cnf kdc.csr user.csr
++rm -f openssl.cnf kdc.csr user.csr user-upn.csr user-upn2.csr user-upn3.csr
diff --git a/SOURCES/Add-test-cert-with-no-extensions.patch b/SOURCES/Add-test-cert-with-no-extensions.patch
new file mode 100644
index 0000000..90201f1
--- /dev/null
+++ b/SOURCES/Add-test-cert-with-no-extensions.patch
@@ -0,0 +1,36 @@
+From dd189f46b9e43392b842c4309c95dc7e71963261 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Thu, 5 Oct 2017 12:54:13 -0400
+Subject: [PATCH] Add test cert with no extensions
+
+Add commands to make-certs.sh to generate a test client certificate
+with no certificate extensions.  Re-run make-certs.sh.
+
+ticket: 8562
+(cherry-picked from commit 0d23835660ab131d244d395e4568969b5c0dc678)
+[rharwood@redhat.com: only backport the make-certs.sh changes]
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/tests/dejagnu/pkinit-certs/make-certs.sh | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/tests/dejagnu/pkinit-certs/make-certs.sh b/src/tests/dejagnu/pkinit-certs/make-certs.sh
+index 0d8c2019a..23426af8a 100755
+--- a/src/tests/dejagnu/pkinit-certs/make-certs.sh
++++ b/src/tests/dejagnu/pkinit-certs/make-certs.sh
+@@ -163,5 +163,14 @@ SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn3_client \
+ openssl pkcs12 -export -in user-upn3.pem -inkey privkey.pem \
+      -out user-upn3.p12 -passout pass:
+ 
++# Generate a client certificate and PKCS#12 bundle with no PKINIT extensions.
++SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \
++    -key privkey.pem -out generic.csr
++SUBJECT=user openssl x509 -set_serial 7 -days $DAYS -req -CA ca.pem \
++    -CAkey privkey.pem -out generic.pem -in generic.csr
++openssl pkcs12 -export -in generic.pem -inkey privkey.pem -out generic.p12 \
++    -passout pass:
++
+ # Clean up.
+ rm -f openssl.cnf kdc.csr user.csr user-upn.csr user-upn2.csr user-upn3.csr
++rm -f generic.csr
diff --git a/SOURCES/Add-the-client_name-kdcpreauth-callback.patch b/SOURCES/Add-the-client_name-kdcpreauth-callback.patch
index 7cd1b67..25f4dea 100644
--- a/SOURCES/Add-the-client_name-kdcpreauth-callback.patch
+++ b/SOURCES/Add-the-client_name-kdcpreauth-callback.patch
@@ -1,4 +1,4 @@
-From b0f389ad69cbd68f2825fe32556e4b4a599a0ac3 Mon Sep 17 00:00:00 2001
+From aa153bb60c4fdc05adbc88cca578612fce6c8ce0 Mon Sep 17 00:00:00 2001
 From: Matt Rogers <mrogers@redhat.com>
 Date: Tue, 4 Apr 2017 16:54:56 -0400
 Subject: [PATCH] Add the client_name() kdcpreauth callback
@@ -7,6 +7,7 @@ Add a kdcpreauth callback to returns the canonicalized client principal.
 
 ticket: 8570 (new)
 (cherry picked from commit a84f39ec30f3deeda7836da6e8b3d8dcf7a045b1)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/include/krb5/kdcpreauth_plugin.h | 6 ++++++
  src/kdc/kdc_preauth.c                | 9 ++++++++-
diff --git a/SOURCES/Add-timestamp-helper-functions.patch b/SOURCES/Add-timestamp-helper-functions.patch
new file mode 100644
index 0000000..1bd6a8e
--- /dev/null
+++ b/SOURCES/Add-timestamp-helper-functions.patch
@@ -0,0 +1,81 @@
+From 6437685130b68670888db1d0551f5464d56c4cec Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Sat, 22 Apr 2017 09:49:12 -0400
+Subject: [PATCH] Add timestamp helper functions
+
+Add k5-int.h helper functions to manipulate krb5_timestamp values,
+avoiding undefined behavior and treating negative timestamp values as
+times between 2038 and 2106.  Add a doxygen comment for krb5_timestamp
+indicating how third-party code should use it safely.
+
+ticket: 8352
+(cherry picked from commit 58e9155060cd93b1a7557e37fbc9b077b76465c2)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/include/k5-int.h      | 31 +++++++++++++++++++++++++++++++
+ src/include/krb5/krb5.hin |  9 +++++++++
+ 2 files changed, 40 insertions(+)
+
+diff --git a/src/include/k5-int.h b/src/include/k5-int.h
+index 06ca2b66d..82ee20760 100644
+--- a/src/include/k5-int.h
++++ b/src/include/k5-int.h
+@@ -2353,6 +2353,37 @@ k5memdup0(const void *in, size_t len, krb5_error_code *code)
+     return ptr;
+ }
+ 
++/* Convert a krb5_timestamp to a time_t value, treating the negative range of
++ * krb5_timestamp as times between 2038 and 2106 (if time_t is 64-bit). */
++static inline time_t
++ts2tt(krb5_timestamp timestamp)
++{
++    return (time_t)(uint32_t)timestamp;
++}
++
++/* Return the delta between two timestamps (a - b) as a signed 32-bit value,
++ * without relying on undefined behavior. */
++static inline krb5_deltat
++ts_delta(krb5_timestamp a, krb5_timestamp b)
++{
++    return (krb5_deltat)((uint32_t)a - (uint32_t)b);
++}
++
++/* Increment a timestamp by a signed 32-bit interval, without relying on
++ * undefined behavior. */
++static inline krb5_timestamp
++ts_incr(krb5_timestamp ts, krb5_deltat delta)
++{
++    return (krb5_timestamp)((uint32_t)ts + (uint32_t)delta);
++}
++
++/* Return true if a comes after b. */
++static inline krb5_boolean
++ts_after(krb5_timestamp a, krb5_timestamp b)
++{
++    return (uint32_t)a > (uint32_t)b;
++}
++
+ krb5_error_code KRB5_CALLCONV
+ krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
+                               krb5_ccache ccache,
+diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
+index cf60d6c41..53ad85384 100644
+--- a/src/include/krb5/krb5.hin
++++ b/src/include/krb5/krb5.hin
+@@ -187,7 +187,16 @@ typedef krb5_int32 krb5_cryptotype;
+ 
+ typedef krb5_int32      krb5_preauthtype; /* This may change, later on */
+ typedef krb5_int32      krb5_flags;
++
++/**
++ * Represents a timestamp in seconds since the POSIX epoch.  This legacy type
++ * is used frequently in the ABI, but cannot represent timestamps after 2038 as
++ * a positive number.  Code which uses this type should cast values of it to
++ * uint32_t so that negative values are treated as timestamps between 2038 and
++ * 2106 on platforms with 64-bit time_t.
++ */
+ typedef krb5_int32      krb5_timestamp;
++
+ typedef krb5_int32      krb5_deltat;
+ 
+ /**
diff --git a/SOURCES/Add-timestamp-tests.patch b/SOURCES/Add-timestamp-tests.patch
new file mode 100644
index 0000000..4fe37aa
--- /dev/null
+++ b/SOURCES/Add-timestamp-tests.patch
@@ -0,0 +1,600 @@
+From 47999bb8735f653f06e0eb46e7eced600210b9da Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Sat, 29 Apr 2017 17:30:36 -0400
+Subject: [PATCH] Add timestamp tests
+
+Add a test program for krb5int_validate_times() covering cases before
+and across the y2038 boundary.  Add a GSSAPI test program to exercise
+lifetime queries, and tests using it in t_gssapi.py for ticket end
+times after y2038.  Add a new test script t_y2038.py which only runs
+on platforms with 64-bit time_t to exercise end-user operations across
+and after y2038.  Add an LDAP test case to test storage of post-y2038
+timestamps.
+
+ticket: 8352
+(cherry picked from commit 8ca62e54e89e2fbd6a089e8ab20b4e374a486003)
+[rharwood@redhat.com: prune gitignore]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/Makefile.in                  |   1 +
+ src/config/pre.in                |   2 +
+ src/configure.in                 |   3 +
+ src/lib/krb5/krb/Makefile.in     |  14 ++--
+ src/lib/krb5/krb/t_valid_times.c | 109 ++++++++++++++++++++++++++++++
+ src/tests/Makefile.in            |   1 +
+ src/tests/gssapi/Makefile.in     |  27 ++++----
+ src/tests/gssapi/t_gssapi.py     |  32 +++++++++
+ src/tests/gssapi/t_lifetime.c    | 140 +++++++++++++++++++++++++++++++++++++++
+ src/tests/t_kdb.py               |   7 ++
+ src/tests/t_y2038.py             |  75 +++++++++++++++++++++
+ 11 files changed, 395 insertions(+), 16 deletions(-)
+ create mode 100644 src/lib/krb5/krb/t_valid_times.c
+ create mode 100644 src/tests/gssapi/t_lifetime.c
+ create mode 100644 src/tests/t_y2038.py
+
+diff --git a/src/Makefile.in b/src/Makefile.in
+index b0249778c..ad8565056 100644
+--- a/src/Makefile.in
++++ b/src/Makefile.in
+@@ -521,6 +521,7 @@ pyrunenv.vals: Makefile
+ 	done > $@
+ 	echo "tls_impl = '$(TLS_IMPL)'" >> $@
+ 	echo "have_sasl = '$(HAVE_SASL)'" >> $@
++	echo "sizeof_time_t = $(SIZEOF_TIME_T)" >> $@
+ 
+ runenv.py: pyrunenv.vals
+ 	echo 'env = {}' > $@
+diff --git a/src/config/pre.in b/src/config/pre.in
+index d961b5621..f23c07d9d 100644
+--- a/src/config/pre.in
++++ b/src/config/pre.in
+@@ -452,6 +452,8 @@ HAVE_SASL = @HAVE_SASL@
+ # Whether we have libresolv 1.1.5 for URI discovery tests
+ HAVE_RESOLV_WRAPPER = @HAVE_RESOLV_WRAPPER@
+ 
++SIZEOF_TIME_T = @SIZEOF_TIME_T@
++
+ # error table rules
+ #
+ ### /* these are invoked as $(...) foo.et, which works, but could be better */
+diff --git a/src/configure.in b/src/configure.in
+index 24f653f0d..4ae2c07d5 100644
+--- a/src/configure.in
++++ b/src/configure.in
+@@ -744,6 +744,9 @@ fi
+ 
+ AC_HEADER_TIME
+ AC_CHECK_TYPE(time_t, long)
++AC_CHECK_SIZEOF(time_t)
++SIZEOF_TIME_T=$ac_cv_sizeof_time_t
++AC_SUBST(SIZEOF_TIME_T)
+ 
+ # Determine where to put the replay cache.
+ 
+diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in
+index 0fe02a95d..55f82b147 100644
+--- a/src/lib/krb5/krb/Makefile.in
++++ b/src/lib/krb5/krb/Makefile.in
+@@ -364,6 +364,7 @@ SRCS=	$(srcdir)/addr_comp.c	\
+ 	$(srcdir)/t_in_ccache.c	\
+ 	$(srcdir)/t_response_items.c \
+ 	$(srcdir)/t_sname_match.c \
++	$(srcdir)/t_valid_times.c \
+ 	$(srcdir)/t_vfy_increds.c
+ 
+ # Someday, when we have a "maintainer mode", do this right:
+@@ -457,9 +458,12 @@ t_response_items: t_response_items.o response_items.o $(KRB5_BASE_DEPLIBS)
+ t_sname_match: t_sname_match.o sname_match.o $(KRB5_BASE_DEPLIBS)
+ 	$(CC_LINK) -o $@ t_sname_match.o sname_match.o $(KRB5_BASE_LIBS)
+ 
++t_valid_times: t_valid_times.o valid_times.o $(KRB5_BASE_DEPLIBS)
++	$(CC_LINK) -o $@ t_valid_times.o valid_times.o $(KRB5_BASE_LIBS)
++
+ TEST_PROGS= t_walk_rtree t_kerb t_ser t_deltat t_expand t_authdata t_pac \
+-	t_in_ccache t_cc_config t_copy_context \
+-	t_princ t_etypes t_vfy_increds t_response_items t_sname_match
++	t_in_ccache t_cc_config t_copy_context t_princ t_etypes t_vfy_increds \
++	t_response_items t_sname_match t_valid_times
+ 
+ check-unix: $(TEST_PROGS)
+ 	$(RUN_TEST_LOCAL_CONF) ./t_kerb \
+@@ -496,6 +500,7 @@ check-unix: $(TEST_PROGS)
+ 	$(RUN_TEST) ./t_response_items
+ 	$(RUN_TEST) ./t_copy_context
+ 	$(RUN_TEST) ./t_sname_match
++	$(RUN_TEST) ./t_valid_times
+ 
+ check-pytests: t_expire_warn t_vfy_increds
+ 	$(RUNPYTEST) $(srcdir)/t_expire_warn.py $(PYTESTFLAGS)
+@@ -522,8 +527,9 @@ clean:
+ 	$(OUTPRE)t_ad_fx_armor$(EXEEXT) $(OUTPRE)t_ad_fx_armor.$(OBJEXT) \
+ 	$(OUTPRE)t_vfy_increds$(EXEEXT) $(OUTPRE)t_vfy_increds.$(OBJEXT) \
+ 	$(OUTPRE)t_response_items$(EXEEXT) \
+-	$(OUTPRE)t_response_items.$(OBJEXT) $(OUTPRE)t_sname_match$(EXEEXT) \
+-	$(OUTPRE)t_sname_match.$(OBJEXT) \
++	$(OUTPRE)t_response_items.$(OBJEXT) \
++	$(OUTPRE)t_sname_match$(EXEEXT) $(OUTPRE)t_sname_match.$(OBJEXT) \
++	$(OUTPRE)t_valid_times$(EXEEXT) $(OUTPRE)t_valid_times.$(OBJECT) \
+ 	$(OUTPRE)t_parse_host_string$(EXEEXT) \
+ 	$(OUTPRE)t_parse_host_string.$(OBJEXT)
+ 
+diff --git a/src/lib/krb5/krb/t_valid_times.c b/src/lib/krb5/krb/t_valid_times.c
+new file mode 100644
+index 000000000..1b469ffc2
+--- /dev/null
++++ b/src/lib/krb5/krb/t_valid_times.c
+@@ -0,0 +1,109 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* lib/krb5/krb/t_valid_times.c - test program for krb5int_validate_times() */
++/*
++ * Copyright (C) 2017 by the Massachusetts Institute of Technology.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ *
++ * * Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in
++ *   the documentation and/or other materials provided with the
++ *   distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
++ * OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "k5-int.h"
++#include "int-proto.h"
++
++#define BOUNDARY (uint32_t)INT32_MIN
++
++int
++main()
++{
++    krb5_error_code ret;
++    krb5_context context;
++    krb5_ticket_times times = { 0, 0, 0, 0 };
++
++    ret = krb5_init_context(&context);
++    assert(!ret);
++
++    /* Current time is within authtime and end time. */
++    ret = krb5_set_debugging_time(context, 1000, 0);
++    times.authtime = 500;
++    times.endtime = 1500;
++    ret = krb5int_validate_times(context, &times);
++    assert(!ret);
++
++    /* Current time is before starttime, but within clock skew. */
++    times.starttime = 1100;
++    ret = krb5int_validate_times(context, &times);
++    assert(!ret);
++
++    /* Current time is before starttime by more than clock skew. */
++    times.starttime = 1400;
++    ret = krb5int_validate_times(context, &times);
++    assert(ret == KRB5KRB_AP_ERR_TKT_NYV);
++
++    /* Current time is after end time, but within clock skew. */
++    times.starttime = 500;
++    times.endtime = 800;
++    ret = krb5int_validate_times(context, &times);
++    assert(!ret);
++
++    /* Current time is after end time by more than clock skew. */
++    times.endtime = 600;
++    ret = krb5int_validate_times(context, &times);
++    assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED);
++
++    /* Current time is within starttime and endtime; current time and
++     * endtime are across y2038 boundary. */
++    ret = krb5_set_debugging_time(context, BOUNDARY - 100, 0);
++    assert(!ret);
++    times.starttime = BOUNDARY - 200;
++    times.endtime = BOUNDARY + 500;
++    ret = krb5int_validate_times(context, &times);
++    assert(!ret);
++
++    /* Current time is before starttime, but by less than clock skew. */
++    times.starttime = BOUNDARY + 100;
++    ret = krb5int_validate_times(context, &times);
++    assert(!ret);
++
++    /* Current time is before starttime by more than clock skew. */
++    times.starttime = BOUNDARY + 250;
++    ret = krb5int_validate_times(context, &times);
++    assert(ret == KRB5KRB_AP_ERR_TKT_NYV);
++
++    /* Current time is after endtime, but by less than clock skew. */
++    ret = krb5_set_debugging_time(context, BOUNDARY + 100, 0);
++    assert(!ret);
++    times.starttime = BOUNDARY - 1000;
++    times.endtime = BOUNDARY - 100;
++    ret = krb5int_validate_times(context, &times);
++    assert(!ret);
++
++    /* Current time is after endtime by more than clock skew. */
++    times.endtime = BOUNDARY - 300;
++    ret = krb5int_validate_times(context, &times);
++    assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED);
++
++    return 0;
++}
+diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
+index 0e93d6b59..2b3112537 100644
+--- a/src/tests/Makefile.in
++++ b/src/tests/Makefile.in
+@@ -168,6 +168,7 @@ check-pytests: localauth plugorder rdreq responder s2p s4u2proxy unlockiter
+ 	$(RUNPYTEST) $(srcdir)/t_princflags.py $(PYTESTFLAGS)
+ 	$(RUNPYTEST) $(srcdir)/t_tabdump.py $(PYTESTFLAGS)
+ 	$(RUNPYTEST) $(srcdir)/t_certauth.py $(PYTESTFLAGS)
++	$(RUNPYTEST) $(srcdir)/t_y2038.py $(PYTESTFLAGS)
+ 
+ clean:
+ 	$(RM) adata etinfo forward gcred hist hooks hrealm icred kdbtest
+diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in
+index 6c1464297..604f926de 100644
+--- a/src/tests/gssapi/Makefile.in
++++ b/src/tests/gssapi/Makefile.in
+@@ -15,15 +15,16 @@ SRCS=	$(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.c \
+ 	$(srcdir)/t_gssexts.c $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c \
+ 	$(srcdir)/t_invalid.c $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_ctx.c \
+ 	$(srcdir)/t_inq_mechs_name.c $(srcdir)/t_iov.c \
+-	$(srcdir)/t_namingexts.c $(srcdir)/t_oid.c $(srcdir)/t_pcontok.c \
+-	$(srcdir)/t_prf.c $(srcdir)/t_s4u.c $(srcdir)/t_s4u2proxy_krb5.c \
+-	$(srcdir)/t_saslname.c $(srcdir)/t_spnego.c $(srcdir)/t_srcattrs.c
++	$(srcdir)/t_lifetime.c $(srcdir)/t_namingexts.c $(srcdir)/t_oid.c \
++	$(srcdir)/t_pcontok.c $(srcdir)/t_prf.c $(srcdir)/t_s4u.c \
++	$(srcdir)/t_s4u2proxy_krb5.c $(srcdir)/t_saslname.c \
++	$(srcdir)/t_spnego.c $(srcdir)/t_srcattrs.c
+ 
+ OBJS=	ccinit.o ccrefresh.o common.o t_accname.o t_ccselect.o t_ciflags.o \
+ 	t_credstore.o t_enctypes.o t_err.o t_export_cred.o t_export_name.o \
+ 	t_gssexts.o t_imp_cred.o t_imp_name.o t_invalid.o t_inq_cred.o \
+-	t_inq_ctx.o t_inq_mechs_name.o t_iov.o t_namingexts.o t_oid.o \
+-	t_pcontok.o t_prf.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \
++	t_inq_ctx.o t_inq_mechs_name.o t_iov.o t_lifetime.o t_namingexts.o \
++	t_oid.o t_pcontok.o t_prf.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \
+ 	t_spnego.o t_srcattrs.o
+ 
+ COMMON_DEPS= common.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+@@ -31,9 +32,9 @@ COMMON_LIBS= common.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
+ 
+ all: ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore t_enctypes \
+ 	t_err t_export_cred t_export_name t_gssexts t_imp_cred t_imp_name \
+-	t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_namingexts \
+-	t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5 t_saslname t_spnego \
+-	t_srcattrs
++	t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime \
++	t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5 t_saslname \
++	t_spnego t_srcattrs
+ 
+ check-unix: t_oid
+ 	$(RUN_TEST) ./t_invalid
+@@ -42,8 +43,8 @@ check-unix: t_oid
+ 
+ check-pytests: ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore \
+ 	t_enctypes t_err t_export_cred t_export_name t_imp_cred t_inq_cred \
+-	t_inq_ctx t_inq_mechs_name t_iov t_pcontok t_s4u t_s4u2proxy_krb5 \
+-	t_spnego t_srcattrs
++	t_inq_ctx t_inq_mechs_name t_iov t_lifetime t_pcontok t_s4u \
++	t_s4u2proxy_krb5 t_spnego t_srcattrs
+ 	$(RUNPYTEST) $(srcdir)/t_gssapi.py $(PYTESTFLAGS)
+ 	$(RUNPYTEST) $(srcdir)/t_ccselect.py $(PYTESTFLAGS)
+ 	$(RUNPYTEST) $(srcdir)/t_client_keytab.py $(PYTESTFLAGS)
+@@ -88,6 +89,8 @@ t_inq_mechs_name: t_inq_mechs_name.o $(COMMON_DEPS)
+ 	$(CC_LINK) -o $@ t_inq_mechs_name.o $(COMMON_LIBS)
+ t_iov: t_iov.o $(COMMON_DEPS)
+ 	$(CC_LINK) -o $@ t_iov.o $(COMMON_LIBS)
++t_lifetime: t_lifetime.o $(COMMON_DEPS)
++	$(CC_LINK) -o $@ t_lifetime.o $(COMMON_LIBS)
+ t_namingexts: t_namingexts.o $(COMMON_DEPS)
+ 	$(CC_LINK) -o $@ t_namingexts.o $(COMMON_LIBS)
+ t_pcontok: t_pcontok.o $(COMMON_DEPS)
+@@ -111,5 +114,5 @@ clean:
+ 	$(RM) ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore
+ 	$(RM) t_enctypes t_err t_export_cred t_export_name t_gssexts t_imp_cred
+ 	$(RM) t_imp_name t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov
+-	$(RM) t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5
+-	$(RM) t_saslname t_spnego t_srcattrs
++	$(RM) t_lifetime t_namingexts t_oid t_pcontok t_prf t_s4u
++	$(RM) t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs
+diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py
+index e23c936d7..fa214242f 100755
+--- a/src/tests/gssapi/t_gssapi.py
++++ b/src/tests/gssapi/t_gssapi.py
+@@ -220,4 +220,36 @@ realm.run(['./t_ciflags', 'p:' + realm.host_princ])
+ # contexts.
+ realm.run(['./t_inq_ctx', 'user', password('user'), 'p:%s' % realm.host_princ])
+ 
++# Test lifetime results, using a realm with a large maximum lifetime
++# so that we can test ticket end dates after y2038.  There are no
++# time_t conversions involved, so we can run these tests on platforms
++# with 32-bit time_t.
++realm.stop()
++conf = {'realms': {'$realm': {'max_life': '9000d'}}}
++realm = K5Realm(kdc_conf=conf, get_creds=False)
++
++# Check a lifetime string result against an expected number value (or None).
++# Allow some variance due to time elapsed during the tests.
++def check_lifetime(msg, val, expected):
++    if expected is None and val != 'indefinite':
++        fail('%s: expected indefinite, got %s' % (msg, val))
++    if expected is not None and val == 'indefinite':
++        fail('%s: expected %d, got indefinite' % (msg, expected))
++    if expected is not None and abs(int(val) - expected) > 100:
++        fail('%s: expected %d, got %s' % (msg, expected, val))
++
++realm.kinit(realm.user_princ, password('user'), flags=['-l', '8500d'])
++out = realm.run(['./t_lifetime', 'p:' + realm.host_princ, str(8000 * 86400)])
++ln = out.split('\n')
++check_lifetime('icred gss_acquire_cred', ln[0], 8500 * 86400)
++check_lifetime('icred gss_inquire_cred', ln[1], 8500 * 86400)
++check_lifetime('acred gss_acquire_cred', ln[2], None)
++check_lifetime('acred gss_inquire_cred', ln[3], None)
++check_lifetime('ictx gss_init_sec_context', ln[4], 8000 * 86400)
++check_lifetime('ictx gss_inquire_context', ln[5], 8000 * 86400)
++check_lifetime('ictx gss_context_time', ln[6], 8000 * 86400)
++check_lifetime('actx gss_accept_sec_context', ln[7], 8000 * 86400 + 300)
++check_lifetime('actx gss_inquire_context', ln[8], 8000 * 86400 + 300)
++check_lifetime('actx gss_context_time', ln[9], 8000 * 86400 + 300)
++
+ success('GSSAPI tests')
+diff --git a/src/tests/gssapi/t_lifetime.c b/src/tests/gssapi/t_lifetime.c
+new file mode 100644
+index 000000000..8dcf18621
+--- /dev/null
++++ b/src/tests/gssapi/t_lifetime.c
+@@ -0,0 +1,140 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* tests/gssapi/t_lifetime.c - display cred and context lifetimes */
++/*
++ * Copyright (C) 2017 by the Massachusetts Institute of Technology.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ *
++ * * Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in
++ *   the documentation and/or other materials provided with the
++ *   distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
++ * OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <assert.h>
++#include "common.h"
++
++/*
++ * Using the default credential, exercise the GSS functions which accept or
++ * produce lifetimes.  Display the following results, one per line, as ASCII
++ * integers or the string "indefinite":
++ *
++ *   initiator cred lifetime according to gss_acquire_cred()
++ *   initiator cred lifetime according to gss_inquire_cred()
++ *   acceptor cred lifetime according to gss_acquire_cred()
++ *   acceptor cred lifetime according to gss_inquire_cred()
++ *   initiator context lifetime according to gss_init_sec_context()
++ *   initiator context lifetime according to gss_inquire_context()
++ *   initiator context lifetime according to gss_context_time()
++ *   acceptor context lifetime according to gss_init_sec_context()
++ *   acceptor context lifetime according to gss_inquire_context()
++ *   acceptor context lifetime according to gss_context_time()
++ */
++
++static void
++display_time(OM_uint32 tval)
++{
++    if (tval == GSS_C_INDEFINITE)
++        puts("indefinite");
++    else
++        printf("%u\n", (unsigned int)tval);
++}
++
++int
++main(int argc, char *argv[])
++{
++    OM_uint32 minor, major;
++    gss_cred_id_t icred, acred;
++    gss_name_t tname;
++    gss_ctx_id_t ictx = GSS_C_NO_CONTEXT, actx = GSS_C_NO_CONTEXT;
++    gss_buffer_desc itok = GSS_C_EMPTY_BUFFER, atok = GSS_C_EMPTY_BUFFER;
++    OM_uint32 time_req = GSS_C_INDEFINITE, time_rec;
++
++    if (argc < 2 || argc > 3) {
++        fprintf(stderr, "Usage: %s targetname [time_req]\n", argv[0]);
++        return 1;
++    }
++    tname = import_name(argv[1]);
++    if (argc >= 3)
++        time_req = atoll(argv[2]);
++
++    /* Get initiator cred and display its lifetime according to
++     * gss_acquire_cred and gss_inquire_cred. */
++    major = gss_acquire_cred(&minor, GSS_C_NO_NAME, time_req, &mechset_krb5,
++                             GSS_C_INITIATE, &icred, NULL, &time_rec);
++    check_gsserr("gss_acquire_cred(initiate)", major, minor);
++    display_time(time_rec);
++    major = gss_inquire_cred(&minor, icred, NULL, &time_rec, NULL, NULL);
++    check_gsserr("gss_inquire_cred(initiate)", major, minor);
++    display_time(time_rec);
++
++    /* Get acceptor cred and display its lifetime according to gss_acquire_cred
++     * and gss_inquire_cred. */
++    major = gss_acquire_cred(&minor, GSS_C_NO_NAME, time_req, &mechset_krb5,
++                             GSS_C_ACCEPT, &acred, NULL, &time_rec);
++    check_gsserr("gss_acquire_cred(accept)", major, minor);
++    display_time(time_rec);
++    major = gss_inquire_cred(&minor, acred, NULL, &time_rec, NULL, NULL);
++    check_gsserr("gss_inquire_cred(accept)", major, minor);
++    display_time(time_rec);
++
++    /* Make an initiator context and display its lifetime according to
++     * gss_init_sec_context, gss_inquire_context, and gss_context_time. */
++    major = gss_init_sec_context(&minor, icred, &ictx, tname, &mech_krb5, 0,
++                                 time_req, GSS_C_NO_CHANNEL_BINDINGS, &atok,
++                                 NULL, &itok, NULL, &time_rec);
++    check_gsserr("gss_init_sec_context", major, minor);
++    assert(major == GSS_S_COMPLETE);
++    display_time(time_rec);
++    major = gss_inquire_context(&minor, ictx, NULL, NULL, &time_rec, NULL,
++                                NULL, NULL, NULL);
++    check_gsserr("gss_inquire_context(initiate)", major, minor);
++    display_time(time_rec);
++    major = gss_context_time(&minor, ictx, &time_rec);
++    check_gsserr("gss_context_time(initiate)", major, minor);
++    display_time(time_rec);
++
++    major = gss_accept_sec_context(&minor, &actx, acred, &itok,
++                                   GSS_C_NO_CHANNEL_BINDINGS, NULL,
++                                   NULL, &atok, NULL, &time_rec, NULL);
++    check_gsserr("gss_accept_sec_context", major, minor);
++    assert(major == GSS_S_COMPLETE);
++    display_time(time_rec);
++    major = gss_inquire_context(&minor, actx, NULL, NULL, &time_rec, NULL,
++                                NULL, NULL, NULL);
++    check_gsserr("gss_inquire_context(accept)", major, minor);
++    display_time(time_rec);
++    major = gss_context_time(&minor, actx, &time_rec);
++    check_gsserr("gss_context_time(accept)", major, minor);
++    display_time(time_rec);
++
++    (void)gss_release_buffer(&minor, &itok);
++    (void)gss_release_buffer(&minor, &atok);
++    (void)gss_release_name(&minor, &tname);
++    (void)gss_release_cred(&minor, &icred);
++    (void)gss_release_cred(&minor, &acred);
++    (void)gss_delete_sec_context(&minor, &ictx, NULL);
++    (void)gss_delete_sec_context(&minor, &actx, NULL);
++    return 0;
++}
+diff --git a/src/tests/t_kdb.py b/src/tests/t_kdb.py
+index 185225afa..c0eeb0118 100755
+--- a/src/tests/t_kdb.py
++++ b/src/tests/t_kdb.py
+@@ -446,6 +446,13 @@ realm.run([kadminl, 'addprinc', '-policy', 'keepoldpasspol', '-pw', 'aaaa',
+ for p in ('bbbb', 'cccc', 'aaaa'):
+     realm.run([kadminl, 'cpw', '-keepold', '-pw', p, 'keepoldpassprinc'])
+ 
++if runenv.sizeof_time_t <= 4:
++    skipped('y2038 LDAP test', 'platform has 32-bit time_t')
++else:
++    # Test storage of timestamps after y2038.
++    realm.run([kadminl, 'modprinc', '-pwexpire', '2040-02-03', 'user'])
++    realm.run([kadminl, 'getprinc', 'user'], expected_msg=' 2040\n')
++
+ realm.stop()
+ 
+ # Briefly test dump and load.
+diff --git a/src/tests/t_y2038.py b/src/tests/t_y2038.py
+new file mode 100644
+index 000000000..02e946df4
+--- /dev/null
++++ b/src/tests/t_y2038.py
+@@ -0,0 +1,75 @@
++#!/usr/bin/python
++from k5test import *
++
++# These tests will become much less important after the y2038 boundary
++# has elapsed, and may start exhibiting problems around the year 2075.
++
++if runenv.sizeof_time_t <= 4:
++    skip_rest('y2038 timestamp tests', 'platform has 32-bit time_t')
++
++# Start a KDC running roughly 21 years in the future, after the y2038
++# boundary.  Set long maximum lifetimes for later tests.
++conf = {'realms': {'$realm': {'max_life': '9000d',
++                              'max_renewable_life': '9000d'}}}
++realm = K5Realm(start_kdc=False, kdc_conf=conf)
++realm.start_kdc(['-T', '662256000'])
++
++# kinit without preauth should succeed with clock skew correction, but
++# will result in an expired ticket, because we sent an absolute end
++# time and didn't get a chance to correct it..
++realm.kinit(realm.user_princ, password('user'))
++realm.run([kvno, realm.host_princ], expected_code=1,
++          expected_msg='Ticket expired')
++
++# kinit with preauth should succeed and result in a valid ticket, as
++# we get a chance to correct the end time based on the KDC time.  Try
++# with encrypted timestamp and encrypted challenge.
++realm.run([kadminl, 'modprinc', '+requires_preauth', 'user'])
++realm.kinit(realm.user_princ, password('user'))
++realm.run([kvno, realm.host_princ])
++realm.kinit(realm.user_princ, password('user'), flags=['-T', realm.ccache])
++realm.run([kvno, realm.host_princ])
++
++# Test that expiration warning works after y2038, by setting a
++# password expiration time ten minutes after the KDC time.
++realm.run([kadminl, 'modprinc', '-pwexpire', '662256600 seconds', 'user'])
++out = realm.kinit(realm.user_princ, password('user'))
++if 'will expire in less than one hour' not in out:
++    fail('password expiration message')
++year = int(out.split()[-1])
++if year < 2038 or year > 9999:
++    fail('password expiration year')
++
++realm.stop_kdc()
++realm.start_kdc()
++realm.start_kadmind()
++realm.prep_kadmin()
++
++# Test getdate parsing of absolute timestamps after 2038 and
++# marshalling over the kadmin protocol.  The local time zone will
++# affect the display time by a little bit, so just look for the year.
++realm.run_kadmin(['modprinc', '-pwexpire', '2040-02-03', realm.host_princ])
++realm.run_kadmin(['getprinc', realm.host_princ], expected_msg=' 2040\n')
++
++# Get a ticket whose lifetime crosses the y2038 boundary and
++# range-check the expiration year as reported by klist.
++realm.kinit(realm.user_princ, password('user'),
++            flags=['-l', '8000d', '-r', '8500d'])
++realm.run([kvno, realm.host_princ])
++out = realm.run([klist])
++if int(out.split('\n')[4].split()[2].split('/')[2]) < 39:
++    fail('unexpected tgt expiration year')
++if int(out.split('\n')[5].split()[2].split('/')[2]) < 40:
++    fail('unexpected tgt rtill year')
++if int(out.split('\n')[6].split()[2].split('/')[2]) < 39:
++    fail('unexpected service ticket expiration year')
++if int(out.split('\n')[7].split()[2].split('/')[2]) < 40:
++    fail('unexpected service ticket rtill year')
++realm.kinit(realm.user_princ, None, ['-R'])
++out = realm.run([klist])
++if int(out.split('\n')[4].split()[2].split('/')[2]) < 39:
++    fail('unexpected renewed tgt expiration year')
++if int(out.split('\n')[5].split()[2].split('/')[2]) < 40:
++    fail('unexpected renewed tgt rtill year')
++
++success('y2038 tests')
diff --git a/SOURCES/Add-y2038-documentation.patch b/SOURCES/Add-y2038-documentation.patch
new file mode 100644
index 0000000..01642e1
--- /dev/null
+++ b/SOURCES/Add-y2038-documentation.patch
@@ -0,0 +1,60 @@
+From f9702eabc568679f48ea5d0bc7be073582cc52ad Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Thu, 4 May 2017 17:03:35 -0400
+Subject: [PATCH] Add y2038 documentation
+
+ticket: 8352
+(cherry picked from commit 85d64c43dbf7a7faa56a1999494cdfa49e8bd2c9)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ doc/appdev/index.rst |  1 +
+ doc/appdev/y2038.rst | 28 ++++++++++++++++++++++++++++
+ 2 files changed, 29 insertions(+)
+ create mode 100644 doc/appdev/y2038.rst
+
+diff --git a/doc/appdev/index.rst b/doc/appdev/index.rst
+index 3d62045ca..961bb1e9e 100644
+--- a/doc/appdev/index.rst
++++ b/doc/appdev/index.rst
+@@ -5,6 +5,7 @@ For application developers
+    :maxdepth: 1
+ 
+    gssapi.rst
++   y2038.rst
+    h5l_mit_apidiff.rst
+    init_creds.rst
+    princ_handle.rst
+diff --git a/doc/appdev/y2038.rst b/doc/appdev/y2038.rst
+new file mode 100644
+index 000000000..bc4122dad
+--- /dev/null
++++ b/doc/appdev/y2038.rst
+@@ -0,0 +1,28 @@
++Year 2038 considerations for uses of krb5_timestamp
++===================================================
++
++POSIX time values, which measure the number of seconds since January 1
++1970, will exceed the maximum value representable in a signed 32-bit
++integer in January 2038.  This documentation describes considerations
++for consumers of the MIT krb5 libraries.
++
++Applications or libraries which use libkrb5 and consume the timestamps
++included in credentials or other structures make use of the
++:c:type:`krb5_timestamp` type.  For historical reasons, krb5_timestamp
++is a signed 32-bit integer, even on platforms where a larger type is
++natively used to represent time values.  To behave properly for time
++values after January 2038, calling code should cast krb5_timestamp
++values to uint32_t, and then to time_t::
++
++    (time_t)(uint32_t)timestamp
++
++Used in this way, krb5_timestamp values can represent time values up
++until February 2106, provided that the platform uses a 64-bit or
++larger time_t type.  This usage will also remain safe if a later
++version of MIT krb5 changes krb5_timestamp to an unsigned 32-bit
++integer.
++
++The GSSAPI only uses representations of time intervals, not absolute
++times.  Callers of the GSSAPI should require no changes to behave
++correctly after January 2038, provided that they use MIT krb5 release
++1.16 or later.
diff --git a/SOURCES/Allow-clock-skew-in-krb5-gss_context_time.patch b/SOURCES/Allow-clock-skew-in-krb5-gss_context_time.patch
new file mode 100644
index 0000000..8eb9c2e
--- /dev/null
+++ b/SOURCES/Allow-clock-skew-in-krb5-gss_context_time.patch
@@ -0,0 +1,37 @@
+From 498b43b1a58795773834c1c5bb2b61dd801b9a03 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Sat, 22 Apr 2017 16:51:23 -0400
+Subject: [PATCH] Allow clock skew in krb5 gss_context_time()
+
+Commit b496ce4095133536e0ace36b74130e4b9ecb5e11 (ticket #8268) adds
+the clock skew to krb5 acceptor context lifetimes for
+gss_accept_sec_context() and gss_inquire_context(), but not for
+gss_context_time().  Add the clock skew in gss_context_time() as well.
+
+ticket: 8581 (new)
+target_version: 1.14-next
+target_version: 1.15-next
+tags: pullup
+
+(cherry picked from commit b0a072e6431261734e7350996a363801f180e8ea)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/lib/gssapi/krb5/context_time.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c
+index a18cfb05b..450593288 100644
+--- a/src/lib/gssapi/krb5/context_time.c
++++ b/src/lib/gssapi/krb5/context_time.c
+@@ -51,7 +51,10 @@ krb5_gss_context_time(minor_status, context_handle, time_rec)
+         return(GSS_S_FAILURE);
+     }
+ 
+-    if ((lifetime = ctx->krb_times.endtime - now) <= 0) {
++    lifetime = ctx->krb_times.endtime - now;
++    if (!ctx->initiate)
++        lifetime += ctx->k5_context->clockskew;
++    if (lifetime <= 0) {
+         *time_rec = 0;
+         *minor_status = 0;
+         return(GSS_S_CONTEXT_EXPIRED);
diff --git a/SOURCES/Convert-some-pkiDebug-messages-to-TRACE-macros.patch b/SOURCES/Convert-some-pkiDebug-messages-to-TRACE-macros.patch
new file mode 100644
index 0000000..69f99cb
--- /dev/null
+++ b/SOURCES/Convert-some-pkiDebug-messages-to-TRACE-macros.patch
@@ -0,0 +1,424 @@
+From b4c2212ae7412e21f4965acdb8c10e4a60b65b9b Mon Sep 17 00:00:00 2001
+From: Matt Rogers <mrogers@redhat.com>
+Date: Wed, 29 Mar 2017 10:35:13 -0400
+Subject: [PATCH] Convert some pkiDebug messages to TRACE macros
+
+ticket: 8568 (new)
+(cherry picked from commit 9852862a83952a94300adfafa3e333f43396ec33)
+(cherry picked from commit 686fa6476eb759532d566794fa8d430774d44cf7)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 46 ++++++---------
+ src/plugins/preauth/pkinit/pkinit_identity.c       |  3 -
+ src/plugins/preauth/pkinit/pkinit_matching.c       |  1 +
+ src/plugins/preauth/pkinit/pkinit_srv.c            | 24 ++++----
+ src/plugins/preauth/pkinit/pkinit_trace.h          | 68 +++++++++++++++++++++-
+ 5 files changed, 97 insertions(+), 45 deletions(-)
+
+diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+index 90c30dbf5..70e230ec2 100644
+--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+@@ -2320,7 +2320,6 @@ crypto_check_cert_eku(krb5_context context,
+ 
+     X509_NAME_oneline(X509_get_subject_name(reqctx->received_cert),
+                       buf, sizeof(buf));
+-    pkiDebug("%s: looking for EKUs in cert = %s\n", __FUNCTION__, buf);
+ 
+     if ((i = X509_get_ext_by_NID(reqctx->received_cert,
+                                  NID_ext_key_usage, -1)) >= 0) {
+@@ -2354,7 +2353,6 @@ crypto_check_cert_eku(krb5_context context,
+ 
+         if (found_eku) {
+             ASN1_BIT_STRING *usage = NULL;
+-            pkiDebug("%s: found acceptable EKU, checking for digitalSignature\n", __FUNCTION__);
+ 
+             /* check that digitalSignature KeyUsage is present */
+             X509_check_ca(reqctx->received_cert);
+@@ -2363,12 +2361,10 @@ crypto_check_cert_eku(krb5_context context,
+ 
+                 if (!ku_reject(reqctx->received_cert,
+                                X509v3_KU_DIGITAL_SIGNATURE)) {
+-                    pkiDebug("%s: found digitalSignature KU\n",
+-                             __FUNCTION__);
++                    TRACE_PKINIT_EKU(context);
+                     *valid_eku = 1;
+                 } else
+-                    pkiDebug("%s: didn't find digitalSignature KU\n",
+-                             __FUNCTION__);
++                    TRACE_PKINIT_EKU_NO_KU(context);
+             }
+             ASN1_BIT_STRING_free(usage);
+         }
+@@ -4317,8 +4313,7 @@ pkinit_get_certs_pkcs12(krb5_context context,
+ 
+     fp = fopen(idopts->cert_filename, "rb");
+     if (fp == NULL) {
+-        pkiDebug("Failed to open PKCS12 file '%s', error %d\n",
+-                 idopts->cert_filename, errno);
++        TRACE_PKINIT_PKCS_OPEN_FAIL(context, idopts->cert_filename, errno);
+         goto cleanup;
+     }
+     set_cloexec_file(fp);
+@@ -4326,8 +4321,7 @@ pkinit_get_certs_pkcs12(krb5_context context,
+     p12 = d2i_PKCS12_fp(fp, NULL);
+     fclose(fp);
+     if (p12 == NULL) {
+-        pkiDebug("Failed to decode PKCS12 file '%s' contents\n",
+-                 idopts->cert_filename);
++        TRACE_PKINIT_PKCS_DECODE_FAIL(context, idopts->cert_filename);
+         goto cleanup;
+     }
+     /*
+@@ -4345,7 +4339,7 @@ pkinit_get_certs_pkcs12(krb5_context context,
+         char *p12name = reassemble_pkcs12_name(idopts->cert_filename);
+         const char *tmp;
+ 
+-        pkiDebug("Initial PKCS12_parse with no password failed\n");
++        TRACE_PKINIT_PKCS_PARSE_FAIL_FIRST(context);
+ 
+         if (id_cryptoctx->defer_id_prompt) {
+             /* Supply the identity name to be passed to the responder. */
+@@ -4386,14 +4380,14 @@ pkinit_get_certs_pkcs12(krb5_context context,
+                                           NULL, NULL, 1, &kprompt);
+             k5int_set_prompt_types(context, 0);
+             if (r) {
+-                pkiDebug("Failed to prompt for PKCS12 password");
++                TRACE_PKINIT_PKCS_PROMPT_FAIL(context);
+                 goto cleanup;
+             }
+         }
+ 
+         ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL);
+         if (ret == 0) {
+-            pkiDebug("Second PKCS12_parse with password failed\n");
++            TRACE_PKINIT_PKCS_PARSE_FAIL_SECOND(context);
+             goto cleanup;
+         }
+     }
+@@ -4516,8 +4510,7 @@ pkinit_get_certs_fs(krb5_context context,
+     }
+ 
+     if (idopts->key_filename == NULL) {
+-        pkiDebug("%s: failed to get user's private key location\n",
+-                 __FUNCTION__);
++        TRACE_PKINIT_NO_PRIVKEY(context);
+         goto cleanup;
+     }
+ 
+@@ -4545,8 +4538,7 @@ pkinit_get_certs_dir(krb5_context context,
+     char *dirname, *suf;
+ 
+     if (idopts->cert_filename == NULL) {
+-        pkiDebug("%s: failed to get user's certificate directory location\n",
+-                 __FUNCTION__);
++        TRACE_PKINIT_NO_CERT(context);
+         return ENOENT;
+     }
+ 
+@@ -4590,8 +4582,7 @@ pkinit_get_certs_dir(krb5_context context,
+         retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
+                                              certname, keyname, i);
+         if (retval == 0) {
+-            pkiDebug("%s: Successfully loaded cert (and key) for %s\n",
+-                     __FUNCTION__, dentry->d_name);
++            TRACE_PKINIT_LOADED_CERT(context, dentry->d_name);
+             i++;
+         }
+         else
+@@ -4599,8 +4590,7 @@ pkinit_get_certs_dir(krb5_context context,
+     }
+ 
+     if (!id_cryptoctx->defer_id_prompt && i == 0) {
+-        pkiDebug("%s: No cert/key pairs found in directory '%s'\n",
+-                 __FUNCTION__, idopts->cert_filename);
++        TRACE_PKINIT_NO_CERT_AND_KEY(context, idopts->cert_filename);
+         retval = ENOENT;
+         goto cleanup;
+     }
+@@ -5370,9 +5360,7 @@ crypto_cert_select_default(krb5_context context,
+         goto errout;
+     }
+     if (cert_count != 1) {
+-        pkiDebug("%s: ERROR: There are %d certs to choose from, "
+-                 "but there must be exactly one.\n",
+-                 __FUNCTION__, cert_count);
++        TRACE_PKINIT_NO_DEFAULT_CERT(context, cert_count);
+         retval = EINVAL;
+         goto errout;
+     }
+@@ -5520,7 +5508,7 @@ load_cas_and_crls(krb5_context context,
+     switch(catype) {
+     case CATYPE_ANCHORS:
+         if (sk_X509_num(ca_certs) == 0) {
+-            pkiDebug("no anchors in file, %s\n", filename);
++            TRACE_PKINIT_NO_CA_ANCHOR(context, filename);
+             if (id_cryptoctx->trustedCAs == NULL)
+                 sk_X509_free(ca_certs);
+         } else {
+@@ -5530,7 +5518,7 @@ load_cas_and_crls(krb5_context context,
+         break;
+     case CATYPE_INTERMEDIATES:
+         if (sk_X509_num(ca_certs) == 0) {
+-            pkiDebug("no intermediates in file, %s\n", filename);
++            TRACE_PKINIT_NO_CA_INTERMEDIATE(context, filename);
+             if (id_cryptoctx->intermediateCAs == NULL)
+                 sk_X509_free(ca_certs);
+         } else {
+@@ -5540,7 +5528,7 @@ load_cas_and_crls(krb5_context context,
+         break;
+     case CATYPE_CRLS:
+         if (sk_X509_CRL_num(ca_crls) == 0) {
+-            pkiDebug("no crls in file, %s\n", filename);
++            TRACE_PKINIT_NO_CRL(context, filename);
+             if (id_cryptoctx->revoked == NULL)
+                 sk_X509_CRL_free(ca_crls);
+         } else {
+@@ -5626,14 +5614,14 @@ crypto_load_cas_and_crls(krb5_context context,
+                          int catype,
+                          char *id)
+ {
+-    pkiDebug("%s: called with idtype %s and catype %s\n",
+-             __FUNCTION__, idtype2string(idtype), catype2string(catype));
+     switch (idtype) {
+     case IDTYPE_FILE:
++        TRACE_PKINIT_LOAD_FROM_FILE(context);
+         return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
+                                  id_cryptoctx, catype, id);
+         break;
+     case IDTYPE_DIR:
++        TRACE_PKINIT_LOAD_FROM_DIR(context);
+         return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx,
+                                      id_cryptoctx, catype, id);
+         break;
+diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c
+index a897efa25..737552e85 100644
+--- a/src/plugins/preauth/pkinit/pkinit_identity.c
++++ b/src/plugins/preauth/pkinit/pkinit_identity.c
+@@ -608,7 +608,6 @@ pkinit_identity_prompt(krb5_context context,
+             retval = pkinit_cert_matching(context, plg_cryptoctx,
+                                           req_cryptoctx, id_cryptoctx, princ);
+             if (retval) {
+-                pkiDebug("%s: No matching certificate found\n", __FUNCTION__);
+                 crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
+                                       id_cryptoctx);
+                 goto errout;
+@@ -621,8 +620,6 @@ pkinit_identity_prompt(krb5_context context,
+             retval = crypto_cert_select_default(context, plg_cryptoctx,
+                                                 req_cryptoctx, id_cryptoctx);
+             if (retval) {
+-                pkiDebug("%s: Failed while selecting default certificate\n",
+-                         __FUNCTION__);
+                 crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
+                                       id_cryptoctx);
+                 goto errout;
+diff --git a/src/plugins/preauth/pkinit/pkinit_matching.c b/src/plugins/preauth/pkinit/pkinit_matching.c
+index a50c50c8d..cad4c2b9a 100644
+--- a/src/plugins/preauth/pkinit/pkinit_matching.c
++++ b/src/plugins/preauth/pkinit/pkinit_matching.c
+@@ -812,6 +812,7 @@ pkinit_cert_matching(krb5_context context,
+             goto cleanup;
+         }
+     } else {
++        TRACE_PKINIT_NO_MATCHING_CERT(context);
+         retval = ENOENT;    /* XXX */
+         goto cleanup;
+     }
+diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
+index 32ca122f2..9c6e96c9e 100644
+--- a/src/plugins/preauth/pkinit/pkinit_srv.c
++++ b/src/plugins/preauth/pkinit/pkinit_srv.c
+@@ -188,6 +188,7 @@ verify_client_san(krb5_context context,
+                                        plgctx->opts->allow_upn ? &upns : NULL,
+                                        NULL);
+     if (retval == ENOENT) {
++        TRACE_PKINIT_SERVER_NO_SAN(context);
+         goto out;
+     } else if (retval) {
+         pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__);
+@@ -224,7 +225,7 @@ verify_client_san(krb5_context context,
+         krb5_free_unparsed_name(context, san_string);
+ #endif
+         if (cb->match_client(context, rock, princs[i])) {
+-            pkiDebug("%s: pkinit san match found\n", __FUNCTION__);
++            TRACE_PKINIT_SERVER_MATCHING_SAN_FOUND(context);
+             *valid_san = 1;
+             retval = 0;
+             goto out;
+@@ -252,7 +253,7 @@ verify_client_san(krb5_context context,
+         krb5_free_unparsed_name(context, san_string);
+ #endif
+         if (cb->match_client(context, rock, upns[i])) {
+-            pkiDebug("%s: upn san match found\n", __FUNCTION__);
++            TRACE_PKINIT_SERVER_MATCHING_UPN_FOUND(context);
+             *valid_san = 1;
+             retval = 0;
+             goto out;
+@@ -300,7 +301,7 @@ verify_client_eku(krb5_context context,
+     *eku_accepted = 0;
+ 
+     if (plgctx->opts->require_eku == 0) {
+-        pkiDebug("%s: configuration requests no EKU checking\n", __FUNCTION__);
++        TRACE_PKINIT_SERVER_EKU_SKIP(context);
+         *eku_accepted = 1;
+         retval = 0;
+         goto out;
+@@ -364,6 +365,7 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
+     ret = KRB5_PLUGIN_NO_HANDLE;
+     for (i = 0; certauth_modules != NULL && certauth_modules[i] != NULL; i++) {
+         h = certauth_modules[i];
++        TRACE_PKINIT_SERVER_CERT_AUTH(context, h->vt.name);
+         ret = h->vt.authorize(context, h->moddata, cert, cert_len, client,
+                               &opts, db_ent, &ais);
+         if (ret == 0)
+@@ -449,7 +451,7 @@ pkinit_server_verify_padata(krb5_context context,
+ 
+     switch ((int)data->pa_type) {
+     case KRB5_PADATA_PK_AS_REQ:
+-        pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
++        TRACE_PKINIT_SERVER_PADATA_VERIFY(context);
+         retval = k5int_decode_krb5_pa_pk_as_req(&k5data, &reqp);
+         if (retval) {
+             pkiDebug("decode_krb5_pa_pk_as_req failed\n");
+@@ -472,7 +474,7 @@ pkinit_server_verify_padata(krb5_context context,
+         break;
+     case KRB5_PADATA_PK_AS_REP_OLD:
+     case KRB5_PADATA_PK_AS_REQ_OLD:
+-        pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n");
++        TRACE_PKINIT_SERVER_PADATA_VERIFY_OLD(context);
+         retval = k5int_decode_krb5_pa_pk_as_req_draft9(&k5data, &reqp9);
+         if (retval) {
+             pkiDebug("decode_krb5_pa_pk_as_req_draft9 failed\n");
+@@ -500,7 +502,7 @@ pkinit_server_verify_padata(krb5_context context,
+         goto cleanup;
+     }
+     if (retval) {
+-        pkiDebug("pkcs7_signeddata_verify failed\n");
++        TRACE_PKINIT_SERVER_PADATA_VERIFY_FAIL(context);
+         goto cleanup;
+     }
+     if (is_signed) {
+@@ -830,7 +832,7 @@ pkinit_server_return_padata(krb5_context context,
+         return ENOENT;
+     }
+ 
+-    pkiDebug("pkinit_return_padata: entered!\n");
++    TRACE_PKINIT_SERVER_RETURN_PADATA(context);
+     reqctx = (pkinit_kdc_req_context)modreq;
+ 
+     if (encrypting_key->contents) {
+@@ -1463,8 +1465,7 @@ pkinit_san_authorize(krb5_context context, krb5_certauth_moddata moddata,
+         return ret;
+ 
+     if (!valid_san) {
+-        pkiDebug("%s: did not find an acceptable SAN in user certificate\n",
+-                 __FUNCTION__);
++        TRACE_PKINIT_SERVER_SAN_REJECT(context);
+         return KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
+     }
+ 
+@@ -1490,8 +1491,7 @@ pkinit_eku_authorize(krb5_context context, krb5_certauth_moddata moddata,
+         return ret;
+ 
+     if (!valid_eku) {
+-        pkiDebug("%s: did not find an acceptable EKU in user certificate\n",
+-                 __FUNCTION__);
++        TRACE_PKINIT_SERVER_EKU_REJECT(context);
+         return KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
+     }
+ 
+@@ -1617,7 +1617,7 @@ pkinit_server_plugin_init(krb5_context context,
+         return ENOMEM;
+ 
+     for (i = 0, j = 0; i < numrealms; i++) {
+-        pkiDebug("%s: processing realm '%s'\n", __FUNCTION__, realmnames[i]);
++        TRACE_PKINIT_SERVER_INIT_REALM(context, realmnames[i]);
+         retval = pkinit_server_plugin_init_realm(context, realmnames[i], &plgctx);
+         if (retval == 0 && plgctx != NULL)
+             realm_contexts[j++] = plgctx;
+diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h
+index 458d0961e..6abe28c0c 100644
+--- a/src/plugins/preauth/pkinit/pkinit_trace.h
++++ b/src/plugins/preauth/pkinit/pkinit_trace.h
+@@ -52,7 +52,7 @@
+ #define TRACE_PKINIT_CLIENT_REP_CHECKSUM_FAIL(c, expected, received)    \
+     TRACE(c, "PKINIT client checksum mismatch: expected {cksum}, "      \
+           "received {cksum}", expected, received)
+-#define TRACE_PKINIT_CLIENT_REP_DH(c)                   \
++#define TRACE_PKINIT_CLIENT_REP_DH(c)           \
+     TRACE(c, "PKINIT client verified DH reply")
+ #define TRACE_PKINIT_CLIENT_REP_DH_FAIL(c)              \
+     TRACE(c, "PKINIT client could not verify DH reply")
+@@ -91,6 +91,72 @@
+ #define TRACE_PKINIT_OPENSSL_ERROR(c, msg)              \
+     TRACE(c, "PKINIT OpenSSL error: {str}", msg)
+ 
++#define TRACE_PKINIT_SERVER_CERT_AUTH(c, modname)                       \
++    TRACE(c, "PKINIT server authorizing cert with module {str}",        \
++          modname)
++#define TRACE_PKINIT_SERVER_EKU_REJECT(c)                               \
++    TRACE(c, "PKINIT server found no acceptable EKU in client cert")
++#define TRACE_PKINIT_SERVER_EKU_SKIP(c)                                 \
++    TRACE(c, "PKINIT server skipping EKU check due to configuration")
++#define TRACE_PKINIT_SERVER_INIT_REALM(c, realm)                \
++    TRACE(c, "PKINIT server initializing realm {str}", realm)
++#define TRACE_PKINIT_SERVER_MATCHING_UPN_FOUND(c)                       \
++    TRACE(c, "PKINIT server found a matching UPN SAN in client cert")
++#define TRACE_PKINIT_SERVER_MATCHING_SAN_FOUND(c)                       \
++    TRACE(c, "PKINIT server found a matching SAN in client cert")
++#define TRACE_PKINIT_SERVER_NO_SAN(c)                           \
++    TRACE(c, "PKINIT server found no SAN in client cert")
++#define TRACE_PKINIT_SERVER_PADATA_VERIFY(c)                    \
++    TRACE(c, "PKINIT server verifying KRB5_PADATA_PK_AS_REQ")
++#define TRACE_PKINIT_SERVER_PADATA_VERIFY_OLD(c)                        \
++    TRACE(c, "PKINIT server verifying KRB5_PADATA_PK_AS_REQ_OLD")
++#define TRACE_PKINIT_SERVER_PADATA_VERIFY_FAIL(c)       \
++    TRACE(c, "PKINIT server failed to verify PA data")
++#define TRACE_PKINIT_SERVER_RETURN_PADATA(c)    \
++    TRACE(c, "PKINIT server returning PA data")
++#define TRACE_PKINIT_SERVER_SAN_REJECT(c)                               \
++    TRACE(c, "PKINIT server found no acceptable SAN in client cert")
++
++#define TRACE_PKINIT_EKU(c)                                             \
++    TRACE(c, "PKINIT found acceptable EKU and digitalSignature KU")
++#define TRACE_PKINIT_EKU_NO_KU(c)                                       \
++    TRACE(c, "PKINIT found acceptable EKU but no digitalSignature KU")
++#define TRACE_PKINIT_LOADED_CERT(c, name)                       \
++    TRACE(c, "PKINIT loaded cert and key for {str}", name)
++#define TRACE_PKINIT_LOAD_FROM_FILE(c)                          \
++    TRACE(c, "PKINIT loading CA certs and CRLs from FILE")
++#define TRACE_PKINIT_LOAD_FROM_DIR(c)                           \
++    TRACE(c, "PKINIT loading CA certs and CRLs from DIR")
++#define TRACE_PKINIT_NO_CA_ANCHOR(c, file)              \
++    TRACE(c, "PKINIT no anchor CA in file {str}", file)
++#define TRACE_PKINIT_NO_CA_INTERMEDIATE(c, file)                \
++    TRACE(c, "PKINIT no intermediate CA in file {str}", file)
++#define TRACE_PKINIT_NO_CERT(c)                 \
++    TRACE(c, "PKINIT no certificate provided")
++#define TRACE_PKINIT_NO_CERT_AND_KEY(c, dirname)                        \
++    TRACE(c, "PKINIT no cert and key pair found in directory {str}",    \
++          dirname)
++#define TRACE_PKINIT_NO_CRL(c, file)                    \
++    TRACE(c, "PKINIT no CRL in file {str}", file)
++#define TRACE_PKINIT_NO_DEFAULT_CERT(c, count)                          \
++    TRACE(c, "PKINIT error: There are {int} certs, but there must "     \
++          "be exactly one.", count)
++#define TRACE_PKINIT_NO_MATCHING_CERT(c)                \
++    TRACE(c, "PKINIT no matching certificate found")
++#define TRACE_PKINIT_NO_PRIVKEY(c)              \
++    TRACE(c, "PKINIT no private key provided")
++#define TRACE_PKINIT_PKCS_DECODE_FAIL(c, name)                          \
++    TRACE(c, "PKINIT failed to decode PKCS12 file {str} contents", name)
++#define TRACE_PKINIT_PKCS_OPEN_FAIL(c, name, err)                       \
++    TRACE(c, "PKINIT failed to open PKCS12 file {str}: err {errno}",    \
++          name, err)
++#define TRACE_PKINIT_PKCS_PARSE_FAIL_FIRST(c)                           \
++    TRACE(c, "PKINIT initial PKCS12_parse with no password failed")
++#define TRACE_PKINIT_PKCS_PARSE_FAIL_SECOND(c)                          \
++    TRACE(c, "PKINIT second PKCS12_parse with password failed")
++#define TRACE_PKINIT_PKCS_PROMPT_FAIL(c)                        \
++    TRACE(c, "PKINIT failed to prompt for PKCS12 password")
++
+ #define TRACE_CERTAUTH_VTINIT_FAIL(c, ret)                              \
+     TRACE(c, "certauth module failed to init vtable: {kerr}", ret)
+ #define TRACE_CERTAUTH_INIT_FAIL(c, name, ret)                          \
diff --git a/SOURCES/Correct-error-handling-bug-in-prior-commit.patch b/SOURCES/Correct-error-handling-bug-in-prior-commit.patch
index e080091..83da7f4 100644
--- a/SOURCES/Correct-error-handling-bug-in-prior-commit.patch
+++ b/SOURCES/Correct-error-handling-bug-in-prior-commit.patch
@@ -1,4 +1,4 @@
-From e9a48c7c89def99b0e60a8b83646a345966c077c Mon Sep 17 00:00:00 2001
+From ca3e61600f1400974c63b2abb30b44f0c94d550b Mon Sep 17 00:00:00 2001
 From: Greg Hudson <ghudson@mit.edu>
 Date: Thu, 23 Mar 2017 13:42:55 -0400
 Subject: [PATCH] Correct error handling bug in prior commit
@@ -9,6 +9,7 @@ possibly-modified alias.
 
 ticket: 8561
 (cherry picked from commit 7fdaef7c3280c86b5df25ae061fb04cc56d8620c)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/SOURCES/Deindent-crypto_retrieve_X509_sans.patch b/SOURCES/Deindent-crypto_retrieve_X509_sans.patch
index 330820d..3864cd3 100644
--- a/SOURCES/Deindent-crypto_retrieve_X509_sans.patch
+++ b/SOURCES/Deindent-crypto_retrieve_X509_sans.patch
@@ -9,6 +9,7 @@ return parameters are always initialized.
 
 (cherry picked from commit c6b772523db9d7791ee1c56eb512c4626556a4e7)
 (cherry picked from commit 23086ac768a32db1e40a9b63684dbcfd76aba033)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 224 +++++++++++----------
  1 file changed, 114 insertions(+), 110 deletions(-)
diff --git a/SOURCES/Expose-context-errors-in-pkinit_server_plugin_init.patch b/SOURCES/Expose-context-errors-in-pkinit_server_plugin_init.patch
new file mode 100644
index 0000000..3144401
--- /dev/null
+++ b/SOURCES/Expose-context-errors-in-pkinit_server_plugin_init.patch
@@ -0,0 +1,74 @@
+From 9c0a06f38189d255575acdae5efb22b76b4c33b3 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Mon, 13 Nov 2017 13:32:37 -0500
+Subject: [PATCH] Expose context errors in pkinit_server_plugin_init
+
+Commit 3ff426b9048a8024e5c175256c63cd0ad0572320 attempted to display
+an error when OCSP support was requested, but this error message was
+suppressed in pkinit_server_plugin_init().  Add a trace log for each
+realm initialization error, and pass through the realm initialization
+error when the KDC serves only one realm.  Other error messages from
+pkinit_init_kdc_profile(), such as missing pkinit_identity or
+pkinit_anchors, are also now exposted.
+
+[ghudson@mit.edu: clarified commit message]
+
+ticket: 8621 (new)
+target_version: 1.16
+tags: pullup
+
+(cherry picked from commit 225aab3540c13c6289b22022d5e110f6fc26151d)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/plugins/preauth/pkinit/pkinit_srv.c   | 19 +++++++++++++------
+ src/plugins/preauth/pkinit/pkinit_trace.h |  3 +++
+ 2 files changed, 16 insertions(+), 6 deletions(-)
+
+diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
+index 8e77606f8..143d331a2 100644
+--- a/src/plugins/preauth/pkinit/pkinit_srv.c
++++ b/src/plugins/preauth/pkinit/pkinit_srv.c
+@@ -1622,16 +1622,23 @@ pkinit_server_plugin_init(krb5_context context,
+ 
+     for (i = 0, j = 0; i < numrealms; i++) {
+         TRACE_PKINIT_SERVER_INIT_REALM(context, realmnames[i]);
+-        retval = pkinit_server_plugin_init_realm(context, realmnames[i], &plgctx);
+-        if (retval == 0 && plgctx != NULL)
++        krb5_clear_error_message(context);
++        retval = pkinit_server_plugin_init_realm(context, realmnames[i],
++                                                 &plgctx);
++        if (retval)
++            TRACE_PKINIT_SERVER_INIT_FAIL(context, realmnames[i], retval);
++        else
+             realm_contexts[j++] = plgctx;
+     }
+ 
+     if (j == 0) {
+-        retval = EINVAL;
+-        krb5_set_error_message(context, retval,
+-                               _("No realms configured correctly for pkinit "
+-                                 "support"));
++        if (numrealms == 1) {
++            k5_prependmsg(context, retval, "PKINIT initialization failed");
++        } else {
++            retval = EINVAL;
++            k5_setmsg(context, retval,
++                      _("No realms configured correctly for pkinit support"));
++        }
+         goto errout;
+     }
+ 
+diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h
+index 6abe28c0c..8d489469f 100644
+--- a/src/plugins/preauth/pkinit/pkinit_trace.h
++++ b/src/plugins/preauth/pkinit/pkinit_trace.h
+@@ -100,6 +100,9 @@
+     TRACE(c, "PKINIT server skipping EKU check due to configuration")
+ #define TRACE_PKINIT_SERVER_INIT_REALM(c, realm)                \
+     TRACE(c, "PKINIT server initializing realm {str}", realm)
++#define TRACE_PKINIT_SERVER_INIT_FAIL(c, realm, retval)                 \
++    TRACE(c, "PKINIT server initialization failed for realm {str}: {kerr}", \
++          realm, retval)
+ #define TRACE_PKINIT_SERVER_MATCHING_UPN_FOUND(c)                       \
+     TRACE(c, "PKINIT server found a matching UPN SAN in client cert")
+ #define TRACE_PKINIT_SERVER_MATCHING_SAN_FOUND(c)                       \
diff --git a/SOURCES/Fix-bugs-in-kdcpolicy-commit.patch b/SOURCES/Fix-bugs-in-kdcpolicy-commit.patch
new file mode 100644
index 0000000..533818c
--- /dev/null
+++ b/SOURCES/Fix-bugs-in-kdcpolicy-commit.patch
@@ -0,0 +1,131 @@
+From d59b00fd1fdcc473739f3033c0f67eb402f20d9c Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Sat, 19 Aug 2017 19:09:24 -0400
+Subject: [PATCH] Fix bugs in kdcpolicy commit
+
+Commit d0969f6a8170344031ef58fd2a161190f1edfb96 added tests using
+"klist ccachname -e", which does not work with a POSIX-conformant
+getopt() implementation such as the one in Solaris.  Fix
+t_kdcpolicy.py to use "klist -e ccachename" instead.
+
+The tests could fail if the clock second rolled over between kinit and
+kvno.  Divide service ticket maximum lifetimes by 2 in the test module
+to correctly exercise TGS policy restrictions and ensure that service
+tickets are not constrained by the TGT end time.
+
+Also use the correct trace macro when a kdcpolicy module declines to
+initialize (my mistake when revising the commit, noted by rharwood).
+
+ticket: 8606
+(cherry picked from commit 09acbd91efc6df54e1572285ffc94c6acb3a9113)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/kdc/policy.c                  |  2 +-
+ src/plugins/kdcpolicy/test/main.c | 10 +++++-----
+ src/tests/t_kdcpolicy.py          | 13 +++++++++----
+ 3 files changed, 15 insertions(+), 10 deletions(-)
+
+diff --git a/src/kdc/policy.c b/src/kdc/policy.c
+index e49644e06..26c16f97c 100644
+--- a/src/kdc/policy.c
++++ b/src/kdc/policy.c
+@@ -222,7 +222,7 @@ load_kdcpolicy_plugins(krb5_context context)
+         if (h->vt.init != NULL) {
+             ret = h->vt.init(context, &h->moddata);
+             if (ret == KRB5_PLUGIN_NO_HANDLE) {
+-                TRACE_KADM5_AUTH_INIT_SKIP(context, h->vt.name);
++                TRACE_KDCPOLICY_INIT_SKIP(context, h->vt.name);
+                 free(h);
+                 continue;
+             }
+diff --git a/src/plugins/kdcpolicy/test/main.c b/src/plugins/kdcpolicy/test/main.c
+index eb8fde053..86c808958 100644
+--- a/src/plugins/kdcpolicy/test/main.c
++++ b/src/plugins/kdcpolicy/test/main.c
+@@ -35,7 +35,7 @@
+ #include <krb5/kdcpolicy_plugin.h>
+ 
+ static krb5_error_code
+-output_from_indicator(const char *const *auth_indicators,
++output_from_indicator(const char *const *auth_indicators, int divisor,
+                       krb5_deltat *lifetime_out,
+                       krb5_deltat *renew_lifetime_out,
+                       const char **status)
+@@ -46,11 +46,11 @@ output_from_indicator(const char *const *auth_indicators,
+     }
+ 
+     if (strcmp(auth_indicators[0], "ONE_HOUR") == 0) {
+-        *lifetime_out = 3600;
++        *lifetime_out = 3600 / divisor;
+         *renew_lifetime_out = *lifetime_out * 2;
+         return 0;
+     } else if (strcmp(auth_indicators[0], "SEVEN_HOURS") == 0) {
+-        *lifetime_out = 7 * 3600;
++        *lifetime_out = 7 * 3600 / divisor;
+         *renew_lifetime_out = *lifetime_out * 2;
+         return 0;
+     }
+@@ -71,7 +71,7 @@ test_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
+         *status = "LOCAL_POLICY";
+         return KRB5KDC_ERR_POLICY;
+     }
+-    return output_from_indicator(auth_indicators, lifetime_out,
++    return output_from_indicator(auth_indicators, 1, lifetime_out,
+                                  renew_lifetime_out, status);
+ }
+ 
+@@ -87,7 +87,7 @@ test_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
+         *status = "LOCAL_POLICY";
+         return KRB5KDC_ERR_POLICY;
+     }
+-    return output_from_indicator(auth_indicators, lifetime_out,
++    return output_from_indicator(auth_indicators, 2, lifetime_out,
+                                  renew_lifetime_out, status);
+ }
+ 
+diff --git a/src/tests/t_kdcpolicy.py b/src/tests/t_kdcpolicy.py
+index 6a745b959..b5d308461 100644
+--- a/src/tests/t_kdcpolicy.py
++++ b/src/tests/t_kdcpolicy.py
+@@ -18,16 +18,21 @@ realm.run([kadminl, 'addprinc', '-pw', password('fail'), 'fail'])
+ def verify_time(out, target_time):
+     times = re.findall(r'\d\d/\d\d/\d\d \d\d:\d\d:\d\d', out)
+     times = [datetime.strptime(t, '%m/%d/%y %H:%M:%S') for t in times]
++    divisor = 1
+     while len(times) > 0:
+         starttime = times.pop(0)
+         endtime = times.pop(0)
+         renewtime = times.pop(0)
+ 
+-        if str(endtime - starttime) != target_time:
++        if str((endtime - starttime) * divisor) != target_time:
+             fail('unexpected lifetime value')
+-        if str(renewtime - endtime) != target_time:
++        if str((renewtime - endtime) * divisor) != target_time:
+             fail('unexpected renewable value')
+ 
++        # Service tickets should have half the lifetime of initial
++        # tickets.
++        divisor = 2
++
+ rflags = ['-r', '1d', '-l', '12h']
+ 
+ # Test AS+TGS success path.
+@@ -35,7 +40,7 @@ realm.kinit(realm.user_princ, password('user'),
+             rflags + ['-X', 'indicators=SEVEN_HOURS'])
+ realm.run([kvno, realm.host_princ])
+ realm.run(['./adata', realm.host_princ], expected_msg='+97: [SEVEN_HOURS]')
+-out = realm.run([klist, realm.ccache, '-e'])
++out = realm.run([klist, '-e', realm.ccache])
+ verify_time(out, '7:00:00')
+ 
+ # Test AS+TGS success path with different values.
+@@ -43,7 +48,7 @@ realm.kinit(realm.user_princ, password('user'),
+             rflags + ['-X', 'indicators=ONE_HOUR'])
+ realm.run([kvno, realm.host_princ])
+ realm.run(['./adata', realm.host_princ], expected_msg='+97: [ONE_HOUR]')
+-out = realm.run([klist, realm.ccache, '-e'])
++out = realm.run([klist, '-e', realm.ccache])
+ verify_time(out, '1:00:00')
+ 
+ # Test TGS failure path (using previous creds).
diff --git a/SOURCES/Fix-certauth-built-in-module-returns.patch b/SOURCES/Fix-certauth-built-in-module-returns.patch
new file mode 100644
index 0000000..f512f49
--- /dev/null
+++ b/SOURCES/Fix-certauth-built-in-module-returns.patch
@@ -0,0 +1,125 @@
+From 41b9111b48e53bf7864ed1f134e0433b070fa900 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Thu, 24 Aug 2017 11:11:46 -0400
+Subject: [PATCH] Fix certauth built-in module returns
+
+The PKINIT certauth eku module should never authoritatively authorize
+a certificate, because an extended key usage does not establish a
+relationship between the certificate and any specific user; it only
+establishes that the certificate was created for PKINIT client
+authentication.  Therefore, pkinit_eku_authorize() should return
+KRB5_PLUGIN_NO_HANDLE on success, not 0.
+
+The certauth san module should pass if it does not find any SANs of
+the types it can match against; the presence of other types of SANs
+should not cause it to explicitly deny a certificate.  Check for an
+empty result from crypto_retrieve_cert_sans() in verify_client_san(),
+instead of returning ENOENT from crypto_retrieve_cert_sans() when
+there are no SANs at all.
+
+ticket: 8561
+(cherry picked from commit 07243f85a760fb37f0622d7ff0177db3f19ab025)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 39 ++++++++++------------
+ src/plugins/preauth/pkinit/pkinit_srv.c            | 14 +++++---
+ 2 files changed, 27 insertions(+), 26 deletions(-)
+
+diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+index 70e230ec2..7fa2efd21 100644
+--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+@@ -2137,7 +2137,6 @@ crypto_retrieve_X509_sans(krb5_context context,
+ 
+     if (!(ext = X509_get_ext(cert, l)) || !(ialt = X509V3_EXT_d2i(ext))) {
+         pkiDebug("%s: found no subject alt name extensions\n", __FUNCTION__);
+-        retval = ENOENT;
+         goto cleanup;
+     }
+     num_sans = sk_GENERAL_NAME_num(ialt);
+@@ -2240,31 +2239,29 @@ crypto_retrieve_X509_sans(krb5_context context,
+     sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free);
+ 
+     retval = 0;
+-    if (princs)
++    if (princs != NULL && *princs != NULL) {
+         *princs_ret = princs;
+-    if (upns)
++        princs = NULL;
++    }
++    if (upns != NULL && *upns != NULL) {
+         *upn_ret = upns;
+-    if (dnss)
++        upns = NULL;
++    }
++    if (dnss != NULL && *dnss != NULL) {
+         *dns_ret = dnss;
++        dnss = NULL;
++    }
+ 
+ cleanup:
+-    if (retval) {
+-        if (princs != NULL) {
+-            for (i = 0; princs[i] != NULL; i++)
+-                krb5_free_principal(context, princs[i]);
+-            free(princs);
+-        }
+-        if (upns != NULL) {
+-            for (i = 0; upns[i] != NULL; i++)
+-                krb5_free_principal(context, upns[i]);
+-            free(upns);
+-        }
+-        if (dnss != NULL) {
+-            for (i = 0; dnss[i] != NULL; i++)
+-                free(dnss[i]);
+-            free(dnss);
+-        }
+-    }
++    for (i = 0; princs != NULL && princs[i] != NULL; i++)
++        krb5_free_principal(context, princs[i]);
++    free(princs);
++    for (i = 0; upns != NULL && upns[i] != NULL; i++)
++        krb5_free_principal(context, upns[i]);
++    free(upns);
++    for (i = 0; dnss != NULL && dnss[i] != NULL; i++)
++        free(dnss[i]);
++    free(dnss);
+     return retval;
+ }
+ 
+diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
+index 9c6e96c9e..8e77606f8 100644
+--- a/src/plugins/preauth/pkinit/pkinit_srv.c
++++ b/src/plugins/preauth/pkinit/pkinit_srv.c
+@@ -187,14 +187,18 @@ verify_client_san(krb5_context context,
+                                        &princs,
+                                        plgctx->opts->allow_upn ? &upns : NULL,
+                                        NULL);
+-    if (retval == ENOENT) {
+-        TRACE_PKINIT_SERVER_NO_SAN(context);
+-        goto out;
+-    } else if (retval) {
++    if (retval) {
+         pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__);
+         retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
+         goto out;
+     }
++
++    if (princs == NULL && upns == NULL) {
++        TRACE_PKINIT_SERVER_NO_SAN(context);
++        retval = ENOENT;
++        goto out;
++    }
++
+     /* XXX Verify this is consistent with client side XXX */
+ #if 0
+     retval = call_san_checking_plugins(context, plgctx, reqctx, princs,
+@@ -1495,7 +1499,7 @@ pkinit_eku_authorize(krb5_context context, krb5_certauth_moddata moddata,
+         return KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
+     }
+ 
+-    return 0;
++    return KRB5_PLUGIN_NO_HANDLE;
+ }
+ 
+ static krb5_error_code
diff --git a/SOURCES/Fix-in_clock_skew-and-use-it-in-AS-client-code.patch b/SOURCES/Fix-in_clock_skew-and-use-it-in-AS-client-code.patch
new file mode 100644
index 0000000..fb84846
--- /dev/null
+++ b/SOURCES/Fix-in_clock_skew-and-use-it-in-AS-client-code.patch
@@ -0,0 +1,59 @@
+From 7e914206a676fb8f972c8021e97fab86a155488b Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Mon, 24 Apr 2017 02:02:36 -0400
+Subject: [PATCH] Fix in_clock_skew() and use it in AS client code
+
+Add a context parameter to the in_clock_skew() macro so that it isn't
+implicitly relying on a local variable.  Use it in
+get_in_tkt.c:verify_as_reply().
+
+(cherry picked from commit 28a07a6461bb443b7fa75cc5cb859ad0db4cbb5a)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/lib/krb5/krb/gc_via_tkt.c | 2 +-
+ src/lib/krb5/krb/get_in_tkt.c | 4 ++--
+ src/lib/krb5/krb/int-proto.h  | 3 ++-
+ 3 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c
+index 4c0a1a461..c85d8b8d8 100644
+--- a/src/lib/krb5/krb/gc_via_tkt.c
++++ b/src/lib/krb5/krb/gc_via_tkt.c
+@@ -305,7 +305,7 @@ krb5int_process_tgs_reply(krb5_context context,
+         goto cleanup;
+ 
+     if (!in_cred->times.starttime &&
+-        !in_clock_skew(dec_rep->enc_part2->times.starttime,
++        !in_clock_skew(context, dec_rep->enc_part2->times.starttime,
+                        timestamp)) {
+         retval = KRB5_KDCREP_SKEW;
+         goto cleanup;
+diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
+index 54badbbc3..a058f5bd7 100644
+--- a/src/lib/krb5/krb/get_in_tkt.c
++++ b/src/lib/krb5/krb/get_in_tkt.c
+@@ -287,8 +287,8 @@ verify_as_reply(krb5_context            context,
+             return retval;
+     } else {
+         if ((request->from == 0) &&
+-            (labs(as_reply->enc_part2->times.starttime - time_now)
+-             > context->clockskew))
++            !in_clock_skew(context, as_reply->enc_part2->times.starttime,
++                           time_now))
+             return (KRB5_KDCREP_SKEW);
+     }
+     return 0;
+diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h
+index 6da74858e..44eca359f 100644
+--- a/src/lib/krb5/krb/int-proto.h
++++ b/src/lib/krb5/krb/int-proto.h
+@@ -83,7 +83,8 @@ krb5int_construct_matching_creds(krb5_context context, krb5_flags options,
+                                  krb5_creds *in_creds, krb5_creds *mcreds,
+                                  krb5_flags *fields);
+ 
+-#define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew)
++#define in_clock_skew(context, date, now)               \
++    (labs((date) - (now)) < (context)->clockskew)
+ 
+ #define IS_TGS_PRINC(p) ((p)->length == 2 &&                            \
+                          data_eq_string((p)->data[0], KRB5_TGS_NAME))
diff --git a/SOURCES/Fix-make-certs.sh-for-OpenSSL-1.1.patch b/SOURCES/Fix-make-certs.sh-for-OpenSSL-1.1.patch
new file mode 100644
index 0000000..f02f9c5
--- /dev/null
+++ b/SOURCES/Fix-make-certs.sh-for-OpenSSL-1.1.patch
@@ -0,0 +1,71 @@
+From 7221a9f695016d3e4873bb799f06665ec74387f8 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Wed, 6 Sep 2017 12:56:37 -0400
+Subject: [PATCH] Fix make-certs.sh for OpenSSL 1.1
+
+The openssl req commands in make-certs.sh contain -subj options which
+were ignored in favor of the config file prior to OpenSSL 1.1.  When
+they are used, they remove elements of the subject which are now
+required by t_pkinit.py.
+
+(cherry picked from commit b0473da67d72e43b9f03b703869069348e872efc)
+[rharwood@redhat.com: remove newer sections in make-certs.sh]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/tests/dejagnu/pkinit-certs/make-certs.sh | 19 +++++++++----------
+ 1 file changed, 9 insertions(+), 10 deletions(-)
+
+diff --git a/src/tests/dejagnu/pkinit-certs/make-certs.sh b/src/tests/dejagnu/pkinit-certs/make-certs.sh
+index 0f07709b0..0d8c2019a 100755
+--- a/src/tests/dejagnu/pkinit-certs/make-certs.sh
++++ b/src/tests/dejagnu/pkinit-certs/make-certs.sh
+@@ -122,15 +122,14 @@ SUBJECT=ca openssl req -config openssl.cnf -new -x509 -extensions exts_ca \
+     -set_serial 1 -days $DAYS -key privkey.pem -out ca.pem
+ 
+ # Generate a KDC certificate.
+-SUBJECT=kdc openssl req -config openssl.cnf -new -subj /CN=kdc \
+-    -key privkey.pem -out kdc.csr
++SUBJECT=kdc openssl req -config openssl.cnf -new -key privkey.pem -out kdc.csr
+ SUBJECT=kdc openssl x509 -extfile openssl.cnf -extensions exts_kdc \
+     -set_serial 2 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
+     -out kdc.pem -in kdc.csr
+ 
+ # Generate a client certificate and PKCS#12 bundles.
+-SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \
+-    -key privkey.pem -out user.csr
++SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \
++    -out user.csr
+ SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_client \
+     -set_serial 3 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
+     -out user.pem -in user.csr
+@@ -140,24 +139,24 @@ openssl pkcs12 -export -in user.pem -inkey privkey.pem -out user-enc.p12 \
+     -passout pass:encrypted
+ 
+ # Generate a client certificate and PKCS#12 bundles with a UPN SAN.
+-SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \
+-    -key privkey.pem -out user-upn.csr
++SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \
++    -out user-upn.csr
+ SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn_client \
+     -set_serial 4 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
+     -out user-upn.pem -in user-upn.csr
+ openssl pkcs12 -export -in user-upn.pem -inkey privkey.pem -out user-upn.p12 \
+     -passout pass:
+ 
+-SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \
+-    -key privkey.pem -out user-upn2.csr
++SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \
++    -out user-upn2.csr
+ SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn2_client \
+     -set_serial 5 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
+     -out user-upn2.pem -in user-upn2.csr
+ openssl pkcs12 -export -in user-upn2.pem -inkey privkey.pem \
+      -out user-upn2.p12 -passout pass:
+ 
+-SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \
+-    -key privkey.pem -out user-upn3.csr
++SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \
++    -out user-upn3.csr
+ SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn3_client \
+     -set_serial 6 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
+     -out user-upn3.pem -in user-upn3.csr
diff --git a/SOURCES/Fix-more-time-manipulations-for-y2038.patch b/SOURCES/Fix-more-time-manipulations-for-y2038.patch
new file mode 100644
index 0000000..44252dc
--- /dev/null
+++ b/SOURCES/Fix-more-time-manipulations-for-y2038.patch
@@ -0,0 +1,84 @@
+From 006c68f6ed266d5ea7a24512349a931f45160cc6 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Wed, 17 May 2017 14:52:09 -0400
+Subject: [PATCH] Fix more time manipulations for y2038
+
+Use timestamp helper functions to ensure that more operations are safe
+after y2038, and display the current timestamp as unsigned in
+krb5int_trace().
+
+ticket: 8352
+(cherry picked from commit a60db180211a383bd382afe729e9309acb8dcf53)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/kadmin/server/misc.c   | 2 +-
+ src/kdc/dispatch.c         | 2 +-
+ src/lib/krb5/os/c_ustime.c | 8 ++++----
+ src/lib/krb5/os/trace.c    | 2 +-
+ 4 files changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/src/kadmin/server/misc.c b/src/kadmin/server/misc.c
+index 27a6376af..a75b65a26 100644
+--- a/src/kadmin/server/misc.c
++++ b/src/kadmin/server/misc.c
+@@ -184,7 +184,7 @@ check_min_life(void *server_handle, krb5_principal principal,
+             (void) kadm5_free_principal_ent(handle->lhandle, &princ);
+             return (ret == KADM5_UNK_POLICY) ? 0 : ret;
+         }
+-        if((now - princ.last_pwd_change) < pol.pw_min_life &&
++        if(ts_delta(now, princ.last_pwd_change) < pol.pw_min_life &&
+            !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
+             if (msg_ret != NULL) {
+                 time_t until;
+diff --git a/src/kdc/dispatch.c b/src/kdc/dispatch.c
+index 3a169ebc7..16a35d2be 100644
+--- a/src/kdc/dispatch.c
++++ b/src/kdc/dispatch.c
+@@ -104,7 +104,7 @@ reseed_random(krb5_context kdc_err_context)
+         if (last_os_random == 0)
+             last_os_random = now;
+         /* Grab random data from OS every hour*/
+-        if (now-last_os_random >= 60 * 60) {
++        if (ts_delta(now, last_os_random) >= 60 * 60) {
+             krb5_c_random_os_entropy(kdc_err_context, 0, NULL);
+             last_os_random = now;
+         }
+diff --git a/src/lib/krb5/os/c_ustime.c b/src/lib/krb5/os/c_ustime.c
+index 871d72183..68fb381f4 100644
+--- a/src/lib/krb5/os/c_ustime.c
++++ b/src/lib/krb5/os/c_ustime.c
+@@ -102,17 +102,17 @@ krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds)
+        putting now.sec in the past.  But don't just use '<' because we
+        need to properly handle the case where the administrator intentionally
+        adjusted time backwards. */
+-    if ((now.sec == last_time.sec-1) ||
+-        ((now.sec == last_time.sec) && (now.usec <= last_time.usec))) {
++    if (now.sec == ts_incr(last_time.sec, -1) ||
++        (now.sec == last_time.sec && !ts_after(last_time.usec, now.usec))) {
+         /* Correct 'now' to be exactly one microsecond later than 'last_time'.
+            Note that _because_ we perform this hack, 'now' may be _earlier_
+            than 'last_time', even though the system time is monotonically
+            increasing. */
+ 
+         now.sec = last_time.sec;
+-        now.usec = ++last_time.usec;
++        now.usec = ts_incr(last_time.usec, 1);
+         if (now.usec >= 1000000) {
+-            ++now.sec;
++            now.sec = ts_incr(now.sec, 1);
+             now.usec = 0;
+         }
+     }
+diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
+index a19246128..74c315c90 100644
+--- a/src/lib/krb5/os/trace.c
++++ b/src/lib/krb5/os/trace.c
+@@ -350,7 +350,7 @@ krb5int_trace(krb5_context context, const char *fmt, ...)
+         goto cleanup;
+     if (krb5_crypto_us_timeofday(&sec, &usec) != 0)
+         goto cleanup;
+-    if (asprintf(&msg, "[%d] %d.%d: %s\n", (int) getpid(), (int) sec,
++    if (asprintf(&msg, "[%d] %u.%d: %s\n", (int) getpid(), (unsigned int) sec,
+                  (int) usec, str) < 0)
+         goto cleanup;
+     info.message = msg;
diff --git a/SOURCES/Improve-PKINIT-UPN-SAN-matching.patch b/SOURCES/Improve-PKINIT-UPN-SAN-matching.patch
index d4d45c6..aaf15b6 100644
--- a/SOURCES/Improve-PKINIT-UPN-SAN-matching.patch
+++ b/SOURCES/Improve-PKINIT-UPN-SAN-matching.patch
@@ -14,6 +14,7 @@ parse UPN values as enterprise principals.
 
 ticket: 8528 (new)
 (cherry picked from commit 46ff765e1fb8cbec2bb602b43311269e695dbedc)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/include/krb5/kdcpreauth_plugin.h               | 13 ++++++++++
  src/kdc/kdc_preauth.c                              | 28 ++++++++++++++++++++--
diff --git a/SOURCES/Make-timestamp-manipulations-y2038-safe.patch b/SOURCES/Make-timestamp-manipulations-y2038-safe.patch
new file mode 100644
index 0000000..8ae5272
--- /dev/null
+++ b/SOURCES/Make-timestamp-manipulations-y2038-safe.patch
@@ -0,0 +1,1845 @@
+From 7c671a869d1fc21b5154c035d568d5b5fd940783 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Sat, 22 Apr 2017 12:52:17 -0400
+Subject: [PATCH] Make timestamp manipulations y2038-safe
+
+Wherever we manipulate krb5_timestamp values using arithmetic,
+comparison operations, or conversion to time_t, use the new helper
+functions in k5-int.h to ensure that the operations work after y2038
+and do not exhibit undefined behavior.  (Relying on
+implementation-defined conversion to signed values is okay as we test
+that in configure.in.)
+
+In printf format strings, use %u instead of signed types.  When
+exporting creds with k5_json_array_fmt(), use a long long so that
+timestamps after y2038 aren't marshalled as negative numbers.  When
+parsing timestamps in test programs, use atoll() instead of atol() so
+that positive timestamps after y2038 can be used as input.
+
+In ksu and klist, make printtime() take a krb5_timestamp parameter to
+avoid an unnecessary conversion to time_t and back.
+
+As Leash does not use k5-int.h, use time_t values internally and
+safely convert from libkrb5 timestamp values.
+
+ticket: 8352
+(cherry picked from commit a9cbbf0899f270fbb14f63ffbed1b6d542333641)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/clients/kinit/kinit.c                          |  2 +-
+ src/clients/klist/klist.c                          | 20 ++++-------
+ src/clients/ksu/ccache.c                           | 20 +++--------
+ src/clients/ksu/ksu.h                              |  2 +-
+ src/kadmin/cli/getdate.y                           |  2 +-
+ src/kadmin/cli/kadmin.c                            |  5 ++-
+ src/kadmin/dbutil/dump.c                           | 27 ++++++++-------
+ src/kadmin/dbutil/kdb5_mkey.c                      |  6 ++--
+ src/kadmin/dbutil/tabdump.c                        |  2 +-
+ src/kadmin/testing/util/tcl_kadm5.c                | 12 +++----
+ src/kdc/do_as_req.c                                |  2 +-
+ src/kdc/do_tgs_req.c                               |  6 ++--
+ src/kdc/extern.c                                   |  4 ++-
+ src/kdc/fast_util.c                                |  4 +--
+ src/kdc/kdc_log.c                                  | 14 ++++----
+ src/kdc/kdc_util.c                                 | 20 +++++------
+ src/kdc/kdc_util.h                                 |  2 ++
+ src/kdc/replay.c                                   |  2 +-
+ src/kdc/tgs_policy.c                               |  7 ++--
+ src/lib/gssapi/krb5/accept_sec_context.c           |  8 +++--
+ src/lib/gssapi/krb5/acquire_cred.c                 | 13 ++++---
+ src/lib/gssapi/krb5/context_time.c                 |  2 +-
+ src/lib/gssapi/krb5/export_cred.c                  |  5 +--
+ src/lib/gssapi/krb5/iakerb.c                       |  4 +--
+ src/lib/gssapi/krb5/init_sec_context.c             |  9 ++---
+ src/lib/gssapi/krb5/inq_context.c                  |  2 +-
+ src/lib/gssapi/krb5/inq_cred.c                     |  5 +--
+ src/lib/gssapi/krb5/s4u_gss_glue.c                 |  2 +-
+ src/lib/kadm5/chpass_util.c                        |  8 ++---
+ src/lib/kadm5/srv/server_acl.c                     |  5 +--
+ src/lib/kadm5/srv/svr_principal.c                  | 12 +++----
+ src/lib/kdb/kdb5.c                                 |  2 +-
+ src/lib/krb5/asn.1/asn1_k_encode.c                 |  3 +-
+ src/lib/krb5/ccache/cc_keyring.c                   | 14 ++++----
+ src/lib/krb5/ccache/cc_memory.c                    |  4 +--
+ src/lib/krb5/ccache/cc_retr.c                      |  4 +--
+ src/lib/krb5/ccache/ccapi/stdcc_util.c             | 40 +++++++++++-----------
+ src/lib/krb5/ccache/cccursor.c                     |  2 +-
+ src/lib/krb5/keytab/kt_file.c                      |  6 ++--
+ src/lib/krb5/krb/gc_via_tkt.c                      |  7 ++--
+ src/lib/krb5/krb/get_creds.c                       |  2 +-
+ src/lib/krb5/krb/get_in_tkt.c                      | 38 ++++++--------------
+ src/lib/krb5/krb/gic_pwd.c                         |  4 +--
+ src/lib/krb5/krb/int-proto.h                       |  2 +-
+ src/lib/krb5/krb/pac.c                             |  2 +-
+ src/lib/krb5/krb/str_conv.c                        |  4 +--
+ src/lib/krb5/krb/t_kerb.c                          | 12 ++-----
+ src/lib/krb5/krb/valid_times.c                     |  4 +--
+ src/lib/krb5/krb/vfy_increds.c                     |  2 +-
+ src/lib/krb5/os/timeofday.c                        |  2 +-
+ src/lib/krb5/os/toffset.c                          |  2 +-
+ src/lib/krb5/os/ustime.c                           |  6 ++--
+ src/lib/krb5/rcache/rc_dfl.c                       |  3 +-
+ src/lib/krb5/rcache/t_replay.c                     |  8 ++---
+ src/plugins/kdb/db2/lockout.c                      |  8 ++---
+ src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c |  2 +-
+ src/plugins/kdb/ldap/libkdb_ldap/lockout.c         |  8 ++---
+ src/windows/cns/tktlist.c                          | 10 +++---
+ src/windows/include/leashwin.h                     | 12 +++----
+ src/windows/leash/KrbListTickets.cpp               | 12 +++----
+ src/windows/leash/LeashView.cpp                    | 22 ++++++------
+ src/windows/leashdll/lshfunc.c                     |  2 +-
+ src/windows/ms2mit/ms2mit.c                        |  2 +-
+ 63 files changed, 230 insertions(+), 255 deletions(-)
+
+diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
+index f1cd1b73d..50065e32e 100644
+--- a/src/clients/kinit/kinit.c
++++ b/src/clients/kinit/kinit.c
+@@ -318,7 +318,7 @@ parse_options(argc, argv, opts)
+                     fprintf(stderr, _("Bad start time value %s\n"), optarg);
+                     errflg++;
+                 } else {
+-                    opts->starttime = abs_starttime - time(0);
++                    opts->starttime = ts_delta(abs_starttime, time(NULL));
+                 }
+             }
+             break;
+diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c
+index ba19788a2..ffeecc394 100644
+--- a/src/clients/klist/klist.c
++++ b/src/clients/klist/klist.c
+@@ -72,7 +72,7 @@ void do_ccache_name (char *);
+ int show_ccache (krb5_ccache);
+ int check_ccache (krb5_ccache);
+ void do_keytab (char *);
+-void printtime (time_t);
++void printtime (krb5_timestamp);
+ void one_addr (krb5_address *);
+ void fillit (FILE *, unsigned int, int);
+ 
+@@ -538,10 +538,10 @@ check_ccache(krb5_ccache cache)
+     while (!(ret = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
+         if (is_local_tgt(creds.server, &princ->realm)) {
+             found_tgt = TRUE;
+-            if (creds.times.endtime > now)
++            if (ts_after(creds.times.endtime, now))
+                 found_current_tgt = TRUE;
+         } else if (!krb5_is_config_principal(kcontext, creds.server) &&
+-                   creds.times.endtime > now) {
++                   ts_after(creds.times.endtime, now)) {
+             found_current_cred = TRUE;
+         }
+         krb5_free_cred_contents(kcontext, &creds);
+@@ -623,19 +623,13 @@ flags_string(cred)
+ }
+ 
+ void
+-printtime(tv)
+-    time_t tv;
++printtime(krb5_timestamp ts)
+ {
+-    char timestring[BUFSIZ];
+-    char fill;
++    char timestring[BUFSIZ], fill = ' ';
+ 
+-    fill = ' ';
+-    if (!krb5_timestamp_to_sfstring((krb5_timestamp) tv,
+-                                    timestring,
+-                                    timestamp_width+1,
+-                                    &fill)) {
++    if (!krb5_timestamp_to_sfstring(ts, timestring, timestamp_width + 1,
++                                    &fill))
+         printf("%s", timestring);
+-    }
+ }
+ 
+ static void
+diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c
+index a0736f2da..236313b7b 100644
+--- a/src/clients/ksu/ccache.c
++++ b/src/clients/ksu/ccache.c
+@@ -278,11 +278,11 @@ krb5_error_code krb5_check_exp(context, tkt_time)
+                 context->clockskew);
+ 
+         fprintf(stderr,"krb5_check_exp: currenttime - endtime %d \n",
+-                (currenttime - tkt_time.endtime ));
++                ts_delta(currenttime, tkt_time.endtime));
+ 
+     }
+ 
+-    if (currenttime - tkt_time.endtime > context->clockskew){
++    if (ts_delta(currenttime, tkt_time.endtime) > context->clockskew) {
+         retval = KRB5KRB_AP_ERR_TKT_EXPIRED ;
+         return retval;
+     }
+@@ -323,21 +323,11 @@ char *flags_string(cred)
+     return(buf);
+ }
+ 
+-void printtime(tv)
+-    time_t tv;
++void printtime(krb5_timestamp ts)
+ {
+-    char fmtbuf[18];
+-    char fill;
+-    krb5_timestamp tstamp;
++    char fmtbuf[18], fill = ' ';
+ 
+-    /* XXXX ASSUMES sizeof(krb5_timestamp) >= sizeof(time_t) */
+-    (void) localtime((time_t *)&tv);
+-    tstamp = tv;
+-    fill = ' ';
+-    if (!krb5_timestamp_to_sfstring(tstamp,
+-                                    fmtbuf,
+-                                    sizeof(fmtbuf),
+-                                    &fill))
++    if (!krb5_timestamp_to_sfstring(ts, fmtbuf, sizeof(fmtbuf), &fill))
+         printf("%s", fmtbuf);
+ }
+ 
+diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h
+index ee8e9d6a0..3bf0bd438 100644
+--- a/src/clients/ksu/ksu.h
++++ b/src/clients/ksu/ksu.h
+@@ -150,7 +150,7 @@ extern krb5_boolean krb5_find_princ_in_cred_list
+ extern krb5_error_code krb5_find_princ_in_cache
+ (krb5_context, krb5_ccache, krb5_principal, krb5_boolean *);
+ 
+-extern void printtime (time_t);
++extern void printtime (krb5_timestamp);
+ 
+ /* authorization.c */
+ extern krb5_boolean fowner (FILE *, uid_t);
+diff --git a/src/kadmin/cli/getdate.y b/src/kadmin/cli/getdate.y
+index 4f0c56f7e..0a19c5648 100644
+--- a/src/kadmin/cli/getdate.y
++++ b/src/kadmin/cli/getdate.y
+@@ -118,7 +118,7 @@ static int getdate_yyerror (char *);
+ 
+ 
+ #define EPOCH		1970
+-#define EPOCH_END	2038 /* assumes 32 bits */
++#define EPOCH_END	2106 /* assumes unsigned 32-bit range */
+ #define HOUR(x)		((time_t)(x) * 60)
+ #define SECSPERDAY	(24L * 60L * 60L)
+ 
+diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c
+index c53c677a8..aee5c83b9 100644
+--- a/src/kadmin/cli/kadmin.c
++++ b/src/kadmin/cli/kadmin.c
+@@ -31,8 +31,7 @@
+  * library */
+ 
+ /* for "_" macro */
+-#include "k5-platform.h"
+-#include <krb5.h>
++#include "k5-int.h"
+ #include <kadm5/admin.h>
+ #include <adm_proto.h>
+ #include <errno.h>
+@@ -144,8 +143,8 @@ strdate(krb5_timestamp when)
+ {
+     struct tm *tm;
+     static char out[40];
++    time_t lcltim = ts2tt(when);
+ 
+-    time_t lcltim = when;
+     tm = localtime(&lcltim);
+     strftime(out, sizeof(out), "%a %b %d %H:%M:%S %Z %Y", tm);
+     return out;
+diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
+index cad53cfbf..a6fc4ea77 100644
+--- a/src/kadmin/dbutil/dump.c
++++ b/src/kadmin/dbutil/dump.c
+@@ -379,11 +379,12 @@ k5beta7_common(krb5_context context, krb5_db_entry *entry,
+     fprintf(fp, "princ\t%d\t%lu\t%d\t%d\t%d\t%s\t", (int)entry->len,
+             (unsigned long)strlen(name), counter, (int)entry->n_key_data,
+             (int)entry->e_length, name);
+-    fprintf(fp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d", entry->attributes,
+-            entry->max_life, entry->max_renewable_life, entry->expiration,
+-            entry->pw_expiration,
+-            omit_nra ? 0 : entry->last_success,
+-            omit_nra ? 0 : entry->last_failed,
++    fprintf(fp, "%d\t%d\t%d\t%u\t%u\t%u\t%u\t%d", entry->attributes,
++            entry->max_life, entry->max_renewable_life,
++            (unsigned int)entry->expiration,
++            (unsigned int)entry->pw_expiration,
++            (unsigned int)(omit_nra ? 0 : entry->last_success),
++            (unsigned int)(omit_nra ? 0 : entry->last_failed),
+             omit_nra ? 0 : entry->fail_auth_count);
+ 
+     /* Write out tagged data. */
+@@ -717,7 +718,7 @@ process_k5beta7_princ(krb5_context context, const char *fname, FILE *filep,
+ {
+     int retval, nread, i, j;
+     krb5_db_entry *dbentry;
+-    int t1, t2, t3, t4, t5, t6, t7;
++    int t1, t2, t3, t4;
+     unsigned int u1, u2, u3, u4, u5;
+     char *name = NULL;
+     krb5_key_data *kp = NULL, *kd;
+@@ -773,8 +774,8 @@ process_k5beta7_princ(krb5_context context, const char *fname, FILE *filep,
+     }
+ 
+     /* Get the fixed principal attributes */
+-    nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
+-                   &t1, &t2, &t3, &t4, &t5, &t6, &t7, &u1);
++    nread = fscanf(filep, "%d\t%d\t%d\t%u\t%u\t%d\t%d\t%d\t",
++                   &t1, &t2, &t3, &u1, &u2, &u3, &u4, &u5);
+     if (nread != 8) {
+         load_err(fname, *linenop, _("cannot read principal attributes"));
+         goto fail;
+@@ -782,11 +783,11 @@ process_k5beta7_princ(krb5_context context, const char *fname, FILE *filep,
+     dbentry->attributes = t1;
+     dbentry->max_life = t2;
+     dbentry->max_renewable_life = t3;
+-    dbentry->expiration = t4;
+-    dbentry->pw_expiration = t5;
+-    dbentry->last_success = t6;
+-    dbentry->last_failed = t7;
+-    dbentry->fail_auth_count = u1;
++    dbentry->expiration = u1;
++    dbentry->pw_expiration = u2;
++    dbentry->last_success = u3;
++    dbentry->last_failed = u4;
++    dbentry->fail_auth_count = u5;
+     dbentry->mask = KADM5_LOAD | KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
+         KADM5_MAX_LIFE | KADM5_MAX_RLIFE |
+         KADM5_PRINC_EXPIRE_TIME | KADM5_LAST_SUCCESS |
+diff --git a/src/kadmin/dbutil/kdb5_mkey.c b/src/kadmin/dbutil/kdb5_mkey.c
+index 7df8cbc83..2efe3176e 100644
+--- a/src/kadmin/dbutil/kdb5_mkey.c
++++ b/src/kadmin/dbutil/kdb5_mkey.c
+@@ -44,8 +44,8 @@ static char *strdate(krb5_timestamp when)
+ {
+     struct tm *tm;
+     static char out[40];
++    time_t lcltim = ts2tt(when);
+ 
+-    time_t lcltim = when;
+     tm = localtime(&lcltim);
+     strftime(out, sizeof(out), "%a %b %d %H:%M:%S %Z %Y", tm);
+     return out;
+@@ -481,7 +481,7 @@ kdb5_use_mkey(int argc, char *argv[])
+                  cur_actkvno != NULL;
+                  prev_actkvno = cur_actkvno, cur_actkvno = cur_actkvno->next) {
+ 
+-                if (new_actkvno->act_time < cur_actkvno->act_time) {
++                if (ts_after(cur_actkvno->act_time, new_actkvno->act_time)) {
+                     if (prev_actkvno) {
+                         prev_actkvno->next = new_actkvno;
+                         new_actkvno->next = cur_actkvno;
+@@ -499,7 +499,7 @@ kdb5_use_mkey(int argc, char *argv[])
+         }
+     }
+ 
+-    if (actkvno_list->act_time > now) {
++    if (ts_after(actkvno_list->act_time, now)) {
+         com_err(progname, EINVAL,
+                 _("there must be one master key currently active"));
+         exit_status++;
+diff --git a/src/kadmin/dbutil/tabdump.c b/src/kadmin/dbutil/tabdump.c
+index 69a3482ec..fb36b060a 100644
+--- a/src/kadmin/dbutil/tabdump.c
++++ b/src/kadmin/dbutil/tabdump.c
+@@ -148,7 +148,7 @@ write_date_iso(struct rec_args *args, krb5_timestamp when)
+     struct tm *tm = NULL;
+     struct rechandle *h = args->rh;
+ 
+-    t = when;
++    t = ts2tt(when);
+     tm = gmtime(&t);
+     if (tm == NULL) {
+         errno = EINVAL;
+diff --git a/src/kadmin/testing/util/tcl_kadm5.c b/src/kadmin/testing/util/tcl_kadm5.c
+index a4997c60c..9dde579ef 100644
+--- a/src/kadmin/testing/util/tcl_kadm5.c
++++ b/src/kadmin/testing/util/tcl_kadm5.c
+@@ -697,13 +697,13 @@ static Tcl_DString *unparse_principal_ent(kadm5_principal_ent_t princ,
+     } else
+         Tcl_DStringAppendElement(str, "null");
+ 
+-    sprintf(buf, "%d", princ->princ_expire_time);
++    sprintf(buf, "%u", (unsigned int)princ->princ_expire_time);
+     Tcl_DStringAppendElement(str, buf);
+ 
+-    sprintf(buf, "%d", princ->last_pwd_change);
++    sprintf(buf, "%u", (unsigned int)princ->last_pwd_change);
+     Tcl_DStringAppendElement(str, buf);
+ 
+-    sprintf(buf, "%d", princ->pw_expiration);
++    sprintf(buf, "%u", (unsigned int)princ->pw_expiration);
+     Tcl_DStringAppendElement(str, buf);
+ 
+     sprintf(buf, "%d", princ->max_life);
+@@ -722,7 +722,7 @@ static Tcl_DString *unparse_principal_ent(kadm5_principal_ent_t princ,
+     } else
+         Tcl_DStringAppendElement(str, "null");
+ 
+-    sprintf(buf, "%d", princ->mod_date);
++    sprintf(buf, "%u", (unsigned int)princ->mod_date);
+     Tcl_DStringAppendElement(str, buf);
+ 
+     if (mask & KADM5_ATTRIBUTES) {
+@@ -758,10 +758,10 @@ static Tcl_DString *unparse_principal_ent(kadm5_principal_ent_t princ,
+     sprintf(buf, "%d", princ->max_renewable_life);
+     Tcl_DStringAppendElement(str, buf);
+ 
+-    sprintf(buf, "%d", princ->last_success);
++    sprintf(buf, "%u", (unsigned int)princ->last_success);
+     Tcl_DStringAppendElement(str, buf);
+ 
+-    sprintf(buf, "%d", princ->last_failed);
++    sprintf(buf, "%u", (unsigned int)princ->last_failed);
+     Tcl_DStringAppendElement(str, buf);
+ 
+     sprintf(buf, "%d", princ->fail_auth_count);
+diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
+index 712ccb794..59a39cd30 100644
+--- a/src/kdc/do_as_req.c
++++ b/src/kdc/do_as_req.c
+@@ -87,7 +87,7 @@ get_key_exp(krb5_db_entry *entry)
+         return entry->pw_expiration;
+     if (entry->pw_expiration == 0)
+         return entry->expiration;
+-    return min(entry->expiration, entry->pw_expiration);
++    return ts_min(entry->expiration, entry->pw_expiration);
+ }
+ 
+ /*
+diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
+index 547a41441..aacd2f20d 100644
+--- a/src/kdc/do_tgs_req.c
++++ b/src/kdc/do_tgs_req.c
+@@ -500,12 +500,12 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt,
+ 
+         old_starttime = enc_tkt_reply.times.starttime ?
+             enc_tkt_reply.times.starttime : enc_tkt_reply.times.authtime;
+-        old_life = enc_tkt_reply.times.endtime - old_starttime;
++        old_life = ts_delta(enc_tkt_reply.times.endtime, old_starttime);
+ 
+         enc_tkt_reply.times.starttime = kdc_time;
+         enc_tkt_reply.times.endtime =
+-            min(header_ticket->enc_part2->times.renew_till,
+-                kdc_time + old_life);
++            ts_min(header_ticket->enc_part2->times.renew_till,
++                   ts_incr(kdc_time, old_life));
+     } else {
+         /* not a renew request */
+         enc_tkt_reply.times.starttime = kdc_time;
+diff --git a/src/kdc/extern.c b/src/kdc/extern.c
+index fe627494b..84b5c6ad5 100644
+--- a/src/kdc/extern.c
++++ b/src/kdc/extern.c
+@@ -37,6 +37,8 @@
+ kdc_realm_t     **kdc_realmlist = (kdc_realm_t **) NULL;
+ int             kdc_numrealms = 0;
+ krb5_data empty_string = {0, 0, ""};
+-krb5_timestamp kdc_infinity = KRB5_INT32_MAX; /* XXX */
+ krb5_keyblock   psr_key;
+ krb5_int32      max_dgram_reply_size = MAX_DGRAM_SIZE;
++
++/* With ts_after(), this is the largest timestamp value. */
++krb5_timestamp kdc_infinity = -1;
+diff --git a/src/kdc/fast_util.c b/src/kdc/fast_util.c
+index 9df940219..e05107ef3 100644
+--- a/src/kdc/fast_util.c
++++ b/src/kdc/fast_util.c
+@@ -607,7 +607,7 @@ kdc_fast_read_cookie(krb5_context context, struct kdc_request_state *state,
+     ret = krb5_timeofday(context, &now);
+     if (ret)
+         goto cleanup;
+-    if (now - COOKIE_LIFETIME > cookie->time) {
++    if (ts2tt(now) > cookie->time + COOKIE_LIFETIME) {
+         /* Don't accept the cookie contents.  Only return an error if the
+          * cookie is relevant to the request. */
+         if (is_relevant(cookie->data, req->padata))
+@@ -700,7 +700,7 @@ kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state,
+     ret = krb5_timeofday(context, &now);
+     if (ret)
+         goto cleanup;
+-    cookie.time = now;
++    cookie.time = ts2tt(now);
+     cookie.data = contents;
+     ret = encode_krb5_secure_cookie(&cookie, &der_cookie);
+     if (ret)
+diff --git a/src/kdc/kdc_log.c b/src/kdc/kdc_log.c
+index 94a2a1c87..c044a3553 100644
+--- a/src/kdc/kdc_log.c
++++ b/src/kdc/kdc_log.c
+@@ -79,9 +79,9 @@ log_as_req(krb5_context context, const krb5_fulladdr *from,
+         /* success */
+         char rep_etypestr[128];
+         rep_etypes2str(rep_etypestr, sizeof(rep_etypestr), reply);
+-        krb5_klog_syslog(LOG_INFO, _("AS_REQ (%s) %s: ISSUE: authtime %d, %s, "
++        krb5_klog_syslog(LOG_INFO, _("AS_REQ (%s) %s: ISSUE: authtime %u, %s, "
+                                      "%s for %s"),
+-                         ktypestr, fromstring, authtime,
++                         ktypestr, fromstring, (unsigned int)authtime,
+                          rep_etypestr, cname2, sname2);
+     } else {
+         /* fail */
+@@ -156,10 +156,10 @@ log_tgs_req(krb5_context ctx, const krb5_fulladdr *from,
+        name (useful), and doesn't log ktypestr (probably not
+        important).  */
+     if (errcode != KRB5KDC_ERR_SERVER_NOMATCH) {
+-        krb5_klog_syslog(LOG_INFO, _("TGS_REQ (%s) %s: %s: authtime %d, %s%s "
++        krb5_klog_syslog(LOG_INFO, _("TGS_REQ (%s) %s: %s: authtime %u, %s%s "
+                                      "%s for %s%s%s"),
+-                         ktypestr, fromstring, status, authtime, rep_etypestr,
+-                         !errcode ? "," : "", logcname, logsname,
++                         ktypestr, fromstring, status, (unsigned int)authtime,
++                         rep_etypestr, !errcode ? "," : "", logcname, logsname,
+                          errcode ? ", " : "", errcode ? emsg : "");
+         if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION))
+             krb5_klog_syslog(LOG_INFO,
+@@ -171,9 +171,9 @@ log_tgs_req(krb5_context ctx, const krb5_fulladdr *from,
+                              logaltcname);
+ 
+     } else
+-        krb5_klog_syslog(LOG_INFO, _("TGS_REQ %s: %s: authtime %d, %s for %s, "
++        krb5_klog_syslog(LOG_INFO, _("TGS_REQ %s: %s: authtime %u, %s for %s, "
+                                      "2nd tkt client %s"),
+-                         fromstring, status, authtime,
++                         fromstring, status, (unsigned int)authtime,
+                          logcname, logsname, logaltcname);
+ 
+     /* OpenSolaris: audit_krb5kdc_tgs_req(...)  or
+diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
+index 29f9dbbf0..778a629e5 100644
+--- a/src/kdc/kdc_util.c
++++ b/src/kdc/kdc_util.c
+@@ -654,7 +654,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
+     }
+ 
+     /* The client must not be expired */
+-    if (client.expiration && client.expiration < kdc_time) {
++    if (client.expiration && ts_after(kdc_time, client.expiration)) {
+         *status = "CLIENT EXPIRED";
+         if (vague_errors)
+             return(KRB_ERR_GENERIC);
+@@ -664,7 +664,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
+ 
+     /* The client's password must not be expired, unless the server is
+        a KRB5_KDC_PWCHANGE_SERVICE. */
+-    if (client.pw_expiration && client.pw_expiration < kdc_time &&
++    if (client.pw_expiration && ts_after(kdc_time, client.pw_expiration) &&
+         !isflagset(server.attributes, KRB5_KDB_PWCHANGE_SERVICE)) {
+         *status = "CLIENT KEY EXPIRED";
+         if (vague_errors)
+@@ -674,7 +674,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
+     }
+ 
+     /* The server must not be expired */
+-    if (server.expiration && server.expiration < kdc_time) {
++    if (server.expiration && ts_after(kdc_time, server.expiration)) {
+         *status = "SERVICE EXPIRED";
+         return(KDC_ERR_SERVICE_EXP);
+     }
+@@ -1765,9 +1765,9 @@ kdc_get_ticket_endtime(kdc_realm_t *kdc_active_realm,
+     if (till == 0)
+         till = kdc_infinity;
+ 
+-    until = min(till, endtime);
++    until = ts_min(till, endtime);
+ 
+-    life = until - starttime;
++    life = ts_delta(until, starttime);
+ 
+     if (client != NULL && client->max_life != 0)
+         life = min(life, client->max_life);
+@@ -1776,7 +1776,7 @@ kdc_get_ticket_endtime(kdc_realm_t *kdc_active_realm,
+     if (kdc_active_realm->realm_maxlife != 0)
+         life = min(life, kdc_active_realm->realm_maxlife);
+ 
+-    *out_endtime = starttime + life;
++    *out_endtime = ts_incr(starttime, life);
+ }
+ 
+ /*
+@@ -1806,22 +1806,22 @@ kdc_get_ticket_renewtime(kdc_realm_t *realm, krb5_kdc_req *request,
+     if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE))
+         rtime = request->rtime ? request->rtime : kdc_infinity;
+     else if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
+-             tkt->times.endtime < request->till)
++             ts_after(request->till, tkt->times.endtime))
+         rtime = request->till;
+     else
+         return;
+ 
+     /* Truncate it to the allowable renewable time. */
+     if (tgt != NULL)
+-        rtime = min(rtime, tgt->times.renew_till);
++        rtime = ts_min(rtime, tgt->times.renew_till);
+     max_rlife = min(server->max_renewable_life, realm->realm_maxrlife);
+     if (client != NULL)
+         max_rlife = min(max_rlife, client->max_renewable_life);
+-    rtime = min(rtime, tkt->times.starttime + max_rlife);
++    rtime = ts_min(rtime, ts_incr(tkt->times.starttime, max_rlife));
+ 
+     /* Make the ticket renewable if the truncated requested time is larger than
+      * the ticket end time. */
+-    if (rtime > tkt->times.endtime) {
++    if (ts_after(rtime, tkt->times.endtime)) {
+         setflag(tkt->flags, TKT_FLG_RENEWABLE);
+         tkt->times.renew_till = rtime;
+     }
+diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
+index bcf05fc27..672f94380 100644
+--- a/src/kdc/kdc_util.h
++++ b/src/kdc/kdc_util.h
+@@ -452,6 +452,8 @@ struct krb5_kdcpreauth_rock_st {
+ #define max(a, b)       ((a) > (b) ? (a) : (b))
+ #endif
+ 
++#define ts_min(a, b) (ts_after(a, b) ? (b) : (a))
++
+ #define ADDRTYPE2FAMILY(X)                                              \
+     ((X) == ADDRTYPE_INET6 ? AF_INET6 : (X) == ADDRTYPE_INET ? AF_INET : -1)
+ 
+diff --git a/src/kdc/replay.c b/src/kdc/replay.c
+index 8da7ac19a..fab39cf88 100644
+--- a/src/kdc/replay.c
++++ b/src/kdc/replay.c
+@@ -61,7 +61,7 @@ static size_t total_size = 0;
+ static krb5_ui_4 seed;
+ 
+ #define STALE_TIME      (2*60)            /* two minutes */
+-#define STALE(ptr, now) (abs((ptr)->timein - (now)) >= STALE_TIME)
++#define STALE(ptr, now) (labs(ts_delta((ptr)->timein, now)) >= STALE_TIME)
+ 
+ /* Return x rotated to the left by r bits. */
+ static inline krb5_ui_4
+diff --git a/src/kdc/tgs_policy.c b/src/kdc/tgs_policy.c
+index a30cacc66..d0f25d1b7 100644
+--- a/src/kdc/tgs_policy.c
++++ b/src/kdc/tgs_policy.c
+@@ -186,7 +186,7 @@ static int
+ check_tgs_svc_time(krb5_kdc_req *req, krb5_db_entry server, krb5_ticket *tkt,
+                    krb5_timestamp kdc_time, const char **status)
+ {
+-    if (server.expiration && server.expiration < kdc_time) {
++    if (server.expiration && ts_after(kdc_time, server.expiration)) {
+         *status = "SERVICE EXPIRED";
+         return KDC_ERR_SERVICE_EXP;
+     }
+@@ -222,7 +222,7 @@ check_tgs_times(krb5_kdc_req *req, krb5_ticket_times *times,
+        KDC time. */
+     if (req->kdc_options & KDC_OPT_VALIDATE) {
+         starttime = times->starttime ? times->starttime : times->authtime;
+-        if (starttime > kdc_time) {
++        if (ts_after(starttime, kdc_time)) {
+             *status = "NOT_YET_VALID";
+             return KRB_AP_ERR_TKT_NYV;
+         }
+@@ -231,7 +231,8 @@ check_tgs_times(krb5_kdc_req *req, krb5_ticket_times *times,
+      * Check the renew_till time.  The endtime was already
+      * been checked in the initial authentication check.
+      */
+-    if ((req->kdc_options & KDC_OPT_RENEW) && times->renew_till < kdc_time) {
++    if ((req->kdc_options & KDC_OPT_RENEW) &&
++        ts_after(kdc_time, times->renew_till)) {
+         *status = "TKT_EXPIRED";
+         return KRB_AP_ERR_TKT_EXPIRED;
+     }
+diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
+index 580d08cbf..06967aa27 100644
+--- a/src/lib/gssapi/krb5/accept_sec_context.c
++++ b/src/lib/gssapi/krb5/accept_sec_context.c
+@@ -351,8 +351,10 @@ kg_accept_dce(minor_status, context_handle, verifier_cred_handle,
+     if (mech_type)
+         *mech_type = ctx->mech_used;
+ 
+-    if (time_rec)
+-        *time_rec = ctx->krb_times.endtime + ctx->k5_context->clockskew - now;
++    if (time_rec) {
++        *time_rec = ts_delta(ctx->krb_times.endtime, now) +
++            ctx->k5_context->clockskew;
++    }
+ 
+     /* Never return GSS_C_DELEG_FLAG since we don't support DCE credential
+      * delegation yet. */
+@@ -1146,7 +1148,7 @@ kg_accept_krb5(minor_status, context_handle,
+     /* Add the maximum allowable clock skew as a grace period for context
+      * expiration, just as we do for the ticket. */
+     if (time_rec)
+-        *time_rec = ctx->krb_times.endtime + context->clockskew - now;
++        *time_rec = ts_delta(ctx->krb_times.endtime, now) + context->clockskew;
+ 
+     if (ret_flags)
+         *ret_flags = ctx->gss_flags;
+diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
+index 03ee25ec1..362ba9d86 100644
+--- a/src/lib/gssapi/krb5/acquire_cred.c
++++ b/src/lib/gssapi/krb5/acquire_cred.c
+@@ -550,7 +550,7 @@ set_refresh_time(krb5_context context, krb5_ccache ccache,
+     char buf[128];
+     krb5_data d;
+ 
+-    snprintf(buf, sizeof(buf), "%ld", (long)refresh_time);
++    snprintf(buf, sizeof(buf), "%u", (unsigned int)ts2tt(refresh_time));
+     d = string2data(buf);
+     (void)krb5_cc_set_config(context, ccache, NULL, KRB5_CC_CONF_REFRESH_TIME,
+                              &d);
+@@ -566,8 +566,9 @@ kg_cred_time_to_refresh(krb5_context context, krb5_gss_cred_id_rec *cred)
+ 
+     if (krb5_timeofday(context, &now))
+         return FALSE;
+-    if (cred->refresh_time != 0 && now >= cred->refresh_time) {
+-        set_refresh_time(context, cred->ccache, cred->refresh_time + 30);
++    if (cred->refresh_time != 0 && !ts_after(cred->refresh_time, now)) {
++        set_refresh_time(context, cred->ccache,
++                         ts_incr(cred->refresh_time, 30));
+         return TRUE;
+     }
+     return FALSE;
+@@ -586,7 +587,8 @@ kg_cred_set_initial_refresh(krb5_context context, krb5_gss_cred_id_rec *cred,
+         return;
+ 
+     /* Make a note to refresh these when they are halfway to expired. */
+-    refresh = times->starttime + (times->endtime - times->starttime) / 2;
++    refresh = ts_incr(times->starttime,
++                      ts_delta(times->endtime, times->starttime) / 2);
+     set_refresh_time(context, cred->ccache, refresh);
+ }
+ 
+@@ -848,7 +850,8 @@ acquire_cred_context(krb5_context context, OM_uint32 *minor_status,
+                                   GSS_C_NO_NAME);
+             if (GSS_ERROR(ret))
+                 goto error_out;
+-            *time_rec = (cred->expire > now) ? (cred->expire - now) : 0;
++            *time_rec = ts_after(cred->expire, now) ?
++                ts_delta(cred->expire, now) : 0;
+             k5_mutex_unlock(&cred->lock);
+         }
+     }
+diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c
+index 450593288..1fdb5a16f 100644
+--- a/src/lib/gssapi/krb5/context_time.c
++++ b/src/lib/gssapi/krb5/context_time.c
+@@ -51,7 +51,7 @@ krb5_gss_context_time(minor_status, context_handle, time_rec)
+         return(GSS_S_FAILURE);
+     }
+ 
+-    lifetime = ctx->krb_times.endtime - now;
++    lifetime = ts_delta(ctx->krb_times.endtime, now);
+     if (!ctx->initiate)
+         lifetime += ctx->k5_context->clockskew;
+     if (lifetime <= 0) {
+diff --git a/src/lib/gssapi/krb5/export_cred.c b/src/lib/gssapi/krb5/export_cred.c
+index 652b2604b..8054e4a77 100644
+--- a/src/lib/gssapi/krb5/export_cred.c
++++ b/src/lib/gssapi/krb5/export_cred.c
+@@ -410,10 +410,11 @@ json_kgcred(krb5_context context, krb5_gss_cred_id_t cred,
+     if (ret)
+         goto cleanup;
+ 
+-    ret = k5_json_array_fmt(&array, "ivvbbvvvvbiivs", cred->usage, name, imp,
++    ret = k5_json_array_fmt(&array, "ivvbbvvvvbLLvs", cred->usage, name, imp,
+                             cred->default_identity, cred->iakerb_mech, keytab,
+                             rcache, ccache, ckeytab, cred->have_tgt,
+-                            cred->expire, cred->refresh_time, etypes,
++                            (long long)ts2tt(cred->expire),
++                            (long long)ts2tt(cred->refresh_time), etypes,
+                             cred->password);
+     if (ret)
+         goto cleanup;
+diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c
+index 2dc4d0c1a..bb1072fe4 100644
+--- a/src/lib/gssapi/krb5/iakerb.c
++++ b/src/lib/gssapi/krb5/iakerb.c
+@@ -494,7 +494,7 @@ iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx,
+         if (code != 0)
+             goto cleanup;
+ 
+-        creds.times.endtime = now + time_req;
++        creds.times.endtime = ts_incr(now, time_req);
+     }
+ 
+     if (cred->name->ad_context != NULL) {
+@@ -669,7 +669,7 @@ iakerb_get_initial_state(iakerb_ctx_id_t ctx,
+         if (code != 0)
+             goto cleanup;
+ 
+-        in_creds.times.endtime = now + time_req;
++        in_creds.times.endtime = ts_incr(now, time_req);
+     }
+ 
+     /* Make an AS request if we have no creds or it's time to refresh them. */
+diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
+index 70f7955ae..8e5cc37fb 100644
+--- a/src/lib/gssapi/krb5/init_sec_context.c
++++ b/src/lib/gssapi/krb5/init_sec_context.c
+@@ -214,7 +214,8 @@ static krb5_error_code get_credentials(context, cred, server, now,
+      * boundaries) because accept_sec_context code is also similarly
+      * non-forgiving.
+      */
+-    if (!krb5_gss_dbg_client_expcreds && result_creds->times.endtime < now) {
++    if (!krb5_gss_dbg_client_expcreds &&
++        ts_after(now, result_creds->times.endtime)) {
+         code = KRB5KRB_AP_ERR_TKT_EXPIRED;
+         goto cleanup;
+     }
+@@ -575,7 +576,7 @@ kg_new_connection(
+     if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
+         ctx->krb_times.endtime = 0;
+     } else {
+-        ctx->krb_times.endtime = now + time_req;
++        ctx->krb_times.endtime = ts_incr(now, time_req);
+     }
+ 
+     if ((code = kg_duplicate_name(context, cred->name, &ctx->here)))
+@@ -659,7 +660,7 @@ kg_new_connection(
+     if (time_rec) {
+         if ((code = krb5_timeofday(context, &now)))
+             goto cleanup;
+-        *time_rec = ctx->krb_times.endtime - now;
++        *time_rec = ts_delta(ctx->krb_times.endtime, now);
+     }
+ 
+     /* set the other returns */
+@@ -873,7 +874,7 @@ mutual_auth(
+     if (time_rec) {
+         if ((code = krb5_timeofday(context, &now)))
+             goto fail;
+-        *time_rec = ctx->krb_times.endtime - now;
++        *time_rec = ts_delta(ctx->krb_times.endtime, now);
+     }
+ 
+     if (ret_flags)
+diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c
+index d2e466e60..cac024da1 100644
+--- a/src/lib/gssapi/krb5/inq_context.c
++++ b/src/lib/gssapi/krb5/inq_context.c
+@@ -120,7 +120,7 @@ krb5_gss_inquire_context(minor_status, context_handle, initiator_name,
+ 
+         /* Add the maximum allowable clock skew as a grace period for context
+          * expiration, just as we do for the ticket during authentication. */
+-        lifetime = ctx->krb_times.endtime - now;
++        lifetime = ts_delta(ctx->krb_times.endtime, now);
+         if (!ctx->initiate)
+             lifetime += context->clockskew;
+         if (lifetime < 0)
+diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c
+index 4e35a0563..e662ae53a 100644
+--- a/src/lib/gssapi/krb5/inq_cred.c
++++ b/src/lib/gssapi/krb5/inq_cred.c
+@@ -130,8 +130,9 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
+         goto fail;
+     }
+ 
+-    if (cred->expire > 0) {
+-        if ((lifetime = cred->expire - now) < 0)
++    if (cred->expire != 0) {
++        lifetime = ts_delta(cred->expire, now);
++        if (lifetime < 0)
+             lifetime = 0;
+     }
+     else
+diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
+index ff1c310bc..10848c1df 100644
+--- a/src/lib/gssapi/krb5/s4u_gss_glue.c
++++ b/src/lib/gssapi/krb5/s4u_gss_glue.c
+@@ -284,7 +284,7 @@ kg_compose_deleg_cred(OM_uint32 *minor_status,
+         if (code != 0)
+             goto cleanup;
+ 
+-        *time_rec = cred->expire - now;
++        *time_rec = ts_delta(cred->expire, now);
+     }
+ 
+     major_status = GSS_S_COMPLETE;
+diff --git a/src/lib/kadm5/chpass_util.c b/src/lib/kadm5/chpass_util.c
+index 408b0eb31..1680a5504 100644
+--- a/src/lib/kadm5/chpass_util.c
++++ b/src/lib/kadm5/chpass_util.c
+@@ -4,15 +4,11 @@
+  */
+ 
+ 
+-#include "autoconf.h"
+-#include <stdio.h>
+-#include <time.h>
+-#include <string.h>
++#include "k5-int.h"
+ 
+ #include <kadm5/admin.h>
+ #include "admin_internal.h"
+ 
+-#include <krb5.h>
+ 
+ #define string_text error_message
+ 
+@@ -218,7 +214,7 @@ kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle,
+         time_t until;
+         char *time_string, *ptr;
+ 
+-        until = princ_ent.last_pwd_change + policy_ent.pw_min_life;
++        until = ts_incr(princ_ent.last_pwd_change, policy_ent.pw_min_life);
+ 
+         time_string = ctime(&until);
+         if (*(ptr = &time_string[strlen(time_string)-1]) == '\n')
+diff --git a/src/lib/kadm5/srv/server_acl.c b/src/lib/kadm5/srv/server_acl.c
+index 59ed0b975..656dddff5 100644
+--- a/src/lib/kadm5/srv/server_acl.c
++++ b/src/lib/kadm5/srv/server_acl.c
+@@ -408,13 +408,14 @@ kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp)
+     }
+     if (rp->mask & KADM5_PRINC_EXPIRE_TIME) {
+         if (!(*maskp & KADM5_PRINC_EXPIRE_TIME)
+-            || (recp->princ_expire_time > (now + rp->princ_lifetime)))
++            || ts_after(recp->princ_expire_time,
++                        ts_incr(now, rp->princ_lifetime)))
+             recp->princ_expire_time = now + rp->princ_lifetime;
+         *maskp |= KADM5_PRINC_EXPIRE_TIME;
+     }
+     if (rp->mask & KADM5_PW_EXPIRATION) {
+         if (!(*maskp & KADM5_PW_EXPIRATION)
+-            || (recp->pw_expiration > (now + rp->pw_lifetime)))
++            || ts_after(recp->pw_expiration, ts_incr(now, rp->pw_lifetime)))
+             recp->pw_expiration = now + rp->pw_lifetime;
+         *maskp |= KADM5_PW_EXPIRATION;
+     }
+diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c
+index 0640b47c4..f4a9a2ad2 100644
+--- a/src/lib/kadm5/srv/svr_principal.c
++++ b/src/lib/kadm5/srv/svr_principal.c
+@@ -400,7 +400,7 @@ kadm5_create_principal_3(void *server_handle,
+     kdb->pw_expiration = 0;
+     if (have_polent) {
+         if(polent.pw_max_life)
+-            kdb->pw_expiration = now + polent.pw_max_life;
++            kdb->pw_expiration = ts_incr(now, polent.pw_max_life);
+         else
+             kdb->pw_expiration = 0;
+     }
+@@ -612,7 +612,7 @@ kadm5_modify_principal(void *server_handle,
+                                                   &(kdb->pw_expiration));
+             if (ret)
+                 goto done;
+-            kdb->pw_expiration += pol.pw_max_life;
++            kdb->pw_expiration = ts_incr(kdb->pw_expiration, pol.pw_max_life);
+         } else {
+             kdb->pw_expiration = 0;
+         }
+@@ -1445,7 +1445,7 @@ kadm5_chpass_principal_3(void *server_handle,
+         }
+ 
+         if (pol.pw_max_life)
+-            kdb->pw_expiration = now + pol.pw_max_life;
++            kdb->pw_expiration = ts_incr(now, pol.pw_max_life);
+         else
+             kdb->pw_expiration = 0;
+     } else {
+@@ -1624,7 +1624,7 @@ kadm5_randkey_principal_3(void *server_handle,
+ #endif
+ 
+         if (pol.pw_max_life)
+-            kdb->pw_expiration = now + pol.pw_max_life;
++            kdb->pw_expiration = ts_incr(now, pol.pw_max_life);
+         else
+             kdb->pw_expiration = 0;
+     } else {
+@@ -1774,7 +1774,7 @@ kadm5_setv4key_principal(void *server_handle,
+ #endif
+ 
+         if (pol.pw_max_life)
+-            kdb->pw_expiration = now + pol.pw_max_life;
++            kdb->pw_expiration = ts_incr(now, pol.pw_max_life);
+         else
+             kdb->pw_expiration = 0;
+     } else {
+@@ -2024,7 +2024,7 @@ kadm5_setkey_principal_4(void *server_handle, krb5_principal principal,
+     }
+     if (have_pol) {
+         if (pol.pw_max_life)
+-            kdb->pw_expiration = now + pol.pw_max_life;
++            kdb->pw_expiration = ts_incr(now, pol.pw_max_life);
+         else
+             kdb->pw_expiration = 0;
+     } else {
+diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c
+index 4adf0fcbb..7f33c7e68 100644
+--- a/src/lib/kdb/kdb5.c
++++ b/src/lib/kdb/kdb5.c
+@@ -1296,7 +1296,7 @@ find_actkvno(krb5_actkvno_node *list, krb5_timestamp now)
+      * are in the future, we will return the first node; if all are in the
+      * past, we will return the last node.
+      */
+-    while (list->next != NULL && list->next->act_time <= now)
++    while (list->next != NULL && !ts_after(list->next->act_time, now))
+         list = list->next;
+     return list->act_kvno;
+ }
+diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c
+index a827ca608..889460989 100644
+--- a/src/lib/krb5/asn.1/asn1_k_encode.c
++++ b/src/lib/krb5/asn.1/asn1_k_encode.c
+@@ -158,8 +158,7 @@ static asn1_error_code
+ encode_kerberos_time(asn1buf *buf, const void *p, taginfo *rettag,
+                      size_t *len_out)
+ {
+-    /* Range checking for time_t vs krb5_timestamp?  */
+-    time_t val = *(krb5_timestamp *)p;
++    time_t val = ts2tt(*(krb5_timestamp *)p);
+     rettag->asn1class = UNIVERSAL;
+     rettag->construction = PRIMITIVE;
+     rettag->tagnum = ASN1_GENERALTIME;
+diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c
+index 4fe3f0d6f..fba710b1b 100644
+--- a/src/lib/krb5/ccache/cc_keyring.c
++++ b/src/lib/krb5/ccache/cc_keyring.c
+@@ -751,7 +751,7 @@ update_keyring_expiration(krb5_context context, krb5_ccache id)
+     for (;;) {
+         if (krcc_next_cred(context, id, &cursor, &creds) != 0)
+             break;
+-        if (creds.times.endtime > endtime)
++        if (ts_after(creds.times.endtime, endtime))
+             endtime = creds.times.endtime;
+         krb5_free_cred_contents(context, &creds);
+     }
+@@ -765,7 +765,7 @@ update_keyring_expiration(krb5_context context, krb5_ccache id)
+ 
+     /* Setting the timeout to zero would reset the timeout, so we set it to one
+      * second instead if creds are already expired. */
+-    timeout = (endtime > now) ? endtime - now : 1;
++    timeout = ts_after(endtime, now) ? ts_delta(endtime, now) : 1;
+     (void)keyctl_set_timeout(data->cache_id, timeout);
+ }
+ 
+@@ -1316,8 +1316,10 @@ krcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
+     if (ret)
+         goto errout;
+ 
+-    if (creds->times.endtime > now)
+-        (void)keyctl_set_timeout(cred_key, creds->times.endtime - now);
++    if (ts_after(creds->times.endtime, now)) {
++        (void)keyctl_set_timeout(cred_key,
++                                 ts_delta(creds->times.endtime, now));
++    }
+ 
+     update_keyring_expiration(context, id);
+ 
+@@ -1680,8 +1682,8 @@ static void
+ krcc_update_change_time(krcc_data *data)
+ {
+     krb5_timestamp now_time = time(NULL);
+-    data->changetime = (data->changetime >= now_time) ?
+-        data->changetime + 1 : now_time;
++    data->changetime = ts_after(now_time, data->changetime) ?
++        now_time : ts_incr(data->changetime, 1);
+ }
+ 
+ /*
+diff --git a/src/lib/krb5/ccache/cc_memory.c b/src/lib/krb5/ccache/cc_memory.c
+index 0354575c5..c5425eb3a 100644
+--- a/src/lib/krb5/ccache/cc_memory.c
++++ b/src/lib/krb5/ccache/cc_memory.c
+@@ -720,8 +720,8 @@ static void
+ update_mcc_change_time(krb5_mcc_data *d)
+ {
+     krb5_timestamp now_time = time(NULL);
+-    d->changetime = (d->changetime >= now_time) ?
+-        d->changetime + 1 : now_time;
++    d->changetime = ts_after(now_time, d->changetime) ?
++        now_time : ts_incr(d->changetime, 1);
+ }
+ 
+ static krb5_error_code KRB5_CALLCONV
+diff --git a/src/lib/krb5/ccache/cc_retr.c b/src/lib/krb5/ccache/cc_retr.c
+index 1314d24bd..1a32e00c8 100644
+--- a/src/lib/krb5/ccache/cc_retr.c
++++ b/src/lib/krb5/ccache/cc_retr.c
+@@ -46,11 +46,11 @@ static krb5_boolean
+ times_match(const krb5_ticket_times *t1, const krb5_ticket_times *t2)
+ {
+     if (t1->renew_till) {
+-        if (t1->renew_till > t2->renew_till)
++        if (ts_after(t1->renew_till, t2->renew_till))
+             return FALSE;               /* this one expires too late */
+     }
+     if (t1->endtime) {
+-        if (t1->endtime > t2->endtime)
++        if (ts_after(t1->endtime, t2->endtime))
+             return FALSE;               /* this one expires too late */
+     }
+     /* only care about expiration on a times_match */
+diff --git a/src/lib/krb5/ccache/ccapi/stdcc_util.c b/src/lib/krb5/ccache/ccapi/stdcc_util.c
+index 9f44af3d0..6092ee432 100644
+--- a/src/lib/krb5/ccache/ccapi/stdcc_util.c
++++ b/src/lib/krb5/ccache/ccapi/stdcc_util.c
+@@ -16,8 +16,8 @@
+ #include <malloc.h>
+ #endif
+ 
++#include "k5-int.h"
+ #include "stdcc_util.h"
+-#include "krb5.h"
+ #ifdef _WIN32                   /* it's part of krb5.h everywhere else */
+ #include "kv5m_err.h"
+ #endif
+@@ -321,10 +321,10 @@ copy_cc_cred_union_to_krb5_creds (krb5_context in_context,
+         keyblock_contents = NULL;
+ 
+         /* copy times */
+-        out_creds->times.authtime   = cv5->authtime     + offset_seconds;
+-        out_creds->times.starttime  = cv5->starttime    + offset_seconds;
+-        out_creds->times.endtime    = cv5->endtime      + offset_seconds;
+-        out_creds->times.renew_till = cv5->renew_till   + offset_seconds;
++        out_creds->times.authtime   = ts_incr(cv5->authtime, offset_seconds);
++        out_creds->times.starttime  = ts_incr(cv5->starttime, offset_seconds);
++        out_creds->times.endtime    = ts_incr(cv5->endtime, offset_seconds);
++        out_creds->times.renew_till = ts_incr(cv5->renew_till, offset_seconds);
+         out_creds->is_skey          = cv5->is_skey;
+         out_creds->ticket_flags     = cv5->ticket_flags;
+ 
+@@ -451,11 +451,11 @@ copy_krb5_creds_to_cc_cred_union (krb5_context in_context,
+         cv5->keyblock.data = keyblock_data;
+         keyblock_data = NULL;
+ 
+-        cv5->authtime     = in_creds->times.authtime   - offset_seconds;
+-        cv5->starttime    = in_creds->times.starttime  - offset_seconds;
+-        cv5->endtime      = in_creds->times.endtime    - offset_seconds;
+-        cv5->renew_till   = in_creds->times.renew_till - offset_seconds;
+-        cv5->is_skey      = in_creds->is_skey;
++        cv5->authtime = ts_incr(in_creds->times.authtime, -offset_seconds);
++        cv5->starttime = ts_incr(in_creds->times.starttime, -offset_seconds);
++        cv5->endtime = ts_incr(in_creds->times.endtime, -offset_seconds);
++        cv5->renew_till = ts_incr(in_creds->times.renew_till, -offset_seconds);
++        cv5->is_skey = in_creds->is_skey;
+         cv5->ticket_flags = in_creds->ticket_flags;
+ 
+         if (in_creds->ticket.data) {
+@@ -732,10 +732,10 @@ void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest)
+     err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
+     if (err) return;
+ #endif
+-    dest->times.authtime   = src->authtime     + offset_seconds;
+-    dest->times.starttime  = src->starttime    + offset_seconds;
+-    dest->times.endtime    = src->endtime      + offset_seconds;
+-    dest->times.renew_till = src->renew_till   + offset_seconds;
++    dest->times.authtime   = ts_incr(src->authtime, offset_seconds);
++    dest->times.starttime  = ts_incr(src->starttime, offset_seconds);
++    dest->times.endtime    = ts_incr(src->endtime, offset_seconds);
++    dest->times.renew_till = ts_incr(src->renew_till, offset_seconds);
+     dest->is_skey          = src->is_skey;
+     dest->ticket_flags     = src->ticket_flags;
+ 
+@@ -804,10 +804,10 @@ void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu)
+     err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
+     if (err) return;
+ #endif
+-    c->authtime     = creds->times.authtime   - offset_seconds;
+-    c->starttime    = creds->times.starttime  - offset_seconds;
+-    c->endtime      = creds->times.endtime    - offset_seconds;
+-    c->renew_till   = creds->times.renew_till - offset_seconds;
++    c->authtime     = ts_incr(creds->times.authtime, -offset_seconds);
++    c->starttime    = ts_incr(creds->times.starttime, -offset_seconds);
++    c->endtime      = ts_incr(creds->times.endtime, -offset_seconds);
++    c->renew_till   = ts_incr(creds->times.renew_till, -offset_seconds);
+     c->is_skey      = creds->is_skey;
+     c->ticket_flags = creds->ticket_flags;
+ 
+@@ -925,11 +925,11 @@ times_match(t1, t2)
+     register const krb5_ticket_times *t2;
+ {
+     if (t1->renew_till) {
+-        if (t1->renew_till > t2->renew_till)
++        if (ts_after(t1->renew_till, t2->renew_till))
+             return FALSE;               /* this one expires too late */
+     }
+     if (t1->endtime) {
+-        if (t1->endtime > t2->endtime)
++        if (ts_after(t1->endtime, t2->endtime))
+             return FALSE;               /* this one expires too late */
+     }
+     /* only care about expiration on a times_match */
+diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c
+index c31a3f5f0..e631f2051 100644
+--- a/src/lib/krb5/ccache/cccursor.c
++++ b/src/lib/krb5/ccache/cccursor.c
+@@ -159,7 +159,7 @@ krb5_cccol_last_change_time(krb5_context context,
+         ret = krb5_cccol_cursor_next(context, c, &ccache);
+         if (ccache) {
+             ret = krb5_cc_last_change_time(context, ccache, &last_time);
+-            if (!ret && last_time > max_change_time) {
++            if (!ret && ts_after(last_time, max_change_time)) {
+                 max_change_time = last_time;
+             }
+             ret = 0;
+diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c
+index 131549ffe..b014abf0b 100644
+--- a/src/lib/krb5/keytab/kt_file.c
++++ b/src/lib/krb5/keytab/kt_file.c
+@@ -264,9 +264,11 @@ more_recent(const krb5_keytab_entry *k1, const krb5_keytab_entry *k2)
+      * limitations (8-bit kvno storage), pre-1.14 kadmin protocol limitations
+      * (8-bit kvno marshalling), or KDB limitations (16-bit kvno storage).
+      */
+-    if (k1->timestamp >= k2->timestamp && k1->vno < 128 && k2->vno > 240)
++    if (!ts_after(k2->timestamp, k1->timestamp) &&
++        k1->vno < 128 && k2->vno > 240)
+         return TRUE;
+-    if (k1->timestamp <= k2->timestamp && k1->vno > 240 && k2->vno < 128)
++    if (!ts_after(k1->timestamp, k2->timestamp) &&
++        k1->vno > 240 && k2->vno < 128)
+         return FALSE;
+ 
+     /* Otherwise do a simple version comparison. */
+diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c
+index c85d8b8d8..cf1ea361f 100644
+--- a/src/lib/krb5/krb/gc_via_tkt.c
++++ b/src/lib/krb5/krb/gc_via_tkt.c
+@@ -287,18 +287,19 @@ krb5int_process_tgs_reply(krb5_context context,
+         retval = KRB5_KDCREP_MODIFIED;
+ 
+     if ((in_cred->times.endtime != 0) &&
+-        (dec_rep->enc_part2->times.endtime > in_cred->times.endtime))
++        ts_after(dec_rep->enc_part2->times.endtime, in_cred->times.endtime))
+         retval = KRB5_KDCREP_MODIFIED;
+ 
+     if ((kdcoptions & KDC_OPT_RENEWABLE) &&
+         (in_cred->times.renew_till != 0) &&
+-        (dec_rep->enc_part2->times.renew_till > in_cred->times.renew_till))
++        ts_after(dec_rep->enc_part2->times.renew_till,
++                 in_cred->times.renew_till))
+         retval = KRB5_KDCREP_MODIFIED;
+ 
+     if ((kdcoptions & KDC_OPT_RENEWABLE_OK) &&
+         (dec_rep->enc_part2->flags & KDC_OPT_RENEWABLE) &&
+         (in_cred->times.endtime != 0) &&
+-        (dec_rep->enc_part2->times.renew_till > in_cred->times.endtime))
++        ts_after(dec_rep->enc_part2->times.renew_till, in_cred->times.endtime))
+         retval = KRB5_KDCREP_MODIFIED;
+ 
+     if (retval != 0)
+diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c
+index 110abeb2b..be5b2d18c 100644
+--- a/src/lib/krb5/krb/get_creds.c
++++ b/src/lib/krb5/krb/get_creds.c
+@@ -816,7 +816,7 @@ get_cached_local_tgt(krb5_context context, krb5_tkt_creds_context ctx,
+         return code;
+ 
+     /* Check if the TGT is expired before bothering the KDC with it. */
+-    if (now > tgt->times.endtime) {
++    if (ts_after(now, tgt->times.endtime)) {
+         krb5_free_creds(context, tgt);
+         return KRB5KRB_AP_ERR_TKT_EXPIRED;
+     }
+diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
+index a058f5bd7..40aba1905 100644
+--- a/src/lib/krb5/krb/get_in_tkt.c
++++ b/src/lib/krb5/krb/get_in_tkt.c
+@@ -39,24 +39,6 @@ static krb5_error_code sort_krb5_padata_sequence(krb5_context context,
+                                                  krb5_data *realm,
+                                                  krb5_pa_data **padata);
+ 
+-/*
+- * This function performs 32 bit bounded addition so we can generate
+- * lifetimes without overflowing krb5_int32
+- */
+-static krb5_int32
+-krb5int_addint32 (krb5_int32 x, krb5_int32 y)
+-{
+-    if ((x > 0) && (y > (KRB5_INT32_MAX - x))) {
+-        /* sum will be be greater than KRB5_INT32_MAX */
+-        return KRB5_INT32_MAX;
+-    } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) {
+-        /* sum will be less than KRB5_INT32_MIN */
+-        return KRB5_INT32_MIN;
+-    }
+-
+-    return x + y;
+-}
+-
+ /*
+  * Decrypt the AS reply in ctx, populating ctx->reply->enc_part2.  If
+  * strengthen_key is not null, combine it with the reply key as specified in
+@@ -267,21 +249,21 @@ verify_as_reply(krb5_context            context,
+             (request->from != 0) &&
+             (request->from != as_reply->enc_part2->times.starttime))
+         || ((request->till != 0) &&
+-            (as_reply->enc_part2->times.endtime > request->till))
++            ts_after(as_reply->enc_part2->times.endtime, request->till))
+         || ((request->kdc_options & KDC_OPT_RENEWABLE) &&
+             (request->rtime != 0) &&
+-            (as_reply->enc_part2->times.renew_till > request->rtime))
++            ts_after(as_reply->enc_part2->times.renew_till, request->rtime))
+         || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
+             !(request->kdc_options & KDC_OPT_RENEWABLE) &&
+             (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
+             (request->till != 0) &&
+-            (as_reply->enc_part2->times.renew_till > request->till))
++            ts_after(as_reply->enc_part2->times.renew_till, request->till))
+     ) {
+         return KRB5_KDCREP_MODIFIED;
+     }
+ 
+     if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) {
+-        time_offset = as_reply->enc_part2->times.authtime - time_now;
++        time_offset = ts_delta(as_reply->enc_part2->times.authtime, time_now);
+         retval = krb5_set_time_offsets(context, time_offset, 0);
+         if (retval)
+             return retval;
+@@ -790,15 +772,15 @@ set_request_times(krb5_context context, krb5_init_creds_context ctx)
+         return code;
+ 
+     /* Omit request start time unless the caller explicitly asked for one. */
+-    from = krb5int_addint32(now, ctx->start_time);
++    from = ts_incr(now, ctx->start_time);
+     if (ctx->start_time != 0)
+         ctx->request->from = from;
+ 
+-    ctx->request->till = krb5int_addint32(from, ctx->tkt_life);
++    ctx->request->till = ts_incr(from, ctx->tkt_life);
+ 
+     if (ctx->renew_life > 0) {
+         /* Don't ask for a smaller renewable time than the lifetime. */
+-        ctx->request->rtime = krb5int_addint32(from, ctx->renew_life);
++        ctx->request->rtime = ts_incr(from, ctx->renew_life);
+         if (ctx->request->rtime < ctx->request->till)
+             ctx->request->rtime = ctx->request->till;
+         ctx->request->kdc_options &= ~KDC_OPT_RENEWABLE_OK;
+@@ -1438,7 +1420,7 @@ note_req_timestamp(krb5_context context, krb5_init_creds_context ctx,
+ 
+     if (k5_time_with_offset(0, 0, &now, &usec) != 0)
+         return;
+-    ctx->pa_offset = kdc_time - now;
++    ctx->pa_offset = ts_delta(kdc_time, now);
+     ctx->pa_offset_usec = kdc_usec - usec;
+     ctx->pa_offset_state = (ctx->fast_state->armor_key != NULL) ?
+         AUTH_OFFSET : UNAUTH_OFFSET;
+@@ -1807,6 +1789,7 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out,
+ {
+     int i;
+     krb5_int32 starttime;
++    krb5_deltat lifetime;
+     krb5_get_init_creds_opt *opt;
+     krb5_error_code retval;
+ 
+@@ -1838,7 +1821,8 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out,
+         if (retval)
+             goto cleanup;
+         if (creds->times.starttime) starttime = creds->times.starttime;
+-        krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime);
++        lifetime = ts_delta(creds->times.endtime, starttime);
++        krb5_get_init_creds_opt_set_tkt_life(opt, lifetime);
+     }
+     *out = opt;
+     return 0;
+diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c
+index 6f3a29f2c..3565a7c4c 100644
+--- a/src/lib/krb5/krb/gic_pwd.c
++++ b/src/lib/krb5/krb/gic_pwd.c
+@@ -211,7 +211,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
+     if (ret != 0)
+         return;
+     if (!is_last_req &&
+-        (pw_exp < now || (pw_exp - now) > 7 * 24 * 60 * 60))
++        (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60))
+         return;
+ 
+     if (!prompter)
+@@ -221,7 +221,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
+     if (ret != 0)
+         return;
+ 
+-    delta = pw_exp - now;
++    delta = ts_delta(pw_exp, now);
+     if (delta < 3600) {
+         snprintf(banner, sizeof(banner),
+                  _("Warning: Your password will expire in less than one hour "
+diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h
+index 44eca359f..48bd9f8f7 100644
+--- a/src/lib/krb5/krb/int-proto.h
++++ b/src/lib/krb5/krb/int-proto.h
+@@ -84,7 +84,7 @@ krb5int_construct_matching_creds(krb5_context context, krb5_flags options,
+                                  krb5_flags *fields);
+ 
+ #define in_clock_skew(context, date, now)               \
+-    (labs((date) - (now)) < (context)->clockskew)
++    (labs(ts_delta(date, now)) < (context)->clockskew)
+ 
+ #define IS_TGS_PRINC(p) ((p)->length == 2 &&                            \
+                          data_eq_string((p)->data[0], KRB5_TGS_NAME))
+diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
+index 9098927b5..c70585a9e 100644
+--- a/src/lib/krb5/krb/pac.c
++++ b/src/lib/krb5/krb/pac.c
+@@ -378,7 +378,7 @@ k5_time_to_seconds_since_1970(int64_t ntTime, krb5_timestamp *elapsedSeconds)
+ 
+     abstime = ntTime > 0 ? ntTime - NT_TIME_EPOCH : -ntTime;
+ 
+-    if (abstime > KRB5_INT32_MAX)
++    if (abstime > UINT32_MAX)
+         return ERANGE;
+ 
+     *elapsedSeconds = abstime;
+diff --git a/src/lib/krb5/krb/str_conv.c b/src/lib/krb5/krb/str_conv.c
+index 3ab7eacac..f0a2ae20b 100644
+--- a/src/lib/krb5/krb/str_conv.c
++++ b/src/lib/krb5/krb/str_conv.c
+@@ -207,7 +207,7 @@ krb5_error_code KRB5_CALLCONV
+ krb5_timestamp_to_string(krb5_timestamp timestamp, char *buffer, size_t buflen)
+ {
+     size_t ret;
+-    time_t timestamp2 = timestamp;
++    time_t timestamp2 = ts2tt(timestamp);
+     struct tm tmbuf;
+     const char *fmt = "%c"; /* This is to get around gcc -Wall warning that
+                                the year returned might be two digits */
+@@ -229,7 +229,7 @@ krb5_timestamp_to_sfstring(krb5_timestamp timestamp, char *buffer, size_t buflen
+     struct tm   *tmp;
+     size_t i;
+     size_t      ndone;
+-    time_t timestamp2 = timestamp;
++    time_t timestamp2 = ts2tt(timestamp);
+     struct tm tmbuf;
+ 
+     static const char * const sftime_format_table[] = {
+diff --git a/src/lib/krb5/krb/t_kerb.c b/src/lib/krb5/krb/t_kerb.c
+index 60cfb5b15..74ac14d9a 100644
+--- a/src/lib/krb5/krb/t_kerb.c
++++ b/src/lib/krb5/krb/t_kerb.c
+@@ -5,16 +5,8 @@
+  */
+ 
+ #include "autoconf.h"
+-#include "krb5.h"
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
+-#include <unistd.h>
++#include "k5-int.h"
+ #include <time.h>
+-#include <sys/types.h>
+-#include <sys/socket.h>
+-#include <netinet/in.h>
+-#include <arpa/inet.h>
+ 
+ #include "com_err.h"
+ 
+@@ -37,7 +29,7 @@ test_string_to_timestamp(krb5_context ctx, char *ktime)
+         com_err("krb5_string_to_timestamp", retval, 0);
+         return;
+     }
+-    t = (time_t) timestamp;
++    t = ts2tt(timestamp);
+     printf("Parsed time was %s", ctime(&t));
+ }
+ 
+diff --git a/src/lib/krb5/krb/valid_times.c b/src/lib/krb5/krb/valid_times.c
+index d63122183..9e509b2dd 100644
+--- a/src/lib/krb5/krb/valid_times.c
++++ b/src/lib/krb5/krb/valid_times.c
+@@ -47,10 +47,10 @@ krb5int_validate_times(krb5_context context, krb5_ticket_times *times)
+     else
+         starttime = times->authtime;
+ 
+-    if (starttime - currenttime > context->clockskew)
++    if (ts_delta(starttime, currenttime) > context->clockskew)
+         return KRB5KRB_AP_ERR_TKT_NYV;  /* ticket not yet valid */
+ 
+-    if ((currenttime - times->endtime) > context->clockskew)
++    if (ts_delta(currenttime, times->endtime) > context->clockskew)
+         return KRB5KRB_AP_ERR_TKT_EXPIRED; /* ticket expired */
+ 
+     return 0;
+diff --git a/src/lib/krb5/krb/vfy_increds.c b/src/lib/krb5/krb/vfy_increds.c
+index 9786d63b5..b4878ba38 100644
+--- a/src/lib/krb5/krb/vfy_increds.c
++++ b/src/lib/krb5/krb/vfy_increds.c
+@@ -120,7 +120,7 @@ get_vfy_cred(krb5_context context, krb5_creds *creds, krb5_principal server,
+         ret = krb5_timeofday(context, &in_creds.times.endtime);
+         if (ret)
+             goto cleanup;
+-        in_creds.times.endtime += 5*60;
++        in_creds.times.endtime = ts_incr(in_creds.times.endtime, 5 * 60);
+         ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds);
+         if (ret)
+             goto cleanup;
+diff --git a/src/lib/krb5/os/timeofday.c b/src/lib/krb5/os/timeofday.c
+index fddb12142..887f24c22 100644
+--- a/src/lib/krb5/os/timeofday.c
++++ b/src/lib/krb5/os/timeofday.c
+@@ -60,7 +60,7 @@ krb5_check_clockskew(krb5_context context, krb5_timestamp date)
+     retval = krb5_timeofday(context, &currenttime);
+     if (retval)
+         return retval;
+-    if (!(labs((date)-currenttime) < context->clockskew))
++    if (labs(ts_delta(date, currenttime)) >= context->clockskew)
+         return KRB5KRB_AP_ERR_SKEW;
+ 
+     return 0;
+diff --git a/src/lib/krb5/os/toffset.c b/src/lib/krb5/os/toffset.c
+index 456193a41..37bc69f49 100644
+--- a/src/lib/krb5/os/toffset.c
++++ b/src/lib/krb5/os/toffset.c
+@@ -47,7 +47,7 @@ krb5_set_real_time(krb5_context context, krb5_timestamp seconds, krb5_int32 micr
+     if (retval)
+         return retval;
+ 
+-    os_ctx->time_offset = seconds - sec;
++    os_ctx->time_offset = ts_delta(seconds, sec);
+     os_ctx->usec_offset = (microseconds > -1) ? microseconds - usec : 0;
+ 
+     os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) |
+diff --git a/src/lib/krb5/os/ustime.c b/src/lib/krb5/os/ustime.c
+index 056357683..1c1b571eb 100644
+--- a/src/lib/krb5/os/ustime.c
++++ b/src/lib/krb5/os/ustime.c
+@@ -49,13 +49,13 @@ k5_time_with_offset(krb5_timestamp offset, krb5_int32 offset_usec,
+     usec += offset_usec;
+     if (usec > 1000000) {
+         usec -= 1000000;
+-        sec++;
++        sec = ts_incr(sec, 1);
+     }
+     if (usec < 0) {
+         usec += 1000000;
+-        sec--;
++        sec = ts_incr(sec, -1);
+     }
+-    sec += offset;
++    sec = ts_incr(sec, offset);
+ 
+     *time_out = sec;
+     *usec_out = usec;
+diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c
+index c0f12ed9d..6b043844d 100644
+--- a/src/lib/krb5/rcache/rc_dfl.c
++++ b/src/lib/krb5/rcache/rc_dfl.c
+@@ -97,8 +97,7 @@ alive(krb5_int32 mytime, krb5_donot_replay *new1, krb5_deltat t)
+ {
+     if (mytime == 0)
+         return CMP_HOHUM; /* who cares? */
+-    /* I hope we don't have to worry about overflow */
+-    if (new1->ctime + t < mytime)
++    if (ts_after(mytime, ts_incr(new1->ctime, t)))
+         return CMP_EXPIRED;
+     return CMP_HOHUM;
+ }
+diff --git a/src/lib/krb5/rcache/t_replay.c b/src/lib/krb5/rcache/t_replay.c
+index db273ec2f..b99cdf1ab 100644
+--- a/src/lib/krb5/rcache/t_replay.c
++++ b/src/lib/krb5/rcache/t_replay.c
+@@ -110,7 +110,7 @@ store(krb5_context ctx, char *rcspec, char *client, char *server, char *msg,
+     krb5_donot_replay rep;
+     krb5_data d;
+ 
+-    if (now_timestamp > 0)
++    if (now_timestamp != 0)
+         krb5_set_debugging_time(ctx, now_timestamp, now_usec);
+     if ((retval = krb5_rc_resolve_full(ctx, &rc, rcspec)))
+         goto cleanup;
+@@ -221,13 +221,13 @@ main(int argc, char **argv)
+             msg = (**argv) ? *argv : NULL;
+             argc--; argv++;
+             if (!argc) usage(progname);
+-            timestamp = (krb5_timestamp) atol(*argv);
++            timestamp = (krb5_timestamp) atoll(*argv);
+             argc--; argv++;
+             if (!argc) usage(progname);
+             usec = (krb5_int32) atol(*argv);
+             argc--; argv++;
+             if (!argc) usage(progname);
+-            now_timestamp = (krb5_timestamp) atol(*argv);
++            now_timestamp = (krb5_timestamp) atoll(*argv);
+             argc--; argv++;
+             if (!argc) usage(progname);
+             now_usec = (krb5_int32) atol(*argv);
+@@ -249,7 +249,7 @@ main(int argc, char **argv)
+             rcspec = *argv;
+             argc--; argv++;
+             if (!argc) usage(progname);
+-            now_timestamp = (krb5_timestamp) atol(*argv);
++            now_timestamp = (krb5_timestamp) atoll(*argv);
+             argc--; argv++;
+             if (!argc) usage(progname);
+             now_usec = (krb5_int32) atol(*argv);
+diff --git a/src/plugins/kdb/db2/lockout.c b/src/plugins/kdb/db2/lockout.c
+index 7d151b55b..3a4f41821 100644
+--- a/src/plugins/kdb/db2/lockout.c
++++ b/src/plugins/kdb/db2/lockout.c
+@@ -100,7 +100,7 @@ locked_check_p(krb5_context context,
+ 
+     /* If the entry was unlocked since the last failure, it's not locked. */
+     if (krb5_dbe_lookup_last_admin_unlock(context, entry, &unlock_time) == 0 &&
+-        entry->last_failed <= unlock_time)
++        !ts_after(entry->last_failed, unlock_time))
+         return FALSE;
+ 
+     if (max_fail == 0 || entry->fail_auth_count < max_fail)
+@@ -109,7 +109,7 @@ locked_check_p(krb5_context context,
+     if (lockout_duration == 0)
+         return TRUE; /* principal permanently locked */
+ 
+-    return (stamp < entry->last_failed + lockout_duration);
++    return ts_after(ts_incr(entry->last_failed, lockout_duration), stamp);
+ }
+ 
+ krb5_error_code
+@@ -200,13 +200,13 @@ krb5_db2_lockout_audit(krb5_context context,
+                 status == KRB5KRB_AP_ERR_BAD_INTEGRITY)) {
+         if (krb5_dbe_lookup_last_admin_unlock(context, entry,
+                                               &unlock_time) == 0 &&
+-            entry->last_failed <= unlock_time) {
++            !ts_after(entry->last_failed, unlock_time)) {
+             /* Reset fail_auth_count after administrative unlock. */
+             entry->fail_auth_count = 0;
+         }
+ 
+         if (failcnt_interval != 0 &&
+-            stamp > entry->last_failed + failcnt_interval) {
++            ts_after(stamp, ts_incr(entry->last_failed, failcnt_interval))) {
+             /* Reset fail_auth_count after failcnt_interval. */
+             entry->fail_auth_count = 0;
+         }
+diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
+index 7ba53f959..88a170495 100644
+--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
+@@ -1734,7 +1734,7 @@ getstringtime(krb5_timestamp epochtime)
+ {
+     struct tm           tme;
+     char                *strtime=NULL;
+-    time_t              posixtime = epochtime;
++    time_t              posixtime = ts2tt(epochtime);
+ 
+     strtime = calloc (50, 1);
+     if (strtime == NULL)
+diff --git a/src/plugins/kdb/ldap/libkdb_ldap/lockout.c b/src/plugins/kdb/ldap/libkdb_ldap/lockout.c
+index 0fc56c2fe..1088ecc5a 100644
+--- a/src/plugins/kdb/ldap/libkdb_ldap/lockout.c
++++ b/src/plugins/kdb/ldap/libkdb_ldap/lockout.c
+@@ -93,7 +93,7 @@ locked_check_p(krb5_context context,
+ 
+     /* If the entry was unlocked since the last failure, it's not locked. */
+     if (krb5_dbe_lookup_last_admin_unlock(context, entry, &unlock_time) == 0 &&
+-        entry->last_failed <= unlock_time)
++        !ts_after(entry->last_failed, unlock_time))
+         return FALSE;
+ 
+     if (max_fail == 0 || entry->fail_auth_count < max_fail)
+@@ -102,7 +102,7 @@ locked_check_p(krb5_context context,
+     if (lockout_duration == 0)
+         return TRUE; /* principal permanently locked */
+ 
+-    return (stamp < entry->last_failed + lockout_duration);
++    return ts_after(ts_incr(entry->last_failed, lockout_duration), stamp);
+ }
+ 
+ krb5_error_code
+@@ -196,14 +196,14 @@ krb5_ldap_lockout_audit(krb5_context context,
+                 status == KRB5KRB_AP_ERR_BAD_INTEGRITY)) {
+         if (krb5_dbe_lookup_last_admin_unlock(context, entry,
+                                               &unlock_time) == 0 &&
+-            entry->last_failed <= unlock_time) {
++            !ts_after(entry->last_failed, unlock_time)) {
+             /* Reset fail_auth_count after administrative unlock. */
+             entry->fail_auth_count = 0;
+             entry->mask |= KADM5_FAIL_AUTH_COUNT;
+         }
+ 
+         if (failcnt_interval != 0 &&
+-            stamp > entry->last_failed + failcnt_interval) {
++            ts_after(stamp, ts_incr(entry->last_failed, failcnt_interval))) {
+             /* Reset fail_auth_count after failcnt_interval */
+             entry->fail_auth_count = 0;
+             entry->mask |= KADM5_FAIL_AUTH_COUNT;
+diff --git a/src/windows/cns/tktlist.c b/src/windows/cns/tktlist.c
+index f2805f5cd..26e699fae 100644
+--- a/src/windows/cns/tktlist.c
++++ b/src/windows/cns/tktlist.c
+@@ -35,6 +35,8 @@
+ #include "cns.h"
+ #include "tktlist.h"
+ 
++#define ts2tt(t) (time_t)(uint32_t)(t)
++
+ /*
+  * Ticket information for a list line
+  */
+@@ -167,10 +169,10 @@ ticket_init_list (HWND hwnd)
+ 
+       ncred++;
+       strcpy (buf, "  ");
+-      strncat(buf, short_date (c.times.starttime - kwin_get_epoch()),
++      strncat(buf, short_date(ts2tt(c.times.starttime) - kwin_get_epoch()),
+ 	      sizeof(buf) - 1 - strlen(buf));
+       strncat(buf, "      ", sizeof(buf) - 1 - strlen(buf));
+-      strncat(buf, short_date (c.times.endtime - kwin_get_epoch()),
++      strncat(buf, short_date(ts2tt(c.times.endtime) - kwin_get_epoch()),
+ 	      sizeof(buf) - 1 - strlen(buf));
+       strncat(buf, "      ", sizeof(buf) - 1 - strlen(buf));
+ 
+@@ -192,8 +194,8 @@ ticket_init_list (HWND hwnd)
+ 	return -1;
+ 
+       lpinfo->ticket = TRUE;
+-      lpinfo->issue_time = c.times.starttime - kwin_get_epoch();
+-      lpinfo->lifetime = c.times.endtime - c.times.starttime;
++      lpinfo->issue_time = ts2tt(c.times.starttime) - kwin_get_epoch();
++      lpinfo->lifetime = ts2tt(c.times.endtime) - c.times.starttime;
+       strcpy(lpinfo->buf, buf);
+ 
+       rc = ListBox_AddItemData(hwnd, lpinfo);
+diff --git a/src/windows/include/leashwin.h b/src/windows/include/leashwin.h
+index 9577365a7..325dce2e9 100644
+--- a/src/windows/include/leashwin.h
++++ b/src/windows/include/leashwin.h
+@@ -111,9 +111,9 @@ struct TicketList {
+     TicketList *next;
+     char *service;
+     char *encTypes;
+-    krb5_timestamp issued;
+-    krb5_timestamp valid_until;
+-    krb5_timestamp renew_until;
++    time_t issued;
++    time_t valid_until;
++    time_t renew_until;
+     unsigned long flags;
+ };
+ 
+@@ -124,9 +124,9 @@ struct TICKETINFO {
+     char   *ccache_name;
+     TicketList *ticket_list;
+     int     btickets;                 /* Do we have tickets? */
+-    long    issued;                   /* The issue time */
+-    long    valid_until;              /* */
+-    long    renew_until;              /* The Renew time (k5 only) */
++    time_t  issued;                   /* The issue time */
++    time_t  valid_until;              /* */
++    time_t  renew_until;              /* The Renew time (k5 only) */
+     unsigned long flags;
+ };
+ 
+diff --git a/src/windows/leash/KrbListTickets.cpp b/src/windows/leash/KrbListTickets.cpp
+index beab0ea11..5dd37b05a 100644
+--- a/src/windows/leash/KrbListTickets.cpp
++++ b/src/windows/leash/KrbListTickets.cpp
+@@ -92,10 +92,10 @@ etype_string(krb5_enctype enctype)
+ static void
+ CredToTicketInfo(krb5_creds KRBv5Credentials, TICKETINFO *ticketinfo)
+ {
+-    ticketinfo->issued = KRBv5Credentials.times.starttime;
+-    ticketinfo->valid_until = KRBv5Credentials.times.endtime;
++    ticketinfo->issued = (DWORD)KRBv5Credentials.times.starttime;
++    ticketinfo->valid_until = (DWORD)KRBv5Credentials.times.endtime;
+     ticketinfo->renew_until = KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE ?
+-        KRBv5Credentials.times.renew_till : 0;
++        (DWORD)KRBv5Credentials.times.renew_till : (DWORD)0;
+     _tzset();
+     if ( ticketinfo->valid_until - time(0) <= 0L )
+         ticketinfo->btickets = EXPD_TICKETS;
+@@ -137,10 +137,10 @@ CredToTicketList(krb5_context ctx, krb5_creds KRBv5Credentials,
+         functionName = "calloc()";
+         goto cleanup;
+     }
+-    list->issued = KRBv5Credentials.times.starttime;
+-    list->valid_until = KRBv5Credentials.times.endtime;
++    list->issued = (DWORD)KRBv5Credentials.times.starttime;
++    list->valid_until = (DWORD)KRBv5Credentials.times.endtime;
+     if (KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE)
+-        list->renew_until = KRBv5Credentials.times.renew_till;
++        list->renew_until = (DWORD)KRBv5Credentials.times.renew_till;
+     else
+         list->renew_until = 0;
+ 
+diff --git a/src/windows/leash/LeashView.cpp b/src/windows/leash/LeashView.cpp
+index ef2a5a3e0..253ae3f06 100644
+--- a/src/windows/leash/LeashView.cpp
++++ b/src/windows/leash/LeashView.cpp
+@@ -229,22 +229,22 @@ static HFONT CreateBoldItalicFont(HFONT font)
+ 
+ bool change_icon_size = true;
+ 
+-void krb5TimestampToFileTime(krb5_timestamp t, LPFILETIME pft)
++void TimestampToFileTime(time_t t, LPFILETIME pft)
+ {
+     // Note that LONGLONG is a 64-bit value
+-    LONGLONG ll;
++    ULONGLONG ll;
+ 
+-    ll = Int32x32To64(t, 10000000) + 116444736000000000;
++    ll = UInt32x32To64((DWORD)t, 10000000) + 116444736000000000;
+     pft->dwLowDateTime = (DWORD)ll;
+     pft->dwHighDateTime = ll >> 32;
+ }
+ 
+ // allocate outstr
+-void krb5TimestampToLocalizedString(krb5_timestamp t, LPTSTR *outStr)
++void TimestampToLocalizedString(time_t t, LPTSTR *outStr)
+ {
+     FILETIME ft, lft;
+     SYSTEMTIME st;
+-    krb5TimestampToFileTime(t, &ft);
++    TimestampToFileTime(t, &ft);
+     FileTimeToLocalFileTime(&ft, &lft);
+     FileTimeToSystemTime(&lft, &st);
+     TCHAR timeFormat[80]; // 80 is max required for LOCALE_STIMEFORMAT
+@@ -1125,9 +1125,9 @@ void CLeashView::AddDisplayItem(CListCtrl &list,
+                                 CCacheDisplayData *elem,
+                                 int iItem,
+                                 char *principal,
+-                                long issued,
+-                                long valid_until,
+-                                long renew_until,
++                                time_t issued,
++                                time_t valid_until,
++                                time_t renew_until,
+                                 char *encTypes,
+                                 unsigned long flags,
+                                 char *ccache_name)
+@@ -1145,7 +1145,7 @@ void CLeashView::AddDisplayItem(CListCtrl &list,
+         if (issued == 0) {
+             list.SetItemText(iItem, iSubItem++, "Unknown");
+         } else {
+-            krb5TimestampToLocalizedString(issued, &localTimeStr);
++            TimestampToLocalizedString(issued, &localTimeStr);
+             list.SetItemText(iItem, iSubItem++, localTimeStr);
+         }
+     }
+@@ -1155,7 +1155,7 @@ void CLeashView::AddDisplayItem(CListCtrl &list,
+         } else if (valid_until < now) {
+             list.SetItemText(iItem, iSubItem++, "Expired");
+         } else if (renew_until) {
+-            krb5TimestampToLocalizedString(renew_until, &localTimeStr);
++            TimestampToLocalizedString(renew_until, &localTimeStr);
+             DurationToString(renew_until - now, &durationStr);
+             if (localTimeStr && durationStr) {
+                 _snprintf(tempStr, MAX_DURATION_STR, "%s %s", localTimeStr, durationStr);
+@@ -1172,7 +1172,7 @@ void CLeashView::AddDisplayItem(CListCtrl &list,
+         } else if (valid_until < now) {
+             list.SetItemText(iItem, iSubItem++, "Expired");
+         } else {
+-            krb5TimestampToLocalizedString(valid_until, &localTimeStr);
++            TimestampToLocalizedString(valid_until, &localTimeStr);
+             DurationToString(valid_until - now, &durationStr);
+             if (localTimeStr && durationStr) {
+                 _snprintf(tempStr, MAX_DURATION_STR, "%s %s", localTimeStr, durationStr);
+diff --git a/src/windows/leashdll/lshfunc.c b/src/windows/leashdll/lshfunc.c
+index 0f76cc334..8dafb7bed 100644
+--- a/src/windows/leashdll/lshfunc.c
++++ b/src/windows/leashdll/lshfunc.c
+@@ -2898,7 +2898,7 @@ static BOOL cc_have_tickets(krb5_context ctx, krb5_ccache cache)
+     _tzset();
+     while (!(code = pkrb5_cc_next_cred(ctx, cache, &cur, &creds))) {
+         if ((!pkrb5_is_config_principal(ctx, creds.server)) &&
+-            (creds.times.endtime - time(0) > 0))
++            ((time_t)(DWORD)creds.times.endtime - time(0) > 0))
+             have_tickets = TRUE;
+ 
+         pkrb5_free_cred_contents(ctx, &creds);
+diff --git a/src/windows/ms2mit/ms2mit.c b/src/windows/ms2mit/ms2mit.c
+index c3325034a..2b4373cc1 100644
+--- a/src/windows/ms2mit/ms2mit.c
++++ b/src/windows/ms2mit/ms2mit.c
+@@ -74,7 +74,7 @@ cc_has_tickets(krb5_context kcontext, krb5_ccache ccache, int *has_tickets)
+             break;
+ 
+         if (!krb5_is_config_principal(kcontext, creds.server) &&
+-            creds.times.endtime > now)
++            ts_after(creds.times.endtime, now))
+             *has_tickets = 1;
+ 
+         krb5_free_cred_contents(kcontext, &creds);
diff --git a/SOURCES/Prevent-KDC-unset-status-assertion-failures.patch b/SOURCES/Prevent-KDC-unset-status-assertion-failures.patch
new file mode 100644
index 0000000..084f55e
--- /dev/null
+++ b/SOURCES/Prevent-KDC-unset-status-assertion-failures.patch
@@ -0,0 +1,110 @@
+From 3b2376b47a9f1fc7dfd138d4ecc70e5d8897dc2b Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Thu, 13 Jul 2017 12:14:20 -0400
+Subject: [PATCH] Prevent KDC unset status assertion failures
+
+Assign status values if S4U2Self padata fails to decode, if an
+S4U2Proxy request uses invalid KDC options, or if an S4U2Proxy request
+uses an evidence ticket which does not match the canonicalized request
+server principal name.  Reported by Samuel Cabrero.
+
+If a status value is not assigned during KDC processing, default to
+"UNKNOWN_REASON" rather than failing an assertion.  This change will
+prevent future denial of service bugs due to similar mistakes, and
+will allow us to omit assigning status values for unlikely errors such
+as small memory allocation failures.
+
+CVE-2017-11368:
+
+In MIT krb5 1.7 and later, an authenticated attacker can cause an
+assertion failure in krb5kdc by sending an invalid S4U2Self or
+S4U2Proxy request.
+
+  CVSSv3 Vector: AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H/E:H/RL:O/RC:C
+
+ticket: 8599 (new)
+target_version: 1.15-next
+target_version: 1.14-next
+tags: pullup
+
+(cherry picked from commit ffb35baac6981f9e8914f8f3bffd37f284b85970)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/kdc/do_as_req.c  |  4 ++--
+ src/kdc/do_tgs_req.c |  3 ++-
+ src/kdc/kdc_util.c   | 10 ++++++++--
+ 3 files changed, 12 insertions(+), 5 deletions(-)
+
+diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
+index 241b05b40..f5cf8ad89 100644
+--- a/src/kdc/do_as_req.c
++++ b/src/kdc/do_as_req.c
+@@ -372,8 +372,8 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
+     did_log = 1;
+ 
+ egress:
+-    if (errcode != 0)
+-        assert (state->status != 0);
++    if (errcode != 0 && state->status == NULL)
++        state->status = "UNKNOWN_REASON";
+ 
+     au_state->status = state->status;
+     au_state->reply = &state->reply;
+diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
+index 4c722a4a3..0009a9319 100644
+--- a/src/kdc/do_tgs_req.c
++++ b/src/kdc/do_tgs_req.c
+@@ -829,7 +829,8 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt,
+     free(reply.enc_part.ciphertext.data);
+ 
+ cleanup:
+-    assert(status != NULL);
++    if (status == NULL)
++        status = "UNKNOWN_REASON";
+     if (reply_key)
+         krb5_free_keyblock(kdc_context, reply_key);
+     if (errcode)
+diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
+index 8cbdf2c5b..5455e2a67 100644
+--- a/src/kdc/kdc_util.c
++++ b/src/kdc/kdc_util.c
+@@ -1213,8 +1213,10 @@ kdc_process_for_user(kdc_realm_t *kdc_active_realm,
+     req_data.data = (char *)pa_data->contents;
+ 
+     code = decode_krb5_pa_for_user(&req_data, &for_user);
+-    if (code)
++    if (code) {
++        *status = "DECODE_PA_FOR_USER";
+         return code;
++    }
+ 
+     code = verify_for_user_checksum(kdc_context, tgs_session, for_user);
+     if (code) {
+@@ -1313,8 +1315,10 @@ kdc_process_s4u_x509_user(krb5_context context,
+     req_data.data = (char *)pa_data->contents;
+ 
+     code = decode_krb5_pa_s4u_x509_user(&req_data, s4u_x509_user);
+-    if (code)
++    if (code) {
++        *status = "DECODE_PA_S4U_X509_USER";
+         return code;
++    }
+ 
+     code = verify_s4u_x509_user_checksum(context,
+                                          tgs_subkey ? tgs_subkey :
+@@ -1617,6 +1621,7 @@ kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm,
+      * that is validated previously in validate_tgs_request().
+      */
+     if (request->kdc_options & (NON_TGT_OPTION | KDC_OPT_ENC_TKT_IN_SKEY)) {
++        *status = "INVALID_S4U2PROXY_OPTIONS";
+         return KRB5KDC_ERR_BADOPTION;
+     }
+ 
+@@ -1624,6 +1629,7 @@ kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm,
+     if (!krb5_principal_compare(kdc_context,
+                                 server->princ, /* after canon */
+                                 server_princ)) {
++        *status = "EVIDENCE_TICKET_MISMATCH";
+         return KRB5KDC_ERR_SERVER_NOMATCH;
+     }
+ 
diff --git a/SOURCES/Remove-incomplete-PKINIT-OCSP-support.patch b/SOURCES/Remove-incomplete-PKINIT-OCSP-support.patch
new file mode 100644
index 0000000..94315ea
--- /dev/null
+++ b/SOURCES/Remove-incomplete-PKINIT-OCSP-support.patch
@@ -0,0 +1,135 @@
+From 9ff3ed399f9a5bb0c6101a986798d80ecc7a1b92 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Mon, 31 Jul 2017 16:03:41 -0400
+Subject: [PATCH] Remove incomplete PKINIT OCSP support
+
+pkinit_kdc_ocsp is non-functional in the PKINIT OpenSSL crypto
+implementation, so remove most traces of it, including its man page
+entry.  If it is present in kdc.conf, error out of PKINIT
+initialization instead of silently ignoring the realm entirely.
+
+ticket: 8603 (new)
+(cherry picked from commit 3ff426b9048a8024e5c175256c63cd0ad0572320)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ doc/admin/conf_files/kdc_conf.rst            |  3 ---
+ src/man/kdc.conf.man                         |  3 ---
+ src/plugins/preauth/pkinit/pkinit.h          |  2 +-
+ src/plugins/preauth/pkinit/pkinit_identity.c | 11 -----------
+ src/plugins/preauth/pkinit/pkinit_srv.c      | 12 ++++++++++--
+ 5 files changed, 11 insertions(+), 20 deletions(-)
+
+diff --git a/doc/admin/conf_files/kdc_conf.rst b/doc/admin/conf_files/kdc_conf.rst
+index 13077ecf4..a4b2a5432 100644
+--- a/doc/admin/conf_files/kdc_conf.rst
++++ b/doc/admin/conf_files/kdc_conf.rst
+@@ -765,9 +765,6 @@ For information about the syntax of some of these options, see
+     pkinit is used to authenticate.  This option may be specified
+     multiple times.  (New in release 1.14.)
+ 
+-**pkinit_kdc_ocsp**
+-    Specifies the location of the KDC's OCSP.
+-
+ **pkinit_pool**
+     Specifies the location of intermediate certificates which may be
+     used by the KDC to complete the trust chain between a client's
+diff --git a/src/man/kdc.conf.man b/src/man/kdc.conf.man
+index 10b333c38..166e68f9a 100644
+--- a/src/man/kdc.conf.man
++++ b/src/man/kdc.conf.man
+@@ -886,9 +886,6 @@ Specifies an authentication indicator to include in the ticket if
+ pkinit is used to authenticate.  This option may be specified
+ multiple times.  (New in release 1.14.)
+ .TP
+-.B \fBpkinit_kdc_ocsp\fP
+-Specifies the location of the KDC\(aqs OCSP.
+-.TP
+ .B \fBpkinit_pool\fP
+ Specifies the location of intermediate certificates which may be
+ used by the KDC to complete the trust chain between a client\(aqs
+diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
+index 876db94c3..a49f3078e 100644
+--- a/src/plugins/preauth/pkinit/pkinit.h
++++ b/src/plugins/preauth/pkinit/pkinit.h
+@@ -73,6 +73,7 @@
+ #define KRB5_CONF_PKINIT_IDENTITIES             "pkinit_identities"
+ #define KRB5_CONF_PKINIT_IDENTITY               "pkinit_identity"
+ #define KRB5_CONF_PKINIT_KDC_HOSTNAME           "pkinit_kdc_hostname"
++/* pkinit_kdc_ocsp has been removed */
+ #define KRB5_CONF_PKINIT_KDC_OCSP               "pkinit_kdc_ocsp"
+ #define KRB5_CONF_PKINIT_POOL                   "pkinit_pool"
+ #define KRB5_CONF_PKINIT_REQUIRE_CRL_CHECKING   "pkinit_require_crl_checking"
+@@ -173,7 +174,6 @@ typedef struct _pkinit_identity_opts {
+     char **anchors;
+     char **intermediates;
+     char **crls;
+-    char *ocsp;
+     int  idtype;
+     char *cert_filename;
+     char *key_filename;
+diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c
+index 177a2cad8..a897efa25 100644
+--- a/src/plugins/preauth/pkinit/pkinit_identity.c
++++ b/src/plugins/preauth/pkinit/pkinit_identity.c
+@@ -125,7 +125,6 @@ pkinit_init_identity_opts(pkinit_identity_opts **idopts)
+     opts->anchors = NULL;
+     opts->intermediates = NULL;
+     opts->crls = NULL;
+-    opts->ocsp = NULL;
+ 
+     opts->cert_filename = NULL;
+     opts->key_filename = NULL;
+@@ -174,12 +173,6 @@ pkinit_dup_identity_opts(pkinit_identity_opts *src_opts,
+     if (retval)
+         goto cleanup;
+ 
+-    if (src_opts->ocsp != NULL) {
+-        newopts->ocsp = strdup(src_opts->ocsp);
+-        if (newopts->ocsp == NULL)
+-            goto cleanup;
+-    }
+-
+     if (src_opts->cert_filename != NULL) {
+         newopts->cert_filename = strdup(src_opts->cert_filename);
+         if (newopts->cert_filename == NULL)
+@@ -674,10 +667,6 @@ pkinit_identity_prompt(krb5_context context,
+         if (retval)
+             goto errout;
+     }
+-    if (idopts->ocsp != NULL) {
+-        retval = ENOTSUP;
+-        goto errout;
+-    }
+ 
+ errout:
+     return retval;
+diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
+index 731d14eb8..32ca122f2 100644
+--- a/src/plugins/preauth/pkinit/pkinit_srv.c
++++ b/src/plugins/preauth/pkinit/pkinit_srv.c
+@@ -1252,7 +1252,7 @@ static krb5_error_code
+ pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
+ {
+     krb5_error_code retval;
+-    char *eku_string = NULL;
++    char *eku_string = NULL, *ocsp_check = NULL;
+ 
+     pkiDebug("%s: entered for realm %s\n", __FUNCTION__, plgctx->realmname);
+     retval = pkinit_kdcdefault_string(context, plgctx->realmname,
+@@ -1287,7 +1287,15 @@ pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
+ 
+     pkinit_kdcdefault_string(context, plgctx->realmname,
+                              KRB5_CONF_PKINIT_KDC_OCSP,
+-                             &plgctx->idopts->ocsp);
++                             &ocsp_check);
++    if (ocsp_check != NULL) {
++        free(ocsp_check);
++        retval = ENOTSUP;
++        krb5_set_error_message(context, retval,
++                               _("OCSP is not supported: (realm: %s)"),
++                               plgctx->realmname);
++        goto errout;
++    }
+ 
+     pkinit_kdcdefault_integer(context, plgctx->realmname,
+                               KRB5_CONF_PKINIT_DH_MIN_BITS,
diff --git a/SOURCES/Use-krb5_timestamp-where-appropriate.patch b/SOURCES/Use-krb5_timestamp-where-appropriate.patch
new file mode 100644
index 0000000..084c698
--- /dev/null
+++ b/SOURCES/Use-krb5_timestamp-where-appropriate.patch
@@ -0,0 +1,328 @@
+From f181bf6ee4ff66489895a8c543521cbec253d1f9 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Wed, 17 May 2017 15:14:15 -0400
+Subject: [PATCH] Use krb5_timestamp where appropriate
+
+Where krb5_int32 is used to hold the number of seconds since the
+epoch, use krb5_timestamp instead.
+
+(cherry picked from commit ae25f6ec5558140a546db34fea389412d81c0631)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ src/clients/klist/klist.c          |  2 +-
+ src/include/k5-int.h               |  2 +-
+ src/kadmin/server/misc.c           |  2 +-
+ src/kdc/dispatch.c                 |  4 ++--
+ src/lib/kadm5/srv/server_acl.c     |  2 +-
+ src/lib/kadm5/srv/server_kdb.c     |  2 +-
+ src/lib/kadm5/srv/svr_principal.c  | 10 +++++-----
+ src/lib/krb5/krb/gen_save_subkey.c |  3 ++-
+ src/lib/krb5/krb/get_in_tkt.c      |  2 +-
+ src/lib/krb5/krb/init_ctx.c        |  3 ++-
+ src/lib/krb5/os/c_ustime.c         |  7 +++++--
+ src/lib/krb5/os/toffset.c          |  3 ++-
+ src/lib/krb5/os/trace.c            |  3 ++-
+ src/lib/krb5/os/ustime.c           |  3 ++-
+ src/lib/krb5/rcache/rc_dfl.c       | 10 +++++-----
+ src/tests/create/kdb5_mkdums.c     |  2 +-
+ 16 files changed, 34 insertions(+), 26 deletions(-)
+
+diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c
+index ffeecc394..4334415be 100644
+--- a/src/clients/klist/klist.c
++++ b/src/clients/klist/klist.c
+@@ -56,7 +56,7 @@ int show_adtype = 0, show_all = 0, list_all = 0, use_client_keytab = 0;
+ int show_config = 0;
+ char *defname;
+ char *progname;
+-krb5_int32 now;
++krb5_timestamp now;
+ unsigned int timestamp_width;
+ 
+ krb5_context kcontext;
+diff --git a/src/include/k5-int.h b/src/include/k5-int.h
+index 82ee20760..ed9c7bf75 100644
+--- a/src/include/k5-int.h
++++ b/src/include/k5-int.h
+@@ -721,7 +721,7 @@ krb5_error_code krb5int_c_copy_keyblock_contents(krb5_context context,
+                                                  const krb5_keyblock *from,
+                                                  krb5_keyblock *to);
+ 
+-krb5_error_code krb5_crypto_us_timeofday(krb5_int32 *, krb5_int32 *);
++krb5_error_code krb5_crypto_us_timeofday(krb5_timestamp *, krb5_int32 *);
+ 
+ /*
+  * End "los-proto.h"
+diff --git a/src/kadmin/server/misc.c b/src/kadmin/server/misc.c
+index a75b65a26..ba672d714 100644
+--- a/src/kadmin/server/misc.c
++++ b/src/kadmin/server/misc.c
+@@ -159,7 +159,7 @@ kadm5_ret_t
+ check_min_life(void *server_handle, krb5_principal principal,
+                char *msg_ret, unsigned int msg_len)
+ {
+-    krb5_int32                  now;
++    krb5_timestamp              now;
+     kadm5_ret_t                 ret;
+     kadm5_policy_ent_rec        pol;
+     kadm5_principal_ent_rec     princ;
+diff --git a/src/kdc/dispatch.c b/src/kdc/dispatch.c
+index 16a35d2be..4ecc23481 100644
+--- a/src/kdc/dispatch.c
++++ b/src/kdc/dispatch.c
+@@ -94,8 +94,8 @@ static void
+ reseed_random(krb5_context kdc_err_context)
+ {
+     krb5_error_code retval;
+-    krb5_int32 now, now_usec;
+-    krb5_int32 usec_difference;
++    krb5_timestamp now;
++    krb5_int32 now_usec, usec_difference;
+     krb5_data data;
+ 
+     retval = krb5_crypto_us_timeofday(&now, &now_usec);
+diff --git a/src/lib/kadm5/srv/server_acl.c b/src/lib/kadm5/srv/server_acl.c
+index 656dddff5..c2cf69169 100644
+--- a/src/lib/kadm5/srv/server_acl.c
++++ b/src/lib/kadm5/srv/server_acl.c
+@@ -375,7 +375,7 @@ kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp)
+     restriction_t              *rp;
+ {
+     krb5_error_code     code;
+-    krb5_int32          now;
++    krb5_timestamp      now;
+ 
+     DPRINT(DEBUG_CALLS, acl_debug_level,
+            ("* kadm5int_acl_impose_restrictions(..., *maskp=0x%08x, rp=0x%08x)\n",
+diff --git a/src/lib/kadm5/srv/server_kdb.c b/src/lib/kadm5/srv/server_kdb.c
+index 612553ba3..f4b8aef2b 100644
+--- a/src/lib/kadm5/srv/server_kdb.c
++++ b/src/lib/kadm5/srv/server_kdb.c
+@@ -365,7 +365,7 @@ kdb_put_entry(kadm5_server_handle_t handle,
+               krb5_db_entry *kdb, osa_princ_ent_rec *adb)
+ {
+     krb5_error_code ret;
+-    krb5_int32 now;
++    krb5_timestamp now;
+     XDR xdrs;
+     krb5_tl_data tl_data;
+ 
+diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c
+index f4a9a2ad2..0d4f0a632 100644
+--- a/src/lib/kadm5/srv/svr_principal.c
++++ b/src/lib/kadm5/srv/svr_principal.c
+@@ -296,7 +296,7 @@ kadm5_create_principal_3(void *server_handle,
+     osa_princ_ent_rec           adb;
+     kadm5_policy_ent_rec        polent;
+     krb5_boolean                have_polent = FALSE;
+-    krb5_int32                  now;
++    krb5_timestamp              now;
+     krb5_tl_data                *tl_data_tail;
+     unsigned int                ret;
+     kadm5_server_handle_t handle = server_handle;
+@@ -1322,7 +1322,7 @@ kadm5_chpass_principal_3(void *server_handle,
+                          int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
+                          char *password)
+ {
+-    krb5_int32                  now;
++    krb5_timestamp              now;
+     kadm5_policy_ent_rec        pol;
+     osa_princ_ent_rec           adb;
+     krb5_db_entry               *kdb;
+@@ -1544,7 +1544,7 @@ kadm5_randkey_principal_3(void *server_handle,
+ {
+     krb5_db_entry               *kdb;
+     osa_princ_ent_rec           adb;
+-    krb5_int32                  now;
++    krb5_timestamp              now;
+     kadm5_policy_ent_rec        pol;
+     int                         ret, last_pwd, n_new_keys;
+     krb5_boolean                have_pol = FALSE;
+@@ -1686,7 +1686,7 @@ kadm5_setv4key_principal(void *server_handle,
+ {
+     krb5_db_entry               *kdb;
+     osa_princ_ent_rec           adb;
+-    krb5_int32                  now;
++    krb5_timestamp              now;
+     kadm5_policy_ent_rec        pol;
+     krb5_keysalt                keysalt;
+     int                         i, kvno, ret;
+@@ -1888,7 +1888,7 @@ kadm5_setkey_principal_4(void *server_handle, krb5_principal principal,
+ {
+     krb5_db_entry *kdb;
+     osa_princ_ent_rec adb;
+-    krb5_int32 now;
++    krb5_timestamp now;
+     kadm5_policy_ent_rec pol;
+     krb5_key_data *new_key_data = NULL;
+     int i, j, ret, n_new_key_data = 0;
+diff --git a/src/lib/krb5/krb/gen_save_subkey.c b/src/lib/krb5/krb/gen_save_subkey.c
+index 61f36aa36..bc2c46d30 100644
+--- a/src/lib/krb5/krb/gen_save_subkey.c
++++ b/src/lib/krb5/krb/gen_save_subkey.c
+@@ -38,7 +38,8 @@ k5_generate_and_save_subkey(krb5_context context,
+        to guarantee randomness, but to make it less likely that multiple
+        sessions could pick the same subkey.  */
+     struct {
+-        krb5_int32 sec, usec;
++        krb5_timestamp sec;
++        krb5_int32 usec;
+     } rnd_data;
+     krb5_data d;
+     krb5_error_code retval;
+diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
+index 40aba1905..7178bd87b 100644
+--- a/src/lib/krb5/krb/get_in_tkt.c
++++ b/src/lib/krb5/krb/get_in_tkt.c
+@@ -1788,7 +1788,7 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out,
+                     krb5_creds *creds)
+ {
+     int i;
+-    krb5_int32 starttime;
++    krb5_timestamp starttime;
+     krb5_deltat lifetime;
+     krb5_get_init_creds_opt *opt;
+     krb5_error_code retval;
+diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
+index cf226fdba..4246c5dd2 100644
+--- a/src/lib/krb5/krb/init_ctx.c
++++ b/src/lib/krb5/krb/init_ctx.c
+@@ -139,7 +139,8 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
+     krb5_context ctx = 0;
+     krb5_error_code retval;
+     struct {
+-        krb5_int32 now, now_usec;
++        krb5_timestamp now;
++        krb5_int32 now_usec;
+         long pid;
+     } seed_data;
+     krb5_data seed;
+diff --git a/src/lib/krb5/os/c_ustime.c b/src/lib/krb5/os/c_ustime.c
+index 68fb381f4..f69f2ea4c 100644
+--- a/src/lib/krb5/os/c_ustime.c
++++ b/src/lib/krb5/os/c_ustime.c
+@@ -29,7 +29,10 @@
+ 
+ k5_mutex_t krb5int_us_time_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+ 
+-struct time_now { krb5_int32 sec, usec; };
++struct time_now {
++    krb5_timestamp sec;
++    krb5_int32 usec;
++};
+ 
+ #if defined(_WIN32)
+ 
+@@ -73,7 +76,7 @@ get_time_now(struct time_now *n)
+ static struct time_now last_time;
+ 
+ krb5_error_code
+-krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds)
++krb5_crypto_us_timeofday(krb5_timestamp *seconds, krb5_int32 *microseconds)
+ {
+     struct time_now now;
+     krb5_error_code err;
+diff --git a/src/lib/krb5/os/toffset.c b/src/lib/krb5/os/toffset.c
+index 37bc69f49..4bbcdde52 100644
+--- a/src/lib/krb5/os/toffset.c
++++ b/src/lib/krb5/os/toffset.c
+@@ -40,7 +40,8 @@ krb5_error_code KRB5_CALLCONV
+ krb5_set_real_time(krb5_context context, krb5_timestamp seconds, krb5_int32 microseconds)
+ {
+     krb5_os_context os_ctx = &context->os_context;
+-    krb5_int32 sec, usec;
++    krb5_timestamp sec;
++    krb5_int32 usec;
+     krb5_error_code retval;
+ 
+     retval = krb5_crypto_us_timeofday(&sec, &usec);
+diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
+index 74c315c90..8750b7650 100644
+--- a/src/lib/krb5/os/trace.c
++++ b/src/lib/krb5/os/trace.c
+@@ -340,7 +340,8 @@ krb5int_trace(krb5_context context, const char *fmt, ...)
+     va_list ap;
+     krb5_trace_info info;
+     char *str = NULL, *msg = NULL;
+-    krb5_int32 sec, usec;
++    krb5_timestamp sec;
++    krb5_int32 usec;
+ 
+     if (context == NULL || context->trace_callback == NULL)
+         return;
+diff --git a/src/lib/krb5/os/ustime.c b/src/lib/krb5/os/ustime.c
+index 1c1b571eb..a80fdf68c 100644
+--- a/src/lib/krb5/os/ustime.c
++++ b/src/lib/krb5/os/ustime.c
+@@ -40,7 +40,8 @@ krb5_error_code
+ k5_time_with_offset(krb5_timestamp offset, krb5_int32 offset_usec,
+                     krb5_timestamp *time_out, krb5_int32 *usec_out)
+ {
+-    krb5_int32 sec, usec;
++    krb5_timestamp sec;
++    krb5_int32 usec;
+     krb5_error_code retval;
+ 
+     retval = krb5_crypto_us_timeofday(&sec, &usec);
+diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c
+index 6b043844d..41ebf94da 100644
+--- a/src/lib/krb5/rcache/rc_dfl.c
++++ b/src/lib/krb5/rcache/rc_dfl.c
+@@ -93,7 +93,7 @@ cmp(krb5_donot_replay *old, krb5_donot_replay *new1, krb5_deltat t)
+ }
+ 
+ static int
+-alive(krb5_int32 mytime, krb5_donot_replay *new1, krb5_deltat t)
++alive(krb5_timestamp mytime, krb5_donot_replay *new1, krb5_deltat t)
+ {
+     if (mytime == 0)
+         return CMP_HOHUM; /* who cares? */
+@@ -129,7 +129,7 @@ struct authlist
+ 
+ static int
+ rc_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep,
+-         krb5_int32 now, krb5_boolean fromfile)
++         krb5_timestamp now, krb5_boolean fromfile)
+ {
+     struct dfl_data *t = (struct dfl_data *)id->data;
+     unsigned int rephash;
+@@ -536,7 +536,7 @@ krb5_rc_dfl_recover_locked(krb5_context context, krb5_rcache id)
+     krb5_error_code retval;
+     long max_size;
+     int expired_entries = 0;
+-    krb5_int32 now;
++    krb5_timestamp now;
+ 
+     if ((retval = krb5_rc_io_open(context, &t->d, t->name))) {
+         return retval;
+@@ -706,7 +706,7 @@ krb5_rc_dfl_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep)
+ {
+     krb5_error_code ret;
+     struct dfl_data *t;
+-    krb5_int32 now;
++    krb5_timestamp now;
+ 
+     ret = krb5_timeofday(context, &now);
+     if (ret)
+@@ -762,7 +762,7 @@ krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id)
+     struct authlist **qt;
+     struct authlist *r;
+     struct authlist *rt;
+-    krb5_int32 now;
++    krb5_timestamp now;
+ 
+     if (krb5_timestamp(context, &now))
+         now = 0;
+diff --git a/src/tests/create/kdb5_mkdums.c b/src/tests/create/kdb5_mkdums.c
+index 622f549f9..7c0666601 100644
+--- a/src/tests/create/kdb5_mkdums.c
++++ b/src/tests/create/kdb5_mkdums.c
+@@ -247,7 +247,7 @@ add_princ(context, str_newprinc)
+ 
+     {
+         /* Add mod princ to db entry */
+-        krb5_int32 now;
++        krb5_timestamp now;
+ 
+         retval = krb5_timeofday(context, &now);
+         if (retval) {
diff --git a/SOURCES/Use-the-canonical-client-principal-name-for-OTP.patch b/SOURCES/Use-the-canonical-client-principal-name-for-OTP.patch
index 2089450..e77b58a 100644
--- a/SOURCES/Use-the-canonical-client-principal-name-for-OTP.patch
+++ b/SOURCES/Use-the-canonical-client-principal-name-for-OTP.patch
@@ -1,4 +1,4 @@
-From 7c922602fe8fec44c55558daa32061cea86355cb Mon Sep 17 00:00:00 2001
+From 685698f8d33810ce085da4d75d1d8febe5323fd3 Mon Sep 17 00:00:00 2001
 From: Matt Rogers <mrogers@redhat.com>
 Date: Wed, 5 Apr 2017 16:48:55 -0400
 Subject: [PATCH] Use the canonical client principal name for OTP
@@ -9,6 +9,7 @@ callback) instead of the request client principal.
 
 ticket: 8571 (new)
 (cherry picked from commit 6411398e35e343cdc4d2d103b079c4d3b9031f7e)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/plugins/preauth/otp/main.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/SOURCES/krb5-1.11-kpasswdtest.patch b/SOURCES/krb5-1.11-kpasswdtest.patch
index 4657926..d58987e 100644
--- a/SOURCES/krb5-1.11-kpasswdtest.patch
+++ b/SOURCES/krb5-1.11-kpasswdtest.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Fri, 22 Apr 2016 10:03:40 -0400
 Subject: [PATCH] krb5-1.11-kpasswdtest.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/kadmin/testing/proto/krb5.conf.proto | 1 +
  1 file changed, 1 insertion(+)
diff --git a/SOURCES/krb5-1.11-run_user_0.patch b/SOURCES/krb5-1.11-run_user_0.patch
index 734341c..3093df6 100644
--- a/SOURCES/krb5-1.11-run_user_0.patch
+++ b/SOURCES/krb5-1.11-run_user_0.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Fri, 22 Apr 2016 10:03:22 -0400
 Subject: [PATCH] krb5-1.11-run_user_0.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/lib/krb5/ccache/cc_dir.c | 14 ++++++++++++++
  1 file changed, 14 insertions(+)
diff --git a/SOURCES/krb5-1.12-api.patch b/SOURCES/krb5-1.12-api.patch
index ae261d5..e040029 100644
--- a/SOURCES/krb5-1.12-api.patch
+++ b/SOURCES/krb5-1.12-api.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Fri, 22 Apr 2016 09:59:22 -0400
 Subject: [PATCH] krb5-1.12-api.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/lib/krb5/krb/princ_comp.c | 7 +++++++
  1 file changed, 7 insertions(+)
diff --git a/SOURCES/krb5-1.12-ksu-path.patch b/SOURCES/krb5-1.12-ksu-path.patch
index 7127916..cc4a074 100644
--- a/SOURCES/krb5-1.12-ksu-path.patch
+++ b/SOURCES/krb5-1.12-ksu-path.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Fri, 22 Apr 2016 09:57:25 -0400
 Subject: [PATCH] krb5-1.12-ksu-path.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/clients/ksu/Makefile.in | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SOURCES/krb5-1.12-ktany.patch b/SOURCES/krb5-1.12-ktany.patch
index a518ebf..bae76e2 100644
--- a/SOURCES/krb5-1.12-ktany.patch
+++ b/SOURCES/krb5-1.12-ktany.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Fri, 22 Apr 2016 09:58:00 -0400
 Subject: [PATCH] krb5-1.12-ktany.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/lib/krb5/keytab/Makefile.in |   3 +
  src/lib/krb5/keytab/kt_any.c    | 292 ++++++++++++++++++++++++++++++++++++++++
diff --git a/SOURCES/krb5-1.12.1-pam.patch b/SOURCES/krb5-1.12.1-pam.patch
index 87eeec9..7b8d6f5 100644
--- a/SOURCES/krb5-1.12.1-pam.patch
+++ b/SOURCES/krb5-1.12.1-pam.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Mon, 18 Apr 2016 15:57:38 -0400
 Subject: [PATCH] krb5-1.12.1-pam.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/aclocal.m4              |  67 ++++++++
  src/clients/ksu/Makefile.in |   8 +-
diff --git a/SOURCES/krb5-1.13-dirsrv-accountlock.patch b/SOURCES/krb5-1.13-dirsrv-accountlock.patch
index 1c7182a..268c859 100644
--- a/SOURCES/krb5-1.13-dirsrv-accountlock.patch
+++ b/SOURCES/krb5-1.13-dirsrv-accountlock.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Fri, 22 Apr 2016 10:01:15 -0400
 Subject: [PATCH] krb5-1.13-dirsrv-accountlock.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/aclocal.m4                                    |  9 +++++++++
  src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c      | 17 +++++++++++++++++
diff --git a/SOURCES/krb5-1.15-beta1-buildconf.patch b/SOURCES/krb5-1.15-beta1-buildconf.patch
index 958cfdf..71e122d 100644
--- a/SOURCES/krb5-1.15-beta1-buildconf.patch
+++ b/SOURCES/krb5-1.15-beta1-buildconf.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Wed, 4 Jan 2017 13:18:18 -0500
 Subject: [PATCH] krb5-1.15-beta1-buildconf.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/build-tools/krb5-config.in | 7 +++++++
  src/config/pre.in              | 2 +-
diff --git a/SOURCES/krb5-1.15-beta1-selinux-label.patch b/SOURCES/krb5-1.15-beta1-selinux-label.patch
index 0e79ce9..0cc22e8 100644
--- a/SOURCES/krb5-1.15-beta1-selinux-label.patch
+++ b/SOURCES/krb5-1.15-beta1-selinux-label.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Wed, 4 Jan 2017 13:17:28 -0500
 Subject: [PATCH] krb5-1.15-beta1-selinux-label.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/aclocal.m4                                     |  49 +++
  src/build-tools/krb5-config.in                     |   3 +-
diff --git a/SOURCES/krb5-1.3.1-dns.patch b/SOURCES/krb5-1.3.1-dns.patch
index 7f2cfdf..761722f 100644
--- a/SOURCES/krb5-1.3.1-dns.patch
+++ b/SOURCES/krb5-1.3.1-dns.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Fri, 22 Apr 2016 09:59:05 -0400
 Subject: [PATCH] krb5-1.3.1-dns.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/aclocal.m4 | 1 +
  1 file changed, 1 insertion(+)
diff --git a/SOURCES/krb5-1.9-debuginfo.patch b/SOURCES/krb5-1.9-debuginfo.patch
index c9a6499..e74a6a9 100644
--- a/SOURCES/krb5-1.9-debuginfo.patch
+++ b/SOURCES/krb5-1.9-debuginfo.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Fri, 22 Apr 2016 10:02:40 -0400
 Subject: [PATCH] krb5-1.9-debuginfo.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/kadmin/cli/Makefile.in                 | 5 +++++
  src/plugins/kdb/ldap/ldap_util/Makefile.in | 2 +-
diff --git a/SOURCES/krb5-kadm5clntmit_libsoname_version_downgrade.patch b/SOURCES/krb5-kadm5clntmit_libsoname_version_downgrade.patch
deleted file mode 100644
index c3a7290..0000000
--- a/SOURCES/krb5-kadm5clntmit_libsoname_version_downgrade.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From 6fbda5af22095ed1b8ca690bc8269cad04e25034 Mon Sep 17 00:00:00 2001
-From: Robbie Harwood <rharwood@redhat.com>
-Date: Fri, 22 Apr 2016 10:03:56 -0400
-Subject: [PATCH] krb5-kadm5clntmit_libsoname_version_downgrade.patch
-
-[rharwood@redhat.com: Adjust for 1.15]
----
- src/lib/kadm5/clnt/Makefile.in | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/lib/kadm5/clnt/Makefile.in b/src/lib/kadm5/clnt/Makefile.in
-index a180e85cd..b9aa7aa49 100644
---- a/src/lib/kadm5/clnt/Makefile.in
-+++ b/src/lib/kadm5/clnt/Makefile.in
-@@ -3,7 +3,7 @@ BUILDTOP=$(REL)..$(S)..$(S)..
- LOCALINCLUDES = -I$(BUILDTOP)/include/kadm5
- 
- LIBBASE=kadm5clnt_mit
--LIBMAJOR=11
-+LIBMAJOR=8
- LIBMINOR=0
- STOBJLISTS=../OBJS.ST OBJS.ST
- SHLIB_EXPDEPS=\
diff --git a/SOURCES/krb5-kvno-230379.patch b/SOURCES/krb5-kvno-230379.patch
index 0e7c5d5..2005ab9 100644
--- a/SOURCES/krb5-kvno-230379.patch
+++ b/SOURCES/krb5-kvno-230379.patch
@@ -3,6 +3,7 @@ From: Robbie Harwood <rharwood@redhat.com>
 Date: Fri, 22 Apr 2016 10:03:07 -0400
 Subject: [PATCH] krb5-kvno-230379.patch
 
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  src/kadmin/ktutil/ktutil.c    | 5 +++--
  src/lib/krb5/keytab/kt_file.c | 2 +-
diff --git a/SPECS/krb5.spec b/SPECS/krb5.spec
index 47b8fe9..e3a5ee2 100644
--- a/SPECS/krb5.spec
+++ b/SPECS/krb5.spec
@@ -7,13 +7,12 @@
 %define libsdocdir %{?_pkgdocdir:%(echo %{_pkgdocdir} | sed -e s,krb5,krb5-libs,g)}%{!?_pkgdocdir:%{_docdir}/%{name}-libs-%{version}}
 
 # Figure out where the default ccache lives and how we set it.
-%global configure_default_ccache_name 1
 %global configured_default_ccache_name KEYRING:persistent:%%{uid}
 
 Summary: The Kerberos network authentication system
 Name: krb5
 Version: 1.15.1
-Release: 8%{?dist}
+Release: 18%{?dist}
 
 # - Maybe we should explode from the now-available-to-everybody tarball instead?
 # http://web.mit.edu/kerberos/dist/krb5/1.13/krb5-1.13.2-signed.tar
@@ -64,11 +63,31 @@ Patch146: krb5-1.11-run_user_0.patch
 Patch147: krb5-1.11-kpasswdtest.patch
 Patch148: Improve-PKINIT-UPN-SAN-matching.patch
 Patch149: Deindent-crypto_retrieve_X509_sans.patch
-Patch151: krb5-kadm5clntmit_libsoname_version_downgrade.patch
 Patch152: Add-certauth-pluggable-interface.patch
 Patch153: Correct-error-handling-bug-in-prior-commit.patch
 Patch154: Add-the-client_name-kdcpreauth-callback.patch
 Patch155: Use-the-canonical-client-principal-name-for-OTP.patch
+Patch156: Remove-incomplete-PKINIT-OCSP-support.patch
+Patch157: Add-support-to-query-the-SSF-of-a-GSS-context.patch
+Patch158: Add-k5test-expected_msg-expected_trace.patch
+Patch159: Add-PKINIT-UPN-tests-to-t_pkinit.py.patch
+Patch160: Add-test-cert-generation-to-make-certs.sh.patch
+Patch161: Fix-make-certs.sh-for-OpenSSL-1.1.patch
+Patch162: Allow-clock-skew-in-krb5-gss_context_time.patch
+Patch163: Fix-in_clock_skew-and-use-it-in-AS-client-code.patch
+Patch164: Add-timestamp-helper-functions.patch
+Patch165: Make-timestamp-manipulations-y2038-safe.patch
+Patch166: Add-timestamp-tests.patch
+Patch167: Add-y2038-documentation.patch
+Patch168: Fix-more-time-manipulations-for-y2038.patch
+Patch169: Use-krb5_timestamp-where-appropriate.patch
+Patch170: Add-KDC-policy-pluggable-interface.patch
+Patch171: Fix-bugs-in-kdcpolicy-commit.patch
+Patch172: Prevent-KDC-unset-status-assertion-failures.patch
+Patch173: Convert-some-pkiDebug-messages-to-TRACE-macros.patch
+Patch174: Fix-certauth-built-in-module-returns.patch
+Patch175: Add-test-cert-with-no-extensions.patch
+Patch176: Expose-context-errors-in-pkinit_server_plugin_init.patch
 
 License: MIT
 URL: http://web.mit.edu/kerberos/www/
@@ -265,11 +284,31 @@ ONLY by kerberos itself. Do not depend on this package.
 %patch147 -p1 -b .krb5-1.11-kpasswdtest
 %patch148 -p1 -b .Improve-PKINIT-UPN-SAN-matching
 %patch149 -p1 -b .Deindent-crypto_retrieve_X509_sans
-%patch151 -p1 -b .krb5-kadm5clntmit_libsoname_version_downgrade
 %patch152 -p1 -b .Add-certauth-pluggable-interface
 %patch153 -p1 -b .Correct-error-handling-bug-in-prior-commit
 %patch154 -p1 -b .Add-the-client_name-kdcpreauth-callback
 %patch155 -p1 -b .Use-the-canonical-client-principal-name-for-OTP
+%patch156 -p1 -b .Remove-incomplete-PKINIT-OCSP-support
+%patch157 -p1 -b .Add-support-to-query-the-SSF-of-a-GSS-context
+%patch158 -p1 -b .Add-k5test-expected_msg-expected_trace
+%patch159 -p1 -b .Add-PKINIT-UPN-tests-to-t_pkinit.py
+%patch160 -p1 -b .Add-test-cert-generation-to-make-certs.sh
+%patch161 -p1 -b .Fix-make-certs.sh-for-OpenSSL-1.1
+%patch162 -p1 -b .Allow-clock-skew-in-krb5-gss_context_time
+%patch163 -p1 -b .Fix-in_clock_skew-and-use-it-in-AS-client-code
+%patch164 -p1 -b .Add-timestamp-helper-functions
+%patch165 -p1 -b .Make-timestamp-manipulations-y2038-safe
+%patch166 -p1 -b .Add-timestamp-tests
+%patch167 -p1 -b .Add-y2038-documentation
+%patch168 -p1 -b .Fix-more-time-manipulations-for-y2038
+%patch169 -p1 -b .Use-krb5_timestamp-where-appropriate
+%patch170 -p1 -b .Add-KDC-policy-pluggable-interface
+%patch171 -p1 -b .Fix-bugs-in-kdcpolicy-commit
+%patch172 -p1 -b .Prevent-KDC-unset-status-assertion-failures
+%patch173 -p1 -b .Convert-some-pkiDebug-messages-to-TRACE-macros
+%patch174 -p1 -b .Fix-certauth-built-in-module-returns
+%patch175 -p1 -b .Add-test-cert-with-no-extensions
+%patch176 -p1 -b .Expose-context-errors-in-pkinit_server_plugin_init
 
 ln NOTICE LICENSE
 
@@ -453,14 +492,12 @@ mkdir -m 755 -p $RPM_BUILD_ROOT/etc/gss/mech.d
 
 # If the default configuration needs to start specifying a default cache
 # location, add it now, then fixup the timestamp so that it looks the same.
-%if 0%{?configure_default_ccache_name}
 DEFCCNAME="%{configured_default_ccache_name}"; export DEFCCNAME
 awk '{print}
      /^# default_realm/{print " default_ccache_name =", ENVIRON["DEFCCNAME"]}' \
      %{SOURCE6} > $RPM_BUILD_ROOT/etc/krb5.conf
 touch -r %{SOURCE6} $RPM_BUILD_ROOT/etc/krb5.conf
 grep default_ccache_name $RPM_BUILD_ROOT/etc/krb5.conf
-%endif
 
 # Server init scripts (krb5kdc,kadmind,kpropd) and their sysconfig files.
 mkdir -p $RPM_BUILD_ROOT%{_unitdir}
@@ -557,51 +594,10 @@ rm -- "$RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/preauth/test.so"
 
 %post libs -p /sbin/ldconfig
 
-%if 0%{?configure_default_ccache_name}
-%triggerun libs -- krb5-libs < 1.11.3-16
-# Triggered roughly on the version where this logic was introduced.
-# Try to add a default_ccache_name to /etc/krb5.conf, removing the previous
-# default which we configured, if we find it.
-DEFCCNAME="%{configured_default_ccache_name}"; export DEFCCNAME
-tmpfile=`mktemp /etc/krb5.conf.XXXXXX`
-if test -z "$tmpfile" ; then
-	# Give up.
-	exit 0
-fi
-# Remove the default value we previously set.  Be very exact about it.
-if grep -q default_ccache_name /etc/krb5.conf ; then
-	sed -r '/^ default_ccache_name = DIR:\/run\/user\/%%\{uid\}\/krb5cc$/d' /etc/krb5.conf > "$tmpfile"
-	if test -s "$tmpfile" ; then
-		if touch -r /etc/krb5.conf "$tmpfile" ; then
-			cat "$tmpfile" > /etc/krb5.conf
-			touch -r "$tmpfile" /etc/krb5.conf
-		fi
-	fi
-fi
-# Add the new default value, unless there's one set.  Don't be too particular
-# about it.
-if ! grep -q default_ccache_name /etc/krb5.conf ; then
-	awk '
-	/^\[.*\]$/ {
-		if (libdefaults) {
-			print " default_ccache_name =", ENVIRON["DEFCCNAME"]
-			print ""
-		}
-		libdefaults=0;
-	}
-	/^\[libdefaults\]$/ { libdefaults=1; }
-	{ print }' /etc/krb5.conf > "$tmpfile"
-	if test -s "$tmpfile" ; then
-		if touch -r /etc/krb5.conf "$tmpfile" ; then
-			cat "$tmpfile" > /etc/krb5.conf
-			touch -r "$tmpfile" /etc/krb5.conf
-		fi
-	fi
+%triggerun libs -- krb5-libs < 1.15.1-13
+if ! grep -q 'includedir /etc/krb5.conf.d' /etc/krb5.conf ; then
+    sed -i '1i # Other applications require this directory to perform krb5 configuration.\nincludedir /etc/krb5.conf.d/\n' /etc/krb5.conf
 fi
-if test -n "$tmpfile" ; then
-	rm -f -- "$tmpfile"
-fi
-%endif
 
 %postun libs -p /sbin/ldconfig
 
@@ -817,6 +813,47 @@ exit 0
 %{_libdir}/libkadm5srv_mit.so.*
 
 %changelog
+* Tue Nov 28 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-18
+- Expose context errors in pkinit_server_plugin_init
+- Resolves: #1460089
+
+* Thu Nov 02 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-17
+- Drop certauth test changes that prevented runnig it
+- Resolves: #1498767
+
+* Thu Nov 02 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-16
+- Drop irrelevant DIR trigger logic
+- Resolves: #1431198
+
+* Thu Oct 05 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-15
+- Fix CVE-2017-7562 (certauth eku bypass)
+- Resolves: #1498767
+
+* Thu Oct 05 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-14
+- Fix CVE-2017-11368 (s4u2 request assertion failures)
+- Resolves: #1498768
+
+* Tue Oct 03 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-13
+- Force-add /etc/krb5.conf.d so we can guarantee it exists
+- Resolves: #1431198
+
+* Tue Sep 26 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-12
+- Add krb5 policy plugin interface
+- Remove soname downgrade
+- Resolves: #1462982
+
+* Wed Sep 06 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-11
+- Make t_certauth.py runnable
+- Resolves: #1443388
+
+* Tue Sep 05 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-10
+- Add context SSF query support
+- Resolves: #1472956
+
+* Thu Aug 17 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-9
+- Remove incomplete PKINIT OCSP support
+- Resolves: #1460089
+
 * Fri Apr 28 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-8
 - Add kprop.service argument file
 - Resolves: #1389073