summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobbie Harwood <rharwood@redhat.com>2017-08-21 18:43:49 +0000
committerRobbie Harwood <rharwood@redhat.com>2017-08-22 19:11:06 +0000
commit95b80fb0b93bbc9909aab76cd2309bc4383a05bc (patch)
treeaca7f7f56649024f17c7908f46b1038114459f6b
parent48ad53c66e1e7883308ffe2ef099cc5925ebc619 (diff)
downloadkrb5-95b80fb0b93bbc9909aab76cd2309bc4383a05bc.tar.gz
krb5-95b80fb0b93bbc9909aab76cd2309bc4383a05bc.tar.xz
krb5-95b80fb0b93bbc9909aab76cd2309bc4383a05bc.zip
Backport kdc policy plugin, but this time with dependencies
-rw-r--r--Add-KDC-policy-pluggable-interface.patch31
-rw-r--r--Add-timestamp-helper-functions.patch80
-rw-r--r--Add-timestamp-tests.patch599
-rw-r--r--Add-y2038-documentation.patch59
-rw-r--r--Allow-clock-skew-in-krb5-gss_context_time.patch36
-rw-r--r--Fix-bugs-in-kdcpolicy-commit.patch130
-rw-r--r--Fix-in_clock_skew-and-use-it-in-AS-client-code.patch58
-rw-r--r--Fix-more-time-manipulations-for-y2038.patch83
-rw-r--r--Make-timestamp-manipulations-y2038-safe.patch1844
-rw-r--r--Use-krb5_timestamp-where-appropriate.patch327
-rw-r--r--krb5.spec16
11 files changed, 3245 insertions, 18 deletions
diff --git a/Add-KDC-policy-pluggable-interface.patch b/Add-KDC-policy-pluggable-interface.patch
index ded21a5..e43bc0d 100644
--- a/Add-KDC-policy-pluggable-interface.patch
+++ b/Add-KDC-policy-pluggable-interface.patch
@@ -1,4 +1,4 @@
-From 387ac75a30b679d6f0b0408b6c8e46ec2df30088 Mon Sep 17 00:00:00 2001
+From 648fa08747a5f2025f47e5b0bc2589f55a65218a 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
@@ -18,8 +18,7 @@ Also authored by Matt Rogers <mrogers@redhat.com>.
ticket: 8606 (new)
(cherry picked from commit d0969f6a8170344031ef58fd2a161190f1edfb96)
-[rharwood@redhat.com: plugin numbering for not having kadmin auth, and
-conflict in tests]
+[rharwood@redhat.com: mention but do not use kadm_auth]
---
doc/plugindev/index.rst | 1 +
doc/plugindev/kdcpolicy.rst | 24 +++
@@ -95,7 +94,7 @@ index 000000000..74f21f08f
+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 b0249778c..84856debb 100644
+index ad8565056..e47bddcb1 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -21,6 +21,7 @@ SUBDIRS=util include lib \
@@ -107,10 +106,10 @@ index b0249778c..84856debb 100644
plugins/preauth/pkinit \
plugins/preauth/test \
diff --git a/src/configure.in b/src/configure.in
-index 24f653f0d..a3881e93f 100644
+index 4ae2c07d5..ee1983043 100644
--- a/src/configure.in
+++ b/src/configure.in
-@@ -1467,6 +1467,7 @@ dnl ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test
+@@ -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
@@ -131,7 +130,7 @@ index 0239338a1..6a3fa8242 100644
$(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 06ca2b66d..a157ff03f 100644
+index ed9c7bf75..39ffb9568 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -1157,7 +1157,9 @@ struct plugin_interface {
@@ -294,7 +293,7 @@ index 000000000..c7592c5db
+
+#endif /* KRB5_POLICY_PLUGIN_H */
diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
-index a4bf91b1b..7636bfb52 100644
+index f85da6da6..f5cf8ad89 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)
@@ -312,7 +311,7 @@ index a4bf91b1b..7636bfb52 100644
* Find the server key
*/
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
-index 339259fd1..b2d5952bf 100644
+index ac5864603..0009a9319 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,
@@ -329,7 +328,7 @@ index 339259fd1..b2d5952bf 100644
* 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 30c501c67..f7212d7a3 100644
+index b710aefe4..5455e2a67 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,
@@ -354,7 +353,7 @@ index 30c501c67..f7212d7a3 100644
}
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
-index bcf05fc27..b499a04e1 100644
+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, ...)
@@ -735,10 +734,10 @@ index 6b000dc90..2a57b0a01 100644
#endif /* __KRB5_KDC_POLICY__ */
diff --git a/src/kdc/tgs_policy.c b/src/kdc/tgs_policy.c
-index a30cacc66..ea285376f 100644
+index d0f25d1b7..33cfbcd81 100644
--- a/src/kdc/tgs_policy.c
+++ b/src/kdc/tgs_policy.c
-@@ -374,11 +374,5 @@ validate_tgs_request(kdc_realm_t *kdc_active_realm,
+@@ -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);
@@ -919,13 +918,13 @@ index 000000000..9682ec74f
@@ -0,0 +1 @@
+kdcpolicy_test_initvt
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
-index 0e93d6b59..60e39dd14 100644
+index 2b3112537..a2093108b 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)
+@@ -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:
diff --git a/Add-timestamp-helper-functions.patch b/Add-timestamp-helper-functions.patch
new file mode 100644
index 0000000..0b36e0b
--- /dev/null
+++ b/Add-timestamp-helper-functions.patch
@@ -0,0 +1,80 @@
+From 38b7fbd7ee64a205c4dcfc345c30132e73f5b249 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)
+---
+ 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/Add-timestamp-tests.patch b/Add-timestamp-tests.patch
new file mode 100644
index 0000000..b71ac48
--- /dev/null
+++ b/Add-timestamp-tests.patch
@@ -0,0 +1,599 @@
+From 1b351445b4b938f54025728ba786f05ee82c47d1 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]
+---
+ 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 397e58962..98c8df25c 100755
+--- a/src/tests/gssapi/t_gssapi.py
++++ b/src/tests/gssapi/t_gssapi.py
+@@ -185,4 +185,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 44635b089..ffc043709 100755
+--- a/src/tests/t_kdb.py
++++ b/src/tests/t_kdb.py
+@@ -414,6 +414,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/Add-y2038-documentation.patch b/Add-y2038-documentation.patch
new file mode 100644
index 0000000..a87d6e4
--- /dev/null
+++ b/Add-y2038-documentation.patch
@@ -0,0 +1,59 @@
+From ebedc35a70f184030c4aab32e782fa2a8610cf73 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)
+---
+ 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/Allow-clock-skew-in-krb5-gss_context_time.patch b/Allow-clock-skew-in-krb5-gss_context_time.patch
new file mode 100644
index 0000000..99e9214
--- /dev/null
+++ b/Allow-clock-skew-in-krb5-gss_context_time.patch
@@ -0,0 +1,36 @@
+From 2944d7c0fcc8d3a87d0bb6f544b4a04c358df732 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)
+---
+ 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/Fix-bugs-in-kdcpolicy-commit.patch b/Fix-bugs-in-kdcpolicy-commit.patch
new file mode 100644
index 0000000..b4ccadb
--- /dev/null
+++ b/Fix-bugs-in-kdcpolicy-commit.patch
@@ -0,0 +1,130 @@
+From 7ab7253c617364ffe8facd870e286c5876e6c30f 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)
+---
+ 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/Fix-in_clock_skew-and-use-it-in-AS-client-code.patch b/Fix-in_clock_skew-and-use-it-in-AS-client-code.patch
new file mode 100644
index 0000000..2547891
--- /dev/null
+++ b/Fix-in_clock_skew-and-use-it-in-AS-client-code.patch
@@ -0,0 +1,58 @@
+From b0351efa57654f06477ab7540e6c0624e3a64f4e 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)
+---
+ 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/Fix-more-time-manipulations-for-y2038.patch b/Fix-more-time-manipulations-for-y2038.patch
new file mode 100644
index 0000000..c202b96
--- /dev/null
+++ b/Fix-more-time-manipulations-for-y2038.patch
@@ -0,0 +1,83 @@
+From c9fca85329f4b25509f83837239bf882841caccc 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)
+---
+ 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/Make-timestamp-manipulations-y2038-safe.patch b/Make-timestamp-manipulations-y2038-safe.patch
new file mode 100644
index 0000000..7c899ad
--- /dev/null
+++ b/Make-timestamp-manipulations-y2038-safe.patch
@@ -0,0 +1,1844 @@
+From 0c0fe06500401d694a4720544c7ed661275d819e 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)
+---
+ 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 a4bf91b1b..f85da6da6 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 339259fd1..ac5864603 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 30c501c67..b710aefe4 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);
+ }
+@@ -1771,9 +1771,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);
+@@ -1782,7 +1782,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);
+ }
+
+ /*
+@@ -1812,22 +1812,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 674d88bab..76efb71c6 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/Use-krb5_timestamp-where-appropriate.patch b/Use-krb5_timestamp-where-appropriate.patch
new file mode 100644
index 0000000..616ed67
--- /dev/null
+++ b/Use-krb5_timestamp-where-appropriate.patch
@@ -0,0 +1,327 @@
+From f0f0a503f58ed4f6ccf924751b356a70f515dd4b 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)
+---
+ 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/krb5.spec b/krb5.spec
index d826758..8d110be 100644
--- a/krb5.spec
+++ b/krb5.spec
@@ -18,7 +18,7 @@ Summary: The Kerberos network authentication system
Name: krb5
Version: 1.15.1
# for prerelease, should be e.g., 0.3.beta2%{?dist}
-Release: 23%{?dist}
+Release: 24%{?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
# - The sources below are stored in a lookaside cache. Upload with
@@ -81,7 +81,16 @@ Patch52: Fix-leaks-in-gss_inquire_cred_by_oid.patch
Patch53: Add-support-to-query-the-SSF-of-a-GSS-context.patch
Patch54: Prevent-KDC-unset-status-assertion-failures.patch
Patch55: Remove-incomplete-PKINIT-OCSP-support.patch
-Patch56: Add-KDC-policy-pluggable-interface.patch
+Patch56: Allow-clock-skew-in-krb5-gss_context_time.patch
+Patch57: Fix-in_clock_skew-and-use-it-in-AS-client-code.patch
+Patch58: Add-timestamp-helper-functions.patch
+Patch59: Make-timestamp-manipulations-y2038-safe.patch
+Patch60: Add-timestamp-tests.patch
+Patch61: Add-y2038-documentation.patch
+Patch62: Fix-more-time-manipulations-for-y2038.patch
+Patch63: Use-krb5_timestamp-where-appropriate.patch
+Patch64: Add-KDC-policy-pluggable-interface.patch
+Patch65: Fix-bugs-in-kdcpolicy-commit.patch
License: MIT
URL: http://web.mit.edu/kerberos/www/
@@ -733,6 +742,9 @@ exit 0
%{_libdir}/libkadm5srv_mit.so.*
%changelog
+* Mon Aug 21 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-24
+- Backport kdc policy plugin, but this time with dependencies
+
* Mon Aug 21 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-23
- Backport kdcpolicy interface