From 95b80fb0b93bbc9909aab76cd2309bc4383a05bc Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Mon, 21 Aug 2017 18:43:49 +0000 Subject: [PATCH] Backport kdc policy plugin, but this time with dependencies --- Add-KDC-policy-pluggable-interface.patch | 31 +- Add-timestamp-helper-functions.patch | 80 + Add-timestamp-tests.patch | 599 ++++++ Add-y2038-documentation.patch | 59 + ...-clock-skew-in-krb5-gss_context_time.patch | 36 + Fix-bugs-in-kdcpolicy-commit.patch | 130 ++ ...ck_skew-and-use-it-in-AS-client-code.patch | 58 + Fix-more-time-manipulations-for-y2038.patch | 83 + Make-timestamp-manipulations-y2038-safe.patch | 1844 +++++++++++++++++ Use-krb5_timestamp-where-appropriate.patch | 327 +++ krb5.spec | 16 +- 11 files changed, 3245 insertions(+), 18 deletions(-) create mode 100644 Add-timestamp-helper-functions.patch create mode 100644 Add-timestamp-tests.patch create mode 100644 Add-y2038-documentation.patch create mode 100644 Allow-clock-skew-in-krb5-gss_context_time.patch create mode 100644 Fix-bugs-in-kdcpolicy-commit.patch create mode 100644 Fix-in_clock_skew-and-use-it-in-AS-client-code.patch create mode 100644 Fix-more-time-manipulations-for-y2038.patch create mode 100644 Make-timestamp-manipulations-y2038-safe.patch create mode 100644 Use-krb5_timestamp-where-appropriate.patch 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 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 . 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 +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 +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, ×); ++ assert(!ret); ++ ++ /* Current time is before starttime, but within clock skew. */ ++ times.starttime = 1100; ++ ret = krb5int_validate_times(context, ×); ++ assert(!ret); ++ ++ /* Current time is before starttime by more than clock skew. */ ++ times.starttime = 1400; ++ ret = krb5int_validate_times(context, ×); ++ 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, ×); ++ assert(!ret); ++ ++ /* Current time is after end time by more than clock skew. */ ++ times.endtime = 600; ++ ret = krb5int_validate_times(context, ×); ++ 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, ×); ++ assert(!ret); ++ ++ /* Current time is before starttime, but by less than clock skew. */ ++ times.starttime = BOUNDARY + 100; ++ ret = krb5int_validate_times(context, ×); ++ assert(!ret); ++ ++ /* Current time is before starttime by more than clock skew. */ ++ times.starttime = BOUNDARY + 250; ++ ret = krb5int_validate_times(context, ×); ++ 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, ×); ++ assert(!ret); ++ ++ /* Current time is after endtime by more than clock skew. */ ++ times.endtime = BOUNDARY - 300; ++ ret = krb5int_validate_times(context, ×); ++ 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 ++#include ++#include ++#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 +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 +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 +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 + + 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 +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 +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 +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 ++#include "k5-int.h" + #include + #include + #include +@@ -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 +-#include +-#include ++#include "k5-int.h" + + #include + #include "admin_internal.h" + +-#include + + #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 + #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 +-#include +-#include +-#include ++#include "k5-int.h" + #include +-#include +-#include +-#include +-#include + + #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, ¤ttime); + 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 +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 - 1.15.1-24 +- Backport kdc policy plugin, but this time with dependencies + * Mon Aug 21 2017 Robbie Harwood - 1.15.1-23 - Backport kdcpolicy interface