Blob Blame History Raw
From 7c671a869d1fc21b5154c035d568d5b5fd940783 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sat, 22 Apr 2017 12:52:17 -0400
Subject: [PATCH] Make timestamp manipulations y2038-safe

Wherever we manipulate krb5_timestamp values using arithmetic,
comparison operations, or conversion to time_t, use the new helper
functions in k5-int.h to ensure that the operations work after y2038
and do not exhibit undefined behavior.  (Relying on
implementation-defined conversion to signed values is okay as we test
that in configure.in.)

In printf format strings, use %u instead of signed types.  When
exporting creds with k5_json_array_fmt(), use a long long so that
timestamps after y2038 aren't marshalled as negative numbers.  When
parsing timestamps in test programs, use atoll() instead of atol() so
that positive timestamps after y2038 can be used as input.

In ksu and klist, make printtime() take a krb5_timestamp parameter to
avoid an unnecessary conversion to time_t and back.

As Leash does not use k5-int.h, use time_t values internally and
safely convert from libkrb5 timestamp values.

ticket: 8352
(cherry picked from commit a9cbbf0899f270fbb14f63ffbed1b6d542333641)
---
 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 ++--
 .../kdb/ldap/libkdb_ldap/ldap_principal2.c    |  2 +-
 src/plugins/kdb/ldap/libkdb_ldap/lockout.c    |  8 ++--
 src/windows/cns/tktlist.c                     | 10 +++--
 src/windows/include/leashwin.h                | 12 +++---
 src/windows/leash/KrbListTickets.cpp          | 12 +++---
 src/windows/leash/LeashView.cpp               | 22 +++++-----
 src/windows/leashdll/lshfunc.c                |  2 +-
 src/windows/ms2mit/ms2mit.c                   |  2 +-
 63 files changed, 230 insertions(+), 255 deletions(-)

diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
index f1cd1b73d..50065e32e 100644
--- a/src/clients/kinit/kinit.c
+++ b/src/clients/kinit/kinit.c
@@ -318,7 +318,7 @@ parse_options(argc, argv, opts)
                     fprintf(stderr, _("Bad start time value %s\n"), optarg);
                     errflg++;
                 } else {
-                    opts->starttime = abs_starttime - time(0);
+                    opts->starttime = ts_delta(abs_starttime, time(NULL));
                 }
             }
             break;
diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c
index ba19788a2..ffeecc394 100644
--- a/src/clients/klist/klist.c
+++ b/src/clients/klist/klist.c
@@ -72,7 +72,7 @@ void do_ccache_name (char *);
 int show_ccache (krb5_ccache);
 int check_ccache (krb5_ccache);
 void do_keytab (char *);
-void printtime (time_t);
+void printtime (krb5_timestamp);
 void one_addr (krb5_address *);
 void fillit (FILE *, unsigned int, int);
 
@@ -538,10 +538,10 @@ check_ccache(krb5_ccache cache)
     while (!(ret = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
         if (is_local_tgt(creds.server, &princ->realm)) {
             found_tgt = TRUE;
-            if (creds.times.endtime > now)
+            if (ts_after(creds.times.endtime, now))
                 found_current_tgt = TRUE;
         } else if (!krb5_is_config_principal(kcontext, creds.server) &&
-                   creds.times.endtime > now) {
+                   ts_after(creds.times.endtime, now)) {
             found_current_cred = TRUE;
         }
         krb5_free_cred_contents(kcontext, &creds);
@@ -623,19 +623,13 @@ flags_string(cred)
 }
 
 void
-printtime(tv)
-    time_t tv;
+printtime(krb5_timestamp ts)
 {
-    char timestring[BUFSIZ];
-    char fill;
+    char timestring[BUFSIZ], fill = ' ';
 
-    fill = ' ';
-    if (!krb5_timestamp_to_sfstring((krb5_timestamp) tv,
-                                    timestring,
-                                    timestamp_width+1,
-                                    &fill)) {
+    if (!krb5_timestamp_to_sfstring(ts, timestring, timestamp_width + 1,
+                                    &fill))
         printf("%s", timestring);
-    }
 }
 
 static void
diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c
index a0736f2da..236313b7b 100644
--- a/src/clients/ksu/ccache.c
+++ b/src/clients/ksu/ccache.c
@@ -278,11 +278,11 @@ krb5_error_code krb5_check_exp(context, tkt_time)
                 context->clockskew);
 
         fprintf(stderr,"krb5_check_exp: currenttime - endtime %d \n",
-                (currenttime - tkt_time.endtime ));
+                ts_delta(currenttime, tkt_time.endtime));
 
     }
 
-    if (currenttime - tkt_time.endtime > context->clockskew){
+    if (ts_delta(currenttime, tkt_time.endtime) > context->clockskew) {
         retval = KRB5KRB_AP_ERR_TKT_EXPIRED ;
         return retval;
     }
@@ -323,21 +323,11 @@ char *flags_string(cred)
     return(buf);
 }
 
-void printtime(tv)
-    time_t tv;
+void printtime(krb5_timestamp ts)
 {
-    char fmtbuf[18];
-    char fill;
-    krb5_timestamp tstamp;
+    char fmtbuf[18], fill = ' ';
 
-    /* XXXX ASSUMES sizeof(krb5_timestamp) >= sizeof(time_t) */
-    (void) localtime((time_t *)&tv);
-    tstamp = tv;
-    fill = ' ';
-    if (!krb5_timestamp_to_sfstring(tstamp,
-                                    fmtbuf,
-                                    sizeof(fmtbuf),
-                                    &fill))
+    if (!krb5_timestamp_to_sfstring(ts, fmtbuf, sizeof(fmtbuf), &fill))
         printf("%s", fmtbuf);
 }
 
diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h
index ee8e9d6a0..3bf0bd438 100644
--- a/src/clients/ksu/ksu.h
+++ b/src/clients/ksu/ksu.h
@@ -150,7 +150,7 @@ extern krb5_boolean krb5_find_princ_in_cred_list
 extern krb5_error_code krb5_find_princ_in_cache
 (krb5_context, krb5_ccache, krb5_principal, krb5_boolean *);
 
-extern void printtime (time_t);
+extern void printtime (krb5_timestamp);
 
 /* authorization.c */
 extern krb5_boolean fowner (FILE *, uid_t);
diff --git a/src/kadmin/cli/getdate.y b/src/kadmin/cli/getdate.y
index 4f0c56f7e..0a19c5648 100644
--- a/src/kadmin/cli/getdate.y
+++ b/src/kadmin/cli/getdate.y
@@ -118,7 +118,7 @@ static int getdate_yyerror (char *);
 
 
 #define EPOCH		1970
-#define EPOCH_END	2038 /* assumes 32 bits */
+#define EPOCH_END	2106 /* assumes unsigned 32-bit range */
 #define HOUR(x)		((time_t)(x) * 60)
 #define SECSPERDAY	(24L * 60L * 60L)
 
diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c
index c53c677a8..aee5c83b9 100644
--- a/src/kadmin/cli/kadmin.c
+++ b/src/kadmin/cli/kadmin.c
@@ -31,8 +31,7 @@
  * library */
 
 /* for "_" macro */
-#include "k5-platform.h"
-#include <krb5.h>
+#include "k5-int.h"
 #include <kadm5/admin.h>
 #include <adm_proto.h>
 #include <errno.h>
@@ -144,8 +143,8 @@ strdate(krb5_timestamp when)
 {
     struct tm *tm;
     static char out[40];
+    time_t lcltim = ts2tt(when);
 
-    time_t lcltim = when;
     tm = localtime(&lcltim);
     strftime(out, sizeof(out), "%a %b %d %H:%M:%S %Z %Y", tm);
     return out;
diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
index cad53cfbf..a6fc4ea77 100644
--- a/src/kadmin/dbutil/dump.c
+++ b/src/kadmin/dbutil/dump.c
@@ -379,11 +379,12 @@ k5beta7_common(krb5_context context, krb5_db_entry *entry,
     fprintf(fp, "princ\t%d\t%lu\t%d\t%d\t%d\t%s\t", (int)entry->len,
             (unsigned long)strlen(name), counter, (int)entry->n_key_data,
             (int)entry->e_length, name);
-    fprintf(fp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d", entry->attributes,
-            entry->max_life, entry->max_renewable_life, entry->expiration,
-            entry->pw_expiration,
-            omit_nra ? 0 : entry->last_success,
-            omit_nra ? 0 : entry->last_failed,
+    fprintf(fp, "%d\t%d\t%d\t%u\t%u\t%u\t%u\t%d", entry->attributes,
+            entry->max_life, entry->max_renewable_life,
+            (unsigned int)entry->expiration,
+            (unsigned int)entry->pw_expiration,
+            (unsigned int)(omit_nra ? 0 : entry->last_success),
+            (unsigned int)(omit_nra ? 0 : entry->last_failed),
             omit_nra ? 0 : entry->fail_auth_count);
 
     /* Write out tagged data. */
@@ -717,7 +718,7 @@ process_k5beta7_princ(krb5_context context, const char *fname, FILE *filep,
 {
     int retval, nread, i, j;
     krb5_db_entry *dbentry;
-    int t1, t2, t3, t4, t5, t6, t7;
+    int t1, t2, t3, t4;
     unsigned int u1, u2, u3, u4, u5;
     char *name = NULL;
     krb5_key_data *kp = NULL, *kd;
@@ -773,8 +774,8 @@ process_k5beta7_princ(krb5_context context, const char *fname, FILE *filep,
     }
 
     /* Get the fixed principal attributes */
-    nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
-                   &t1, &t2, &t3, &t4, &t5, &t6, &t7, &u1);
+    nread = fscanf(filep, "%d\t%d\t%d\t%u\t%u\t%d\t%d\t%d\t",
+                   &t1, &t2, &t3, &u1, &u2, &u3, &u4, &u5);
     if (nread != 8) {
         load_err(fname, *linenop, _("cannot read principal attributes"));
         goto fail;
@@ -782,11 +783,11 @@ process_k5beta7_princ(krb5_context context, const char *fname, FILE *filep,
     dbentry->attributes = t1;
     dbentry->max_life = t2;
     dbentry->max_renewable_life = t3;
-    dbentry->expiration = t4;
-    dbentry->pw_expiration = t5;
-    dbentry->last_success = t6;
-    dbentry->last_failed = t7;
-    dbentry->fail_auth_count = u1;
+    dbentry->expiration = u1;
+    dbentry->pw_expiration = u2;
+    dbentry->last_success = u3;
+    dbentry->last_failed = u4;
+    dbentry->fail_auth_count = u5;
     dbentry->mask = KADM5_LOAD | KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
         KADM5_MAX_LIFE | KADM5_MAX_RLIFE |
         KADM5_PRINC_EXPIRE_TIME | KADM5_LAST_SUCCESS |
diff --git a/src/kadmin/dbutil/kdb5_mkey.c b/src/kadmin/dbutil/kdb5_mkey.c
index 7df8cbc83..2efe3176e 100644
--- a/src/kadmin/dbutil/kdb5_mkey.c
+++ b/src/kadmin/dbutil/kdb5_mkey.c
@@ -44,8 +44,8 @@ static char *strdate(krb5_timestamp when)
 {
     struct tm *tm;
     static char out[40];
+    time_t lcltim = ts2tt(when);
 
-    time_t lcltim = when;
     tm = localtime(&lcltim);
     strftime(out, sizeof(out), "%a %b %d %H:%M:%S %Z %Y", tm);
     return out;
@@ -481,7 +481,7 @@ kdb5_use_mkey(int argc, char *argv[])
                  cur_actkvno != NULL;
                  prev_actkvno = cur_actkvno, cur_actkvno = cur_actkvno->next) {
 
-                if (new_actkvno->act_time < cur_actkvno->act_time) {
+                if (ts_after(cur_actkvno->act_time, new_actkvno->act_time)) {
                     if (prev_actkvno) {
                         prev_actkvno->next = new_actkvno;
                         new_actkvno->next = cur_actkvno;
@@ -499,7 +499,7 @@ kdb5_use_mkey(int argc, char *argv[])
         }
     }
 
-    if (actkvno_list->act_time > now) {
+    if (ts_after(actkvno_list->act_time, now)) {
         com_err(progname, EINVAL,
                 _("there must be one master key currently active"));
         exit_status++;
diff --git a/src/kadmin/dbutil/tabdump.c b/src/kadmin/dbutil/tabdump.c
index 69a3482ec..fb36b060a 100644
--- a/src/kadmin/dbutil/tabdump.c
+++ b/src/kadmin/dbutil/tabdump.c
@@ -148,7 +148,7 @@ write_date_iso(struct rec_args *args, krb5_timestamp when)
     struct tm *tm = NULL;
     struct rechandle *h = args->rh;
 
-    t = when;
+    t = ts2tt(when);
     tm = gmtime(&t);
     if (tm == NULL) {
         errno = EINVAL;
diff --git a/src/kadmin/testing/util/tcl_kadm5.c b/src/kadmin/testing/util/tcl_kadm5.c
index a4997c60c..9dde579ef 100644
--- a/src/kadmin/testing/util/tcl_kadm5.c
+++ b/src/kadmin/testing/util/tcl_kadm5.c
@@ -697,13 +697,13 @@ static Tcl_DString *unparse_principal_ent(kadm5_principal_ent_t princ,
     } else
         Tcl_DStringAppendElement(str, "null");
 
-    sprintf(buf, "%d", princ->princ_expire_time);
+    sprintf(buf, "%u", (unsigned int)princ->princ_expire_time);
     Tcl_DStringAppendElement(str, buf);
 
-    sprintf(buf, "%d", princ->last_pwd_change);
+    sprintf(buf, "%u", (unsigned int)princ->last_pwd_change);
     Tcl_DStringAppendElement(str, buf);
 
-    sprintf(buf, "%d", princ->pw_expiration);
+    sprintf(buf, "%u", (unsigned int)princ->pw_expiration);
     Tcl_DStringAppendElement(str, buf);
 
     sprintf(buf, "%d", princ->max_life);
@@ -722,7 +722,7 @@ static Tcl_DString *unparse_principal_ent(kadm5_principal_ent_t princ,
     } else
         Tcl_DStringAppendElement(str, "null");
 
-    sprintf(buf, "%d", princ->mod_date);
+    sprintf(buf, "%u", (unsigned int)princ->mod_date);
     Tcl_DStringAppendElement(str, buf);
 
     if (mask & KADM5_ATTRIBUTES) {
@@ -758,10 +758,10 @@ static Tcl_DString *unparse_principal_ent(kadm5_principal_ent_t princ,
     sprintf(buf, "%d", princ->max_renewable_life);
     Tcl_DStringAppendElement(str, buf);
 
-    sprintf(buf, "%d", princ->last_success);
+    sprintf(buf, "%u", (unsigned int)princ->last_success);
     Tcl_DStringAppendElement(str, buf);
 
-    sprintf(buf, "%d", princ->last_failed);
+    sprintf(buf, "%u", (unsigned int)princ->last_failed);
     Tcl_DStringAppendElement(str, buf);
 
     sprintf(buf, "%d", princ->fail_auth_count);
diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
index 712ccb794..59a39cd30 100644
--- a/src/kdc/do_as_req.c
+++ b/src/kdc/do_as_req.c
@@ -87,7 +87,7 @@ get_key_exp(krb5_db_entry *entry)
         return entry->pw_expiration;
     if (entry->pw_expiration == 0)
         return entry->expiration;
-    return min(entry->expiration, entry->pw_expiration);
+    return ts_min(entry->expiration, entry->pw_expiration);
 }
 
 /*
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 547a41441..aacd2f20d 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -500,12 +500,12 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt,
 
         old_starttime = enc_tkt_reply.times.starttime ?
             enc_tkt_reply.times.starttime : enc_tkt_reply.times.authtime;
-        old_life = enc_tkt_reply.times.endtime - old_starttime;
+        old_life = ts_delta(enc_tkt_reply.times.endtime, old_starttime);
 
         enc_tkt_reply.times.starttime = kdc_time;
         enc_tkt_reply.times.endtime =
-            min(header_ticket->enc_part2->times.renew_till,
-                kdc_time + old_life);
+            ts_min(header_ticket->enc_part2->times.renew_till,
+                   ts_incr(kdc_time, old_life));
     } else {
         /* not a renew request */
         enc_tkt_reply.times.starttime = kdc_time;
diff --git a/src/kdc/extern.c b/src/kdc/extern.c
index fe627494b..84b5c6ad5 100644
--- a/src/kdc/extern.c
+++ b/src/kdc/extern.c
@@ -37,6 +37,8 @@
 kdc_realm_t     **kdc_realmlist = (kdc_realm_t **) NULL;
 int             kdc_numrealms = 0;
 krb5_data empty_string = {0, 0, ""};
-krb5_timestamp kdc_infinity = KRB5_INT32_MAX; /* XXX */
 krb5_keyblock   psr_key;
 krb5_int32      max_dgram_reply_size = MAX_DGRAM_SIZE;
+
+/* With ts_after(), this is the largest timestamp value. */
+krb5_timestamp kdc_infinity = -1;
diff --git a/src/kdc/fast_util.c b/src/kdc/fast_util.c
index 9df940219..e05107ef3 100644
--- a/src/kdc/fast_util.c
+++ b/src/kdc/fast_util.c
@@ -607,7 +607,7 @@ kdc_fast_read_cookie(krb5_context context, struct kdc_request_state *state,
     ret = krb5_timeofday(context, &now);
     if (ret)
         goto cleanup;
-    if (now - COOKIE_LIFETIME > cookie->time) {
+    if (ts2tt(now) > cookie->time + COOKIE_LIFETIME) {
         /* Don't accept the cookie contents.  Only return an error if the
          * cookie is relevant to the request. */
         if (is_relevant(cookie->data, req->padata))
@@ -700,7 +700,7 @@ kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state,
     ret = krb5_timeofday(context, &now);
     if (ret)
         goto cleanup;
-    cookie.time = now;
+    cookie.time = ts2tt(now);
     cookie.data = contents;
     ret = encode_krb5_secure_cookie(&cookie, &der_cookie);
     if (ret)
diff --git a/src/kdc/kdc_log.c b/src/kdc/kdc_log.c
index 94a2a1c87..c044a3553 100644
--- a/src/kdc/kdc_log.c
+++ b/src/kdc/kdc_log.c
@@ -79,9 +79,9 @@ log_as_req(krb5_context context, const krb5_fulladdr *from,
         /* success */
         char rep_etypestr[128];
         rep_etypes2str(rep_etypestr, sizeof(rep_etypestr), reply);
-        krb5_klog_syslog(LOG_INFO, _("AS_REQ (%s) %s: ISSUE: authtime %d, %s, "
+        krb5_klog_syslog(LOG_INFO, _("AS_REQ (%s) %s: ISSUE: authtime %u, %s, "
                                      "%s for %s"),
-                         ktypestr, fromstring, authtime,
+                         ktypestr, fromstring, (unsigned int)authtime,
                          rep_etypestr, cname2, sname2);
     } else {
         /* fail */
@@ -156,10 +156,10 @@ log_tgs_req(krb5_context ctx, const krb5_fulladdr *from,
        name (useful), and doesn't log ktypestr (probably not
        important).  */
     if (errcode != KRB5KDC_ERR_SERVER_NOMATCH) {
-        krb5_klog_syslog(LOG_INFO, _("TGS_REQ (%s) %s: %s: authtime %d, %s%s "
+        krb5_klog_syslog(LOG_INFO, _("TGS_REQ (%s) %s: %s: authtime %u, %s%s "
                                      "%s for %s%s%s"),
-                         ktypestr, fromstring, status, authtime, rep_etypestr,
-                         !errcode ? "," : "", logcname, logsname,
+                         ktypestr, fromstring, status, (unsigned int)authtime,
+                         rep_etypestr, !errcode ? "," : "", logcname, logsname,
                          errcode ? ", " : "", errcode ? emsg : "");
         if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION))
             krb5_klog_syslog(LOG_INFO,
@@ -171,9 +171,9 @@ log_tgs_req(krb5_context ctx, const krb5_fulladdr *from,
                              logaltcname);
 
     } else
-        krb5_klog_syslog(LOG_INFO, _("TGS_REQ %s: %s: authtime %d, %s for %s, "
+        krb5_klog_syslog(LOG_INFO, _("TGS_REQ %s: %s: authtime %u, %s for %s, "
                                      "2nd tkt client %s"),
-                         fromstring, status, authtime,
+                         fromstring, status, (unsigned int)authtime,
                          logcname, logsname, logaltcname);
 
     /* OpenSolaris: audit_krb5kdc_tgs_req(...)  or
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index 29f9dbbf0..778a629e5 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -654,7 +654,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
     }
 
     /* The client must not be expired */
-    if (client.expiration && client.expiration < kdc_time) {
+    if (client.expiration && ts_after(kdc_time, client.expiration)) {
         *status = "CLIENT EXPIRED";
         if (vague_errors)
             return(KRB_ERR_GENERIC);
@@ -664,7 +664,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
 
     /* The client's password must not be expired, unless the server is
        a KRB5_KDC_PWCHANGE_SERVICE. */
-    if (client.pw_expiration && client.pw_expiration < kdc_time &&
+    if (client.pw_expiration && ts_after(kdc_time, client.pw_expiration) &&
         !isflagset(server.attributes, KRB5_KDB_PWCHANGE_SERVICE)) {
         *status = "CLIENT KEY EXPIRED";
         if (vague_errors)
@@ -674,7 +674,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
     }
 
     /* The server must not be expired */
-    if (server.expiration && server.expiration < kdc_time) {
+    if (server.expiration && ts_after(kdc_time, server.expiration)) {
         *status = "SERVICE EXPIRED";
         return(KDC_ERR_SERVICE_EXP);
     }
@@ -1765,9 +1765,9 @@ kdc_get_ticket_endtime(kdc_realm_t *kdc_active_realm,
     if (till == 0)
         till = kdc_infinity;
 
-    until = min(till, endtime);
+    until = ts_min(till, endtime);
 
-    life = until - starttime;
+    life = ts_delta(until, starttime);
 
     if (client != NULL && client->max_life != 0)
         life = min(life, client->max_life);
@@ -1776,7 +1776,7 @@ kdc_get_ticket_endtime(kdc_realm_t *kdc_active_realm,
     if (kdc_active_realm->realm_maxlife != 0)
         life = min(life, kdc_active_realm->realm_maxlife);
 
-    *out_endtime = starttime + life;
+    *out_endtime = ts_incr(starttime, life);
 }
 
 /*
@@ -1806,22 +1806,22 @@ kdc_get_ticket_renewtime(kdc_realm_t *realm, krb5_kdc_req *request,
     if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE))
         rtime = request->rtime ? request->rtime : kdc_infinity;
     else if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
-             tkt->times.endtime < request->till)
+             ts_after(request->till, tkt->times.endtime))
         rtime = request->till;
     else
         return;
 
     /* Truncate it to the allowable renewable time. */
     if (tgt != NULL)
-        rtime = min(rtime, tgt->times.renew_till);
+        rtime = ts_min(rtime, tgt->times.renew_till);
     max_rlife = min(server->max_renewable_life, realm->realm_maxrlife);
     if (client != NULL)
         max_rlife = min(max_rlife, client->max_renewable_life);
-    rtime = min(rtime, tkt->times.starttime + max_rlife);
+    rtime = ts_min(rtime, ts_incr(tkt->times.starttime, max_rlife));
 
     /* Make the ticket renewable if the truncated requested time is larger than
      * the ticket end time. */
-    if (rtime > tkt->times.endtime) {
+    if (ts_after(rtime, tkt->times.endtime)) {
         setflag(tkt->flags, TKT_FLG_RENEWABLE);
         tkt->times.renew_till = rtime;
     }
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index bcf05fc27..672f94380 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -452,6 +452,8 @@ struct krb5_kdcpreauth_rock_st {
 #define max(a, b)       ((a) > (b) ? (a) : (b))
 #endif
 
+#define ts_min(a, b) (ts_after(a, b) ? (b) : (a))
+
 #define ADDRTYPE2FAMILY(X)                                              \
     ((X) == ADDRTYPE_INET6 ? AF_INET6 : (X) == ADDRTYPE_INET ? AF_INET : -1)
 
diff --git a/src/kdc/replay.c b/src/kdc/replay.c
index 8da7ac19a..fab39cf88 100644
--- a/src/kdc/replay.c
+++ b/src/kdc/replay.c
@@ -61,7 +61,7 @@ static size_t total_size = 0;
 static krb5_ui_4 seed;
 
 #define STALE_TIME      (2*60)            /* two minutes */
-#define STALE(ptr, now) (abs((ptr)->timein - (now)) >= STALE_TIME)
+#define STALE(ptr, now) (labs(ts_delta((ptr)->timein, now)) >= STALE_TIME)
 
 /* Return x rotated to the left by r bits. */
 static inline krb5_ui_4
diff --git a/src/kdc/tgs_policy.c b/src/kdc/tgs_policy.c
index a30cacc66..d0f25d1b7 100644
--- a/src/kdc/tgs_policy.c
+++ b/src/kdc/tgs_policy.c
@@ -186,7 +186,7 @@ static int
 check_tgs_svc_time(krb5_kdc_req *req, krb5_db_entry server, krb5_ticket *tkt,
                    krb5_timestamp kdc_time, const char **status)
 {
-    if (server.expiration && server.expiration < kdc_time) {
+    if (server.expiration && ts_after(kdc_time, server.expiration)) {
         *status = "SERVICE EXPIRED";
         return KDC_ERR_SERVICE_EXP;
     }
@@ -222,7 +222,7 @@ check_tgs_times(krb5_kdc_req *req, krb5_ticket_times *times,
        KDC time. */
     if (req->kdc_options & KDC_OPT_VALIDATE) {
         starttime = times->starttime ? times->starttime : times->authtime;
-        if (starttime > kdc_time) {
+        if (ts_after(starttime, kdc_time)) {
             *status = "NOT_YET_VALID";
             return KRB_AP_ERR_TKT_NYV;
         }
@@ -231,7 +231,8 @@ check_tgs_times(krb5_kdc_req *req, krb5_ticket_times *times,
      * Check the renew_till time.  The endtime was already
      * been checked in the initial authentication check.
      */
-    if ((req->kdc_options & KDC_OPT_RENEW) && times->renew_till < kdc_time) {
+    if ((req->kdc_options & KDC_OPT_RENEW) &&
+        ts_after(kdc_time, times->renew_till)) {
         *status = "TKT_EXPIRED";
         return KRB_AP_ERR_TKT_EXPIRED;
     }
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 580d08cbf..06967aa27 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -351,8 +351,10 @@ kg_accept_dce(minor_status, context_handle, verifier_cred_handle,
     if (mech_type)
         *mech_type = ctx->mech_used;
 
-    if (time_rec)
-        *time_rec = ctx->krb_times.endtime + ctx->k5_context->clockskew - now;
+    if (time_rec) {
+        *time_rec = ts_delta(ctx->krb_times.endtime, now) +
+            ctx->k5_context->clockskew;
+    }
 
     /* Never return GSS_C_DELEG_FLAG since we don't support DCE credential
      * delegation yet. */
@@ -1146,7 +1148,7 @@ kg_accept_krb5(minor_status, context_handle,
     /* Add the maximum allowable clock skew as a grace period for context
      * expiration, just as we do for the ticket. */
     if (time_rec)
-        *time_rec = ctx->krb_times.endtime + context->clockskew - now;
+        *time_rec = ts_delta(ctx->krb_times.endtime, now) + context->clockskew;
 
     if (ret_flags)
         *ret_flags = ctx->gss_flags;
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
index 03ee25ec1..362ba9d86 100644
--- a/src/lib/gssapi/krb5/acquire_cred.c
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -550,7 +550,7 @@ set_refresh_time(krb5_context context, krb5_ccache ccache,
     char buf[128];
     krb5_data d;
 
-    snprintf(buf, sizeof(buf), "%ld", (long)refresh_time);
+    snprintf(buf, sizeof(buf), "%u", (unsigned int)ts2tt(refresh_time));
     d = string2data(buf);
     (void)krb5_cc_set_config(context, ccache, NULL, KRB5_CC_CONF_REFRESH_TIME,
                              &d);
@@ -566,8 +566,9 @@ kg_cred_time_to_refresh(krb5_context context, krb5_gss_cred_id_rec *cred)
 
     if (krb5_timeofday(context, &now))
         return FALSE;
-    if (cred->refresh_time != 0 && now >= cred->refresh_time) {
-        set_refresh_time(context, cred->ccache, cred->refresh_time + 30);
+    if (cred->refresh_time != 0 && !ts_after(cred->refresh_time, now)) {
+        set_refresh_time(context, cred->ccache,
+                         ts_incr(cred->refresh_time, 30));
         return TRUE;
     }
     return FALSE;
@@ -586,7 +587,8 @@ kg_cred_set_initial_refresh(krb5_context context, krb5_gss_cred_id_rec *cred,
         return;
 
     /* Make a note to refresh these when they are halfway to expired. */
-    refresh = times->starttime + (times->endtime - times->starttime) / 2;
+    refresh = ts_incr(times->starttime,
+                      ts_delta(times->endtime, times->starttime) / 2);
     set_refresh_time(context, cred->ccache, refresh);
 }
 
@@ -848,7 +850,8 @@ acquire_cred_context(krb5_context context, OM_uint32 *minor_status,
                                   GSS_C_NO_NAME);
             if (GSS_ERROR(ret))
                 goto error_out;
-            *time_rec = (cred->expire > now) ? (cred->expire - now) : 0;
+            *time_rec = ts_after(cred->expire, now) ?
+                ts_delta(cred->expire, now) : 0;
             k5_mutex_unlock(&cred->lock);
         }
     }
diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c
index 450593288..1fdb5a16f 100644
--- a/src/lib/gssapi/krb5/context_time.c
+++ b/src/lib/gssapi/krb5/context_time.c
@@ -51,7 +51,7 @@ krb5_gss_context_time(minor_status, context_handle, time_rec)
         return(GSS_S_FAILURE);
     }
 
-    lifetime = ctx->krb_times.endtime - now;
+    lifetime = ts_delta(ctx->krb_times.endtime, now);
     if (!ctx->initiate)
         lifetime += ctx->k5_context->clockskew;
     if (lifetime <= 0) {
diff --git a/src/lib/gssapi/krb5/export_cred.c b/src/lib/gssapi/krb5/export_cred.c
index 652b2604b..8054e4a77 100644
--- a/src/lib/gssapi/krb5/export_cred.c
+++ b/src/lib/gssapi/krb5/export_cred.c
@@ -410,10 +410,11 @@ json_kgcred(krb5_context context, krb5_gss_cred_id_t cred,
     if (ret)
         goto cleanup;
 
-    ret = k5_json_array_fmt(&array, "ivvbbvvvvbiivs", cred->usage, name, imp,
+    ret = k5_json_array_fmt(&array, "ivvbbvvvvbLLvs", cred->usage, name, imp,
                             cred->default_identity, cred->iakerb_mech, keytab,
                             rcache, ccache, ckeytab, cred->have_tgt,
-                            cred->expire, cred->refresh_time, etypes,
+                            (long long)ts2tt(cred->expire),
+                            (long long)ts2tt(cred->refresh_time), etypes,
                             cred->password);
     if (ret)
         goto cleanup;
diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c
index 2dc4d0c1a..bb1072fe4 100644
--- a/src/lib/gssapi/krb5/iakerb.c
+++ b/src/lib/gssapi/krb5/iakerb.c
@@ -494,7 +494,7 @@ iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx,
         if (code != 0)
             goto cleanup;
 
-        creds.times.endtime = now + time_req;
+        creds.times.endtime = ts_incr(now, time_req);
     }
 
     if (cred->name->ad_context != NULL) {
@@ -669,7 +669,7 @@ iakerb_get_initial_state(iakerb_ctx_id_t ctx,
         if (code != 0)
             goto cleanup;
 
-        in_creds.times.endtime = now + time_req;
+        in_creds.times.endtime = ts_incr(now, time_req);
     }
 
     /* Make an AS request if we have no creds or it's time to refresh them. */
diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
index 70f7955ae..8e5cc37fb 100644
--- a/src/lib/gssapi/krb5/init_sec_context.c
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -214,7 +214,8 @@ static krb5_error_code get_credentials(context, cred, server, now,
      * boundaries) because accept_sec_context code is also similarly
      * non-forgiving.
      */
-    if (!krb5_gss_dbg_client_expcreds && result_creds->times.endtime < now) {
+    if (!krb5_gss_dbg_client_expcreds &&
+        ts_after(now, result_creds->times.endtime)) {
         code = KRB5KRB_AP_ERR_TKT_EXPIRED;
         goto cleanup;
     }
@@ -575,7 +576,7 @@ kg_new_connection(
     if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
         ctx->krb_times.endtime = 0;
     } else {
-        ctx->krb_times.endtime = now + time_req;
+        ctx->krb_times.endtime = ts_incr(now, time_req);
     }
 
     if ((code = kg_duplicate_name(context, cred->name, &ctx->here)))
@@ -659,7 +660,7 @@ kg_new_connection(
     if (time_rec) {
         if ((code = krb5_timeofday(context, &now)))
             goto cleanup;
-        *time_rec = ctx->krb_times.endtime - now;
+        *time_rec = ts_delta(ctx->krb_times.endtime, now);
     }
 
     /* set the other returns */
@@ -873,7 +874,7 @@ mutual_auth(
     if (time_rec) {
         if ((code = krb5_timeofday(context, &now)))
             goto fail;
-        *time_rec = ctx->krb_times.endtime - now;
+        *time_rec = ts_delta(ctx->krb_times.endtime, now);
     }
 
     if (ret_flags)
diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c
index d2e466e60..cac024da1 100644
--- a/src/lib/gssapi/krb5/inq_context.c
+++ b/src/lib/gssapi/krb5/inq_context.c
@@ -120,7 +120,7 @@ krb5_gss_inquire_context(minor_status, context_handle, initiator_name,
 
         /* Add the maximum allowable clock skew as a grace period for context
          * expiration, just as we do for the ticket during authentication. */
-        lifetime = ctx->krb_times.endtime - now;
+        lifetime = ts_delta(ctx->krb_times.endtime, now);
         if (!ctx->initiate)
             lifetime += context->clockskew;
         if (lifetime < 0)
diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c
index 4e35a0563..e662ae53a 100644
--- a/src/lib/gssapi/krb5/inq_cred.c
+++ b/src/lib/gssapi/krb5/inq_cred.c
@@ -130,8 +130,9 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
         goto fail;
     }
 
-    if (cred->expire > 0) {
-        if ((lifetime = cred->expire - now) < 0)
+    if (cred->expire != 0) {
+        lifetime = ts_delta(cred->expire, now);
+        if (lifetime < 0)
             lifetime = 0;
     }
     else
diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
index ff1c310bc..10848c1df 100644
--- a/src/lib/gssapi/krb5/s4u_gss_glue.c
+++ b/src/lib/gssapi/krb5/s4u_gss_glue.c
@@ -284,7 +284,7 @@ kg_compose_deleg_cred(OM_uint32 *minor_status,
         if (code != 0)
             goto cleanup;
 
-        *time_rec = cred->expire - now;
+        *time_rec = ts_delta(cred->expire, now);
     }
 
     major_status = GSS_S_COMPLETE;
diff --git a/src/lib/kadm5/chpass_util.c b/src/lib/kadm5/chpass_util.c
index 408b0eb31..1680a5504 100644
--- a/src/lib/kadm5/chpass_util.c
+++ b/src/lib/kadm5/chpass_util.c
@@ -4,15 +4,11 @@
  */
 
 
-#include "autoconf.h"
-#include <stdio.h>
-#include <time.h>
-#include <string.h>
+#include "k5-int.h"
 
 #include <kadm5/admin.h>
 #include "admin_internal.h"
 
-#include <krb5.h>
 
 #define string_text error_message
 
@@ -218,7 +214,7 @@ kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle,
         time_t until;
         char *time_string, *ptr;
 
-        until = princ_ent.last_pwd_change + policy_ent.pw_min_life;
+        until = ts_incr(princ_ent.last_pwd_change, policy_ent.pw_min_life);
 
         time_string = ctime(&until);
         if (*(ptr = &time_string[strlen(time_string)-1]) == '\n')
diff --git a/src/lib/kadm5/srv/server_acl.c b/src/lib/kadm5/srv/server_acl.c
index 59ed0b975..656dddff5 100644
--- a/src/lib/kadm5/srv/server_acl.c
+++ b/src/lib/kadm5/srv/server_acl.c
@@ -408,13 +408,14 @@ kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp)
     }
     if (rp->mask & KADM5_PRINC_EXPIRE_TIME) {
         if (!(*maskp & KADM5_PRINC_EXPIRE_TIME)
-            || (recp->princ_expire_time > (now + rp->princ_lifetime)))
+            || ts_after(recp->princ_expire_time,
+                        ts_incr(now, rp->princ_lifetime)))
             recp->princ_expire_time = now + rp->princ_lifetime;
         *maskp |= KADM5_PRINC_EXPIRE_TIME;
     }
     if (rp->mask & KADM5_PW_EXPIRATION) {
         if (!(*maskp & KADM5_PW_EXPIRATION)
-            || (recp->pw_expiration > (now + rp->pw_lifetime)))
+            || ts_after(recp->pw_expiration, ts_incr(now, rp->pw_lifetime)))
             recp->pw_expiration = now + rp->pw_lifetime;
         *maskp |= KADM5_PW_EXPIRATION;
     }
diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c
index 0640b47c4..f4a9a2ad2 100644
--- a/src/lib/kadm5/srv/svr_principal.c
+++ b/src/lib/kadm5/srv/svr_principal.c
@@ -400,7 +400,7 @@ kadm5_create_principal_3(void *server_handle,
     kdb->pw_expiration = 0;
     if (have_polent) {
         if(polent.pw_max_life)
-            kdb->pw_expiration = now + polent.pw_max_life;
+            kdb->pw_expiration = ts_incr(now, polent.pw_max_life);
         else
             kdb->pw_expiration = 0;
     }
@@ -612,7 +612,7 @@ kadm5_modify_principal(void *server_handle,
                                                   &(kdb->pw_expiration));
             if (ret)
                 goto done;
-            kdb->pw_expiration += pol.pw_max_life;
+            kdb->pw_expiration = ts_incr(kdb->pw_expiration, pol.pw_max_life);
         } else {
             kdb->pw_expiration = 0;
         }
@@ -1445,7 +1445,7 @@ kadm5_chpass_principal_3(void *server_handle,
         }
 
         if (pol.pw_max_life)
-            kdb->pw_expiration = now + pol.pw_max_life;
+            kdb->pw_expiration = ts_incr(now, pol.pw_max_life);
         else
             kdb->pw_expiration = 0;
     } else {
@@ -1624,7 +1624,7 @@ kadm5_randkey_principal_3(void *server_handle,
 #endif
 
         if (pol.pw_max_life)
-            kdb->pw_expiration = now + pol.pw_max_life;
+            kdb->pw_expiration = ts_incr(now, pol.pw_max_life);
         else
             kdb->pw_expiration = 0;
     } else {
@@ -1774,7 +1774,7 @@ kadm5_setv4key_principal(void *server_handle,
 #endif
 
         if (pol.pw_max_life)
-            kdb->pw_expiration = now + pol.pw_max_life;
+            kdb->pw_expiration = ts_incr(now, pol.pw_max_life);
         else
             kdb->pw_expiration = 0;
     } else {
@@ -2024,7 +2024,7 @@ kadm5_setkey_principal_4(void *server_handle, krb5_principal principal,
     }
     if (have_pol) {
         if (pol.pw_max_life)
-            kdb->pw_expiration = now + pol.pw_max_life;
+            kdb->pw_expiration = ts_incr(now, pol.pw_max_life);
         else
             kdb->pw_expiration = 0;
     } else {
diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c
index 4adf0fcbb..7f33c7e68 100644
--- a/src/lib/kdb/kdb5.c
+++ b/src/lib/kdb/kdb5.c
@@ -1296,7 +1296,7 @@ find_actkvno(krb5_actkvno_node *list, krb5_timestamp now)
      * are in the future, we will return the first node; if all are in the
      * past, we will return the last node.
      */
-    while (list->next != NULL && list->next->act_time <= now)
+    while (list->next != NULL && !ts_after(list->next->act_time, now))
         list = list->next;
     return list->act_kvno;
 }
diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c
index a827ca608..889460989 100644
--- a/src/lib/krb5/asn.1/asn1_k_encode.c
+++ b/src/lib/krb5/asn.1/asn1_k_encode.c
@@ -158,8 +158,7 @@ static asn1_error_code
 encode_kerberos_time(asn1buf *buf, const void *p, taginfo *rettag,
                      size_t *len_out)
 {
-    /* Range checking for time_t vs krb5_timestamp?  */
-    time_t val = *(krb5_timestamp *)p;
+    time_t val = ts2tt(*(krb5_timestamp *)p);
     rettag->asn1class = UNIVERSAL;
     rettag->construction = PRIMITIVE;
     rettag->tagnum = ASN1_GENERALTIME;
diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c
index 4fe3f0d6f..fba710b1b 100644
--- a/src/lib/krb5/ccache/cc_keyring.c
+++ b/src/lib/krb5/ccache/cc_keyring.c
@@ -751,7 +751,7 @@ update_keyring_expiration(krb5_context context, krb5_ccache id)
     for (;;) {
         if (krcc_next_cred(context, id, &cursor, &creds) != 0)
             break;
-        if (creds.times.endtime > endtime)
+        if (ts_after(creds.times.endtime, endtime))
             endtime = creds.times.endtime;
         krb5_free_cred_contents(context, &creds);
     }
@@ -765,7 +765,7 @@ update_keyring_expiration(krb5_context context, krb5_ccache id)
 
     /* Setting the timeout to zero would reset the timeout, so we set it to one
      * second instead if creds are already expired. */
-    timeout = (endtime > now) ? endtime - now : 1;
+    timeout = ts_after(endtime, now) ? ts_delta(endtime, now) : 1;
     (void)keyctl_set_timeout(data->cache_id, timeout);
 }
 
@@ -1316,8 +1316,10 @@ krcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
     if (ret)
         goto errout;
 
-    if (creds->times.endtime > now)
-        (void)keyctl_set_timeout(cred_key, creds->times.endtime - now);
+    if (ts_after(creds->times.endtime, now)) {
+        (void)keyctl_set_timeout(cred_key,
+                                 ts_delta(creds->times.endtime, now));
+    }
 
     update_keyring_expiration(context, id);
 
@@ -1680,8 +1682,8 @@ static void
 krcc_update_change_time(krcc_data *data)
 {
     krb5_timestamp now_time = time(NULL);
-    data->changetime = (data->changetime >= now_time) ?
-        data->changetime + 1 : now_time;
+    data->changetime = ts_after(now_time, data->changetime) ?
+        now_time : ts_incr(data->changetime, 1);
 }
 
 /*
diff --git a/src/lib/krb5/ccache/cc_memory.c b/src/lib/krb5/ccache/cc_memory.c
index 0354575c5..c5425eb3a 100644
--- a/src/lib/krb5/ccache/cc_memory.c
+++ b/src/lib/krb5/ccache/cc_memory.c
@@ -720,8 +720,8 @@ static void
 update_mcc_change_time(krb5_mcc_data *d)
 {
     krb5_timestamp now_time = time(NULL);
-    d->changetime = (d->changetime >= now_time) ?
-        d->changetime + 1 : now_time;
+    d->changetime = ts_after(now_time, d->changetime) ?
+        now_time : ts_incr(d->changetime, 1);
 }
 
 static krb5_error_code KRB5_CALLCONV
diff --git a/src/lib/krb5/ccache/cc_retr.c b/src/lib/krb5/ccache/cc_retr.c
index 1314d24bd..1a32e00c8 100644
--- a/src/lib/krb5/ccache/cc_retr.c
+++ b/src/lib/krb5/ccache/cc_retr.c
@@ -46,11 +46,11 @@ static krb5_boolean
 times_match(const krb5_ticket_times *t1, const krb5_ticket_times *t2)
 {
     if (t1->renew_till) {
-        if (t1->renew_till > t2->renew_till)
+        if (ts_after(t1->renew_till, t2->renew_till))
             return FALSE;               /* this one expires too late */
     }
     if (t1->endtime) {
-        if (t1->endtime > t2->endtime)
+        if (ts_after(t1->endtime, t2->endtime))
             return FALSE;               /* this one expires too late */
     }
     /* only care about expiration on a times_match */
diff --git a/src/lib/krb5/ccache/ccapi/stdcc_util.c b/src/lib/krb5/ccache/ccapi/stdcc_util.c
index 9f44af3d0..6092ee432 100644
--- a/src/lib/krb5/ccache/ccapi/stdcc_util.c
+++ b/src/lib/krb5/ccache/ccapi/stdcc_util.c
@@ -16,8 +16,8 @@
 #include <malloc.h>
 #endif
 
+#include "k5-int.h"
 #include "stdcc_util.h"
-#include "krb5.h"
 #ifdef _WIN32                   /* it's part of krb5.h everywhere else */
 #include "kv5m_err.h"
 #endif
@@ -321,10 +321,10 @@ copy_cc_cred_union_to_krb5_creds (krb5_context in_context,
         keyblock_contents = NULL;
 
         /* copy times */
-        out_creds->times.authtime   = cv5->authtime     + offset_seconds;
-        out_creds->times.starttime  = cv5->starttime    + offset_seconds;
-        out_creds->times.endtime    = cv5->endtime      + offset_seconds;
-        out_creds->times.renew_till = cv5->renew_till   + offset_seconds;
+        out_creds->times.authtime   = ts_incr(cv5->authtime, offset_seconds);
+        out_creds->times.starttime  = ts_incr(cv5->starttime, offset_seconds);
+        out_creds->times.endtime    = ts_incr(cv5->endtime, offset_seconds);
+        out_creds->times.renew_till = ts_incr(cv5->renew_till, offset_seconds);
         out_creds->is_skey          = cv5->is_skey;
         out_creds->ticket_flags     = cv5->ticket_flags;
 
@@ -451,11 +451,11 @@ copy_krb5_creds_to_cc_cred_union (krb5_context in_context,
         cv5->keyblock.data = keyblock_data;
         keyblock_data = NULL;
 
-        cv5->authtime     = in_creds->times.authtime   - offset_seconds;
-        cv5->starttime    = in_creds->times.starttime  - offset_seconds;
-        cv5->endtime      = in_creds->times.endtime    - offset_seconds;
-        cv5->renew_till   = in_creds->times.renew_till - offset_seconds;
-        cv5->is_skey      = in_creds->is_skey;
+        cv5->authtime = ts_incr(in_creds->times.authtime, -offset_seconds);
+        cv5->starttime = ts_incr(in_creds->times.starttime, -offset_seconds);
+        cv5->endtime = ts_incr(in_creds->times.endtime, -offset_seconds);
+        cv5->renew_till = ts_incr(in_creds->times.renew_till, -offset_seconds);
+        cv5->is_skey = in_creds->is_skey;
         cv5->ticket_flags = in_creds->ticket_flags;
 
         if (in_creds->ticket.data) {
@@ -732,10 +732,10 @@ void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest)
     err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
     if (err) return;
 #endif
-    dest->times.authtime   = src->authtime     + offset_seconds;
-    dest->times.starttime  = src->starttime    + offset_seconds;
-    dest->times.endtime    = src->endtime      + offset_seconds;
-    dest->times.renew_till = src->renew_till   + offset_seconds;
+    dest->times.authtime   = ts_incr(src->authtime, offset_seconds);
+    dest->times.starttime  = ts_incr(src->starttime, offset_seconds);
+    dest->times.endtime    = ts_incr(src->endtime, offset_seconds);
+    dest->times.renew_till = ts_incr(src->renew_till, offset_seconds);
     dest->is_skey          = src->is_skey;
     dest->ticket_flags     = src->ticket_flags;
 
@@ -804,10 +804,10 @@ void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu)
     err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
     if (err) return;
 #endif
-    c->authtime     = creds->times.authtime   - offset_seconds;
-    c->starttime    = creds->times.starttime  - offset_seconds;
-    c->endtime      = creds->times.endtime    - offset_seconds;
-    c->renew_till   = creds->times.renew_till - offset_seconds;
+    c->authtime     = ts_incr(creds->times.authtime, -offset_seconds);
+    c->starttime    = ts_incr(creds->times.starttime, -offset_seconds);
+    c->endtime      = ts_incr(creds->times.endtime, -offset_seconds);
+    c->renew_till   = ts_incr(creds->times.renew_till, -offset_seconds);
     c->is_skey      = creds->is_skey;
     c->ticket_flags = creds->ticket_flags;
 
@@ -925,11 +925,11 @@ times_match(t1, t2)
     register const krb5_ticket_times *t2;
 {
     if (t1->renew_till) {
-        if (t1->renew_till > t2->renew_till)
+        if (ts_after(t1->renew_till, t2->renew_till))
             return FALSE;               /* this one expires too late */
     }
     if (t1->endtime) {
-        if (t1->endtime > t2->endtime)
+        if (ts_after(t1->endtime, t2->endtime))
             return FALSE;               /* this one expires too late */
     }
     /* only care about expiration on a times_match */
diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c
index c31a3f5f0..e631f2051 100644
--- a/src/lib/krb5/ccache/cccursor.c
+++ b/src/lib/krb5/ccache/cccursor.c
@@ -159,7 +159,7 @@ krb5_cccol_last_change_time(krb5_context context,
         ret = krb5_cccol_cursor_next(context, c, &ccache);
         if (ccache) {
             ret = krb5_cc_last_change_time(context, ccache, &last_time);
-            if (!ret && last_time > max_change_time) {
+            if (!ret && ts_after(last_time, max_change_time)) {
                 max_change_time = last_time;
             }
             ret = 0;
diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c
index 131549ffe..b014abf0b 100644
--- a/src/lib/krb5/keytab/kt_file.c
+++ b/src/lib/krb5/keytab/kt_file.c
@@ -264,9 +264,11 @@ more_recent(const krb5_keytab_entry *k1, const krb5_keytab_entry *k2)
      * limitations (8-bit kvno storage), pre-1.14 kadmin protocol limitations
      * (8-bit kvno marshalling), or KDB limitations (16-bit kvno storage).
      */
-    if (k1->timestamp >= k2->timestamp && k1->vno < 128 && k2->vno > 240)
+    if (!ts_after(k2->timestamp, k1->timestamp) &&
+        k1->vno < 128 && k2->vno > 240)
         return TRUE;
-    if (k1->timestamp <= k2->timestamp && k1->vno > 240 && k2->vno < 128)
+    if (!ts_after(k1->timestamp, k2->timestamp) &&
+        k1->vno > 240 && k2->vno < 128)
         return FALSE;
 
     /* Otherwise do a simple version comparison. */
diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c
index c85d8b8d8..cf1ea361f 100644
--- a/src/lib/krb5/krb/gc_via_tkt.c
+++ b/src/lib/krb5/krb/gc_via_tkt.c
@@ -287,18 +287,19 @@ krb5int_process_tgs_reply(krb5_context context,
         retval = KRB5_KDCREP_MODIFIED;
 
     if ((in_cred->times.endtime != 0) &&
-        (dec_rep->enc_part2->times.endtime > in_cred->times.endtime))
+        ts_after(dec_rep->enc_part2->times.endtime, in_cred->times.endtime))
         retval = KRB5_KDCREP_MODIFIED;
 
     if ((kdcoptions & KDC_OPT_RENEWABLE) &&
         (in_cred->times.renew_till != 0) &&
-        (dec_rep->enc_part2->times.renew_till > in_cred->times.renew_till))
+        ts_after(dec_rep->enc_part2->times.renew_till,
+                 in_cred->times.renew_till))
         retval = KRB5_KDCREP_MODIFIED;
 
     if ((kdcoptions & KDC_OPT_RENEWABLE_OK) &&
         (dec_rep->enc_part2->flags & KDC_OPT_RENEWABLE) &&
         (in_cred->times.endtime != 0) &&
-        (dec_rep->enc_part2->times.renew_till > in_cred->times.endtime))
+        ts_after(dec_rep->enc_part2->times.renew_till, in_cred->times.endtime))
         retval = KRB5_KDCREP_MODIFIED;
 
     if (retval != 0)
diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c
index 110abeb2b..be5b2d18c 100644
--- a/src/lib/krb5/krb/get_creds.c
+++ b/src/lib/krb5/krb/get_creds.c
@@ -816,7 +816,7 @@ get_cached_local_tgt(krb5_context context, krb5_tkt_creds_context ctx,
         return code;
 
     /* Check if the TGT is expired before bothering the KDC with it. */
-    if (now > tgt->times.endtime) {
+    if (ts_after(now, tgt->times.endtime)) {
         krb5_free_creds(context, tgt);
         return KRB5KRB_AP_ERR_TKT_EXPIRED;
     }
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index a058f5bd7..40aba1905 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -39,24 +39,6 @@ static krb5_error_code sort_krb5_padata_sequence(krb5_context context,
                                                  krb5_data *realm,
                                                  krb5_pa_data **padata);
 
-/*
- * This function performs 32 bit bounded addition so we can generate
- * lifetimes without overflowing krb5_int32
- */
-static krb5_int32
-krb5int_addint32 (krb5_int32 x, krb5_int32 y)
-{
-    if ((x > 0) && (y > (KRB5_INT32_MAX - x))) {
-        /* sum will be be greater than KRB5_INT32_MAX */
-        return KRB5_INT32_MAX;
-    } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) {
-        /* sum will be less than KRB5_INT32_MIN */
-        return KRB5_INT32_MIN;
-    }
-
-    return x + y;
-}
-
 /*
  * Decrypt the AS reply in ctx, populating ctx->reply->enc_part2.  If
  * strengthen_key is not null, combine it with the reply key as specified in
@@ -267,21 +249,21 @@ verify_as_reply(krb5_context            context,
             (request->from != 0) &&
             (request->from != as_reply->enc_part2->times.starttime))
         || ((request->till != 0) &&
-            (as_reply->enc_part2->times.endtime > request->till))
+            ts_after(as_reply->enc_part2->times.endtime, request->till))
         || ((request->kdc_options & KDC_OPT_RENEWABLE) &&
             (request->rtime != 0) &&
-            (as_reply->enc_part2->times.renew_till > request->rtime))
+            ts_after(as_reply->enc_part2->times.renew_till, request->rtime))
         || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
             !(request->kdc_options & KDC_OPT_RENEWABLE) &&
             (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
             (request->till != 0) &&
-            (as_reply->enc_part2->times.renew_till > request->till))
+            ts_after(as_reply->enc_part2->times.renew_till, request->till))
     ) {
         return KRB5_KDCREP_MODIFIED;
     }
 
     if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) {
-        time_offset = as_reply->enc_part2->times.authtime - time_now;
+        time_offset = ts_delta(as_reply->enc_part2->times.authtime, time_now);
         retval = krb5_set_time_offsets(context, time_offset, 0);
         if (retval)
             return retval;
@@ -790,15 +772,15 @@ set_request_times(krb5_context context, krb5_init_creds_context ctx)
         return code;
 
     /* Omit request start time unless the caller explicitly asked for one. */
-    from = krb5int_addint32(now, ctx->start_time);
+    from = ts_incr(now, ctx->start_time);
     if (ctx->start_time != 0)
         ctx->request->from = from;
 
-    ctx->request->till = krb5int_addint32(from, ctx->tkt_life);
+    ctx->request->till = ts_incr(from, ctx->tkt_life);
 
     if (ctx->renew_life > 0) {
         /* Don't ask for a smaller renewable time than the lifetime. */
-        ctx->request->rtime = krb5int_addint32(from, ctx->renew_life);
+        ctx->request->rtime = ts_incr(from, ctx->renew_life);
         if (ctx->request->rtime < ctx->request->till)
             ctx->request->rtime = ctx->request->till;
         ctx->request->kdc_options &= ~KDC_OPT_RENEWABLE_OK;
@@ -1438,7 +1420,7 @@ note_req_timestamp(krb5_context context, krb5_init_creds_context ctx,
 
     if (k5_time_with_offset(0, 0, &now, &usec) != 0)
         return;
-    ctx->pa_offset = kdc_time - now;
+    ctx->pa_offset = ts_delta(kdc_time, now);
     ctx->pa_offset_usec = kdc_usec - usec;
     ctx->pa_offset_state = (ctx->fast_state->armor_key != NULL) ?
         AUTH_OFFSET : UNAUTH_OFFSET;
@@ -1807,6 +1789,7 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out,
 {
     int i;
     krb5_int32 starttime;
+    krb5_deltat lifetime;
     krb5_get_init_creds_opt *opt;
     krb5_error_code retval;
 
@@ -1838,7 +1821,8 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out,
         if (retval)
             goto cleanup;
         if (creds->times.starttime) starttime = creds->times.starttime;
-        krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime);
+        lifetime = ts_delta(creds->times.endtime, starttime);
+        krb5_get_init_creds_opt_set_tkt_life(opt, lifetime);
     }
     *out = opt;
     return 0;
diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c
index 6f3a29f2c..3565a7c4c 100644
--- a/src/lib/krb5/krb/gic_pwd.c
+++ b/src/lib/krb5/krb/gic_pwd.c
@@ -211,7 +211,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
     if (ret != 0)
         return;
     if (!is_last_req &&
-        (pw_exp < now || (pw_exp - now) > 7 * 24 * 60 * 60))
+        (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60))
         return;
 
     if (!prompter)
@@ -221,7 +221,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
     if (ret != 0)
         return;
 
-    delta = pw_exp - now;
+    delta = ts_delta(pw_exp, now);
     if (delta < 3600) {
         snprintf(banner, sizeof(banner),
                  _("Warning: Your password will expire in less than one hour "
diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h
index 44eca359f..48bd9f8f7 100644
--- a/src/lib/krb5/krb/int-proto.h
+++ b/src/lib/krb5/krb/int-proto.h
@@ -84,7 +84,7 @@ krb5int_construct_matching_creds(krb5_context context, krb5_flags options,
                                  krb5_flags *fields);
 
 #define in_clock_skew(context, date, now)               \
-    (labs((date) - (now)) < (context)->clockskew)
+    (labs(ts_delta(date, now)) < (context)->clockskew)
 
 #define IS_TGS_PRINC(p) ((p)->length == 2 &&                            \
                          data_eq_string((p)->data[0], KRB5_TGS_NAME))
diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
index 9098927b5..c70585a9e 100644
--- a/src/lib/krb5/krb/pac.c
+++ b/src/lib/krb5/krb/pac.c
@@ -378,7 +378,7 @@ k5_time_to_seconds_since_1970(int64_t ntTime, krb5_timestamp *elapsedSeconds)
 
     abstime = ntTime > 0 ? ntTime - NT_TIME_EPOCH : -ntTime;
 
-    if (abstime > KRB5_INT32_MAX)
+    if (abstime > UINT32_MAX)
         return ERANGE;
 
     *elapsedSeconds = abstime;
diff --git a/src/lib/krb5/krb/str_conv.c b/src/lib/krb5/krb/str_conv.c
index 3ab7eacac..f0a2ae20b 100644
--- a/src/lib/krb5/krb/str_conv.c
+++ b/src/lib/krb5/krb/str_conv.c
@@ -207,7 +207,7 @@ krb5_error_code KRB5_CALLCONV
 krb5_timestamp_to_string(krb5_timestamp timestamp, char *buffer, size_t buflen)
 {
     size_t ret;
-    time_t timestamp2 = timestamp;
+    time_t timestamp2 = ts2tt(timestamp);
     struct tm tmbuf;
     const char *fmt = "%c"; /* This is to get around gcc -Wall warning that
                                the year returned might be two digits */
@@ -229,7 +229,7 @@ krb5_timestamp_to_sfstring(krb5_timestamp timestamp, char *buffer, size_t buflen
     struct tm   *tmp;
     size_t i;
     size_t      ndone;
-    time_t timestamp2 = timestamp;
+    time_t timestamp2 = ts2tt(timestamp);
     struct tm tmbuf;
 
     static const char * const sftime_format_table[] = {
diff --git a/src/lib/krb5/krb/t_kerb.c b/src/lib/krb5/krb/t_kerb.c
index 60cfb5b15..74ac14d9a 100644
--- a/src/lib/krb5/krb/t_kerb.c
+++ b/src/lib/krb5/krb/t_kerb.c
@@ -5,16 +5,8 @@
  */
 
 #include "autoconf.h"
-#include "krb5.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
+#include "k5-int.h"
 #include <time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
 
 #include "com_err.h"
 
@@ -37,7 +29,7 @@ test_string_to_timestamp(krb5_context ctx, char *ktime)
         com_err("krb5_string_to_timestamp", retval, 0);
         return;
     }
-    t = (time_t) timestamp;
+    t = ts2tt(timestamp);
     printf("Parsed time was %s", ctime(&t));
 }
 
diff --git a/src/lib/krb5/krb/valid_times.c b/src/lib/krb5/krb/valid_times.c
index d63122183..9e509b2dd 100644
--- a/src/lib/krb5/krb/valid_times.c
+++ b/src/lib/krb5/krb/valid_times.c
@@ -47,10 +47,10 @@ krb5int_validate_times(krb5_context context, krb5_ticket_times *times)
     else
         starttime = times->authtime;
 
-    if (starttime - currenttime > context->clockskew)
+    if (ts_delta(starttime, currenttime) > context->clockskew)
         return KRB5KRB_AP_ERR_TKT_NYV;  /* ticket not yet valid */
 
-    if ((currenttime - times->endtime) > context->clockskew)
+    if (ts_delta(currenttime, times->endtime) > context->clockskew)
         return KRB5KRB_AP_ERR_TKT_EXPIRED; /* ticket expired */
 
     return 0;
diff --git a/src/lib/krb5/krb/vfy_increds.c b/src/lib/krb5/krb/vfy_increds.c
index 9786d63b5..b4878ba38 100644
--- a/src/lib/krb5/krb/vfy_increds.c
+++ b/src/lib/krb5/krb/vfy_increds.c
@@ -120,7 +120,7 @@ get_vfy_cred(krb5_context context, krb5_creds *creds, krb5_principal server,
         ret = krb5_timeofday(context, &in_creds.times.endtime);
         if (ret)
             goto cleanup;
-        in_creds.times.endtime += 5*60;
+        in_creds.times.endtime = ts_incr(in_creds.times.endtime, 5 * 60);
         ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds);
         if (ret)
             goto cleanup;
diff --git a/src/lib/krb5/os/timeofday.c b/src/lib/krb5/os/timeofday.c
index fddb12142..887f24c22 100644
--- a/src/lib/krb5/os/timeofday.c
+++ b/src/lib/krb5/os/timeofday.c
@@ -60,7 +60,7 @@ krb5_check_clockskew(krb5_context context, krb5_timestamp date)
     retval = krb5_timeofday(context, &currenttime);
     if (retval)
         return retval;
-    if (!(labs((date)-currenttime) < context->clockskew))
+    if (labs(ts_delta(date, currenttime)) >= context->clockskew)
         return KRB5KRB_AP_ERR_SKEW;
 
     return 0;
diff --git a/src/lib/krb5/os/toffset.c b/src/lib/krb5/os/toffset.c
index 456193a41..37bc69f49 100644
--- a/src/lib/krb5/os/toffset.c
+++ b/src/lib/krb5/os/toffset.c
@@ -47,7 +47,7 @@ krb5_set_real_time(krb5_context context, krb5_timestamp seconds, krb5_int32 micr
     if (retval)
         return retval;
 
-    os_ctx->time_offset = seconds - sec;
+    os_ctx->time_offset = ts_delta(seconds, sec);
     os_ctx->usec_offset = (microseconds > -1) ? microseconds - usec : 0;
 
     os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) |
diff --git a/src/lib/krb5/os/ustime.c b/src/lib/krb5/os/ustime.c
index 056357683..1c1b571eb 100644
--- a/src/lib/krb5/os/ustime.c
+++ b/src/lib/krb5/os/ustime.c
@@ -49,13 +49,13 @@ k5_time_with_offset(krb5_timestamp offset, krb5_int32 offset_usec,
     usec += offset_usec;
     if (usec > 1000000) {
         usec -= 1000000;
-        sec++;
+        sec = ts_incr(sec, 1);
     }
     if (usec < 0) {
         usec += 1000000;
-        sec--;
+        sec = ts_incr(sec, -1);
     }
-    sec += offset;
+    sec = ts_incr(sec, offset);
 
     *time_out = sec;
     *usec_out = usec;
diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c
index c0f12ed9d..6b043844d 100644
--- a/src/lib/krb5/rcache/rc_dfl.c
+++ b/src/lib/krb5/rcache/rc_dfl.c
@@ -97,8 +97,7 @@ alive(krb5_int32 mytime, krb5_donot_replay *new1, krb5_deltat t)
 {
     if (mytime == 0)
         return CMP_HOHUM; /* who cares? */
-    /* I hope we don't have to worry about overflow */
-    if (new1->ctime + t < mytime)
+    if (ts_after(mytime, ts_incr(new1->ctime, t)))
         return CMP_EXPIRED;
     return CMP_HOHUM;
 }
diff --git a/src/lib/krb5/rcache/t_replay.c b/src/lib/krb5/rcache/t_replay.c
index db273ec2f..b99cdf1ab 100644
--- a/src/lib/krb5/rcache/t_replay.c
+++ b/src/lib/krb5/rcache/t_replay.c
@@ -110,7 +110,7 @@ store(krb5_context ctx, char *rcspec, char *client, char *server, char *msg,
     krb5_donot_replay rep;
     krb5_data d;
 
-    if (now_timestamp > 0)
+    if (now_timestamp != 0)
         krb5_set_debugging_time(ctx, now_timestamp, now_usec);
     if ((retval = krb5_rc_resolve_full(ctx, &rc, rcspec)))
         goto cleanup;
@@ -221,13 +221,13 @@ main(int argc, char **argv)
             msg = (**argv) ? *argv : NULL;
             argc--; argv++;
             if (!argc) usage(progname);
-            timestamp = (krb5_timestamp) atol(*argv);
+            timestamp = (krb5_timestamp) atoll(*argv);
             argc--; argv++;
             if (!argc) usage(progname);
             usec = (krb5_int32) atol(*argv);
             argc--; argv++;
             if (!argc) usage(progname);
-            now_timestamp = (krb5_timestamp) atol(*argv);
+            now_timestamp = (krb5_timestamp) atoll(*argv);
             argc--; argv++;
             if (!argc) usage(progname);
             now_usec = (krb5_int32) atol(*argv);
@@ -249,7 +249,7 @@ main(int argc, char **argv)
             rcspec = *argv;
             argc--; argv++;
             if (!argc) usage(progname);
-            now_timestamp = (krb5_timestamp) atol(*argv);
+            now_timestamp = (krb5_timestamp) atoll(*argv);
             argc--; argv++;
             if (!argc) usage(progname);
             now_usec = (krb5_int32) atol(*argv);
diff --git a/src/plugins/kdb/db2/lockout.c b/src/plugins/kdb/db2/lockout.c
index 7d151b55b..3a4f41821 100644
--- a/src/plugins/kdb/db2/lockout.c
+++ b/src/plugins/kdb/db2/lockout.c
@@ -100,7 +100,7 @@ locked_check_p(krb5_context context,
 
     /* If the entry was unlocked since the last failure, it's not locked. */
     if (krb5_dbe_lookup_last_admin_unlock(context, entry, &unlock_time) == 0 &&
-        entry->last_failed <= unlock_time)
+        !ts_after(entry->last_failed, unlock_time))
         return FALSE;
 
     if (max_fail == 0 || entry->fail_auth_count < max_fail)
@@ -109,7 +109,7 @@ locked_check_p(krb5_context context,
     if (lockout_duration == 0)
         return TRUE; /* principal permanently locked */
 
-    return (stamp < entry->last_failed + lockout_duration);
+    return ts_after(ts_incr(entry->last_failed, lockout_duration), stamp);
 }
 
 krb5_error_code
@@ -200,13 +200,13 @@ krb5_db2_lockout_audit(krb5_context context,
                 status == KRB5KRB_AP_ERR_BAD_INTEGRITY)) {
         if (krb5_dbe_lookup_last_admin_unlock(context, entry,
                                               &unlock_time) == 0 &&
-            entry->last_failed <= unlock_time) {
+            !ts_after(entry->last_failed, unlock_time)) {
             /* Reset fail_auth_count after administrative unlock. */
             entry->fail_auth_count = 0;
         }
 
         if (failcnt_interval != 0 &&
-            stamp > entry->last_failed + failcnt_interval) {
+            ts_after(stamp, ts_incr(entry->last_failed, failcnt_interval))) {
             /* Reset fail_auth_count after failcnt_interval. */
             entry->fail_auth_count = 0;
         }
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
index 7ba53f959..88a170495 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
@@ -1734,7 +1734,7 @@ getstringtime(krb5_timestamp epochtime)
 {
     struct tm           tme;
     char                *strtime=NULL;
-    time_t              posixtime = epochtime;
+    time_t              posixtime = ts2tt(epochtime);
 
     strtime = calloc (50, 1);
     if (strtime == NULL)
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/lockout.c b/src/plugins/kdb/ldap/libkdb_ldap/lockout.c
index 0fc56c2fe..1088ecc5a 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/lockout.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/lockout.c
@@ -93,7 +93,7 @@ locked_check_p(krb5_context context,
 
     /* If the entry was unlocked since the last failure, it's not locked. */
     if (krb5_dbe_lookup_last_admin_unlock(context, entry, &unlock_time) == 0 &&
-        entry->last_failed <= unlock_time)
+        !ts_after(entry->last_failed, unlock_time))
         return FALSE;
 
     if (max_fail == 0 || entry->fail_auth_count < max_fail)
@@ -102,7 +102,7 @@ locked_check_p(krb5_context context,
     if (lockout_duration == 0)
         return TRUE; /* principal permanently locked */
 
-    return (stamp < entry->last_failed + lockout_duration);
+    return ts_after(ts_incr(entry->last_failed, lockout_duration), stamp);
 }
 
 krb5_error_code
@@ -196,14 +196,14 @@ krb5_ldap_lockout_audit(krb5_context context,
                 status == KRB5KRB_AP_ERR_BAD_INTEGRITY)) {
         if (krb5_dbe_lookup_last_admin_unlock(context, entry,
                                               &unlock_time) == 0 &&
-            entry->last_failed <= unlock_time) {
+            !ts_after(entry->last_failed, unlock_time)) {
             /* Reset fail_auth_count after administrative unlock. */
             entry->fail_auth_count = 0;
             entry->mask |= KADM5_FAIL_AUTH_COUNT;
         }
 
         if (failcnt_interval != 0 &&
-            stamp > entry->last_failed + failcnt_interval) {
+            ts_after(stamp, ts_incr(entry->last_failed, failcnt_interval))) {
             /* Reset fail_auth_count after failcnt_interval */
             entry->fail_auth_count = 0;
             entry->mask |= KADM5_FAIL_AUTH_COUNT;
diff --git a/src/windows/cns/tktlist.c b/src/windows/cns/tktlist.c
index f2805f5cd..26e699fae 100644
--- a/src/windows/cns/tktlist.c
+++ b/src/windows/cns/tktlist.c
@@ -35,6 +35,8 @@
 #include "cns.h"
 #include "tktlist.h"
 
+#define ts2tt(t) (time_t)(uint32_t)(t)
+
 /*
  * Ticket information for a list line
  */
@@ -167,10 +169,10 @@ ticket_init_list (HWND hwnd)
 
       ncred++;
       strcpy (buf, "  ");
-      strncat(buf, short_date (c.times.starttime - kwin_get_epoch()),
+      strncat(buf, short_date(ts2tt(c.times.starttime) - kwin_get_epoch()),
 	      sizeof(buf) - 1 - strlen(buf));
       strncat(buf, "      ", sizeof(buf) - 1 - strlen(buf));
-      strncat(buf, short_date (c.times.endtime - kwin_get_epoch()),
+      strncat(buf, short_date(ts2tt(c.times.endtime) - kwin_get_epoch()),
 	      sizeof(buf) - 1 - strlen(buf));
       strncat(buf, "      ", sizeof(buf) - 1 - strlen(buf));
 
@@ -192,8 +194,8 @@ ticket_init_list (HWND hwnd)
 	return -1;
 
       lpinfo->ticket = TRUE;
-      lpinfo->issue_time = c.times.starttime - kwin_get_epoch();
-      lpinfo->lifetime = c.times.endtime - c.times.starttime;
+      lpinfo->issue_time = ts2tt(c.times.starttime) - kwin_get_epoch();
+      lpinfo->lifetime = ts2tt(c.times.endtime) - c.times.starttime;
       strcpy(lpinfo->buf, buf);
 
       rc = ListBox_AddItemData(hwnd, lpinfo);
diff --git a/src/windows/include/leashwin.h b/src/windows/include/leashwin.h
index 9577365a7..325dce2e9 100644
--- a/src/windows/include/leashwin.h
+++ b/src/windows/include/leashwin.h
@@ -111,9 +111,9 @@ struct TicketList {
     TicketList *next;
     char *service;
     char *encTypes;
-    krb5_timestamp issued;
-    krb5_timestamp valid_until;
-    krb5_timestamp renew_until;
+    time_t issued;
+    time_t valid_until;
+    time_t renew_until;
     unsigned long flags;
 };
 
@@ -124,9 +124,9 @@ struct TICKETINFO {
     char   *ccache_name;
     TicketList *ticket_list;
     int     btickets;                 /* Do we have tickets? */
-    long    issued;                   /* The issue time */
-    long    valid_until;              /* */
-    long    renew_until;              /* The Renew time (k5 only) */
+    time_t  issued;                   /* The issue time */
+    time_t  valid_until;              /* */
+    time_t  renew_until;              /* The Renew time (k5 only) */
     unsigned long flags;
 };
 
diff --git a/src/windows/leash/KrbListTickets.cpp b/src/windows/leash/KrbListTickets.cpp
index beab0ea11..5dd37b05a 100644
--- a/src/windows/leash/KrbListTickets.cpp
+++ b/src/windows/leash/KrbListTickets.cpp
@@ -92,10 +92,10 @@ etype_string(krb5_enctype enctype)
 static void
 CredToTicketInfo(krb5_creds KRBv5Credentials, TICKETINFO *ticketinfo)
 {
-    ticketinfo->issued = KRBv5Credentials.times.starttime;
-    ticketinfo->valid_until = KRBv5Credentials.times.endtime;
+    ticketinfo->issued = (DWORD)KRBv5Credentials.times.starttime;
+    ticketinfo->valid_until = (DWORD)KRBv5Credentials.times.endtime;
     ticketinfo->renew_until = KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE ?
-        KRBv5Credentials.times.renew_till : 0;
+        (DWORD)KRBv5Credentials.times.renew_till : (DWORD)0;
     _tzset();
     if ( ticketinfo->valid_until - time(0) <= 0L )
         ticketinfo->btickets = EXPD_TICKETS;
@@ -137,10 +137,10 @@ CredToTicketList(krb5_context ctx, krb5_creds KRBv5Credentials,
         functionName = "calloc()";
         goto cleanup;
     }
-    list->issued = KRBv5Credentials.times.starttime;
-    list->valid_until = KRBv5Credentials.times.endtime;
+    list->issued = (DWORD)KRBv5Credentials.times.starttime;
+    list->valid_until = (DWORD)KRBv5Credentials.times.endtime;
     if (KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE)
-        list->renew_until = KRBv5Credentials.times.renew_till;
+        list->renew_until = (DWORD)KRBv5Credentials.times.renew_till;
     else
         list->renew_until = 0;
 
diff --git a/src/windows/leash/LeashView.cpp b/src/windows/leash/LeashView.cpp
index ef2a5a3e0..253ae3f06 100644
--- a/src/windows/leash/LeashView.cpp
+++ b/src/windows/leash/LeashView.cpp
@@ -229,22 +229,22 @@ static HFONT CreateBoldItalicFont(HFONT font)
 
 bool change_icon_size = true;
 
-void krb5TimestampToFileTime(krb5_timestamp t, LPFILETIME pft)
+void TimestampToFileTime(time_t t, LPFILETIME pft)
 {
     // Note that LONGLONG is a 64-bit value
-    LONGLONG ll;
+    ULONGLONG ll;
 
-    ll = Int32x32To64(t, 10000000) + 116444736000000000;
+    ll = UInt32x32To64((DWORD)t, 10000000) + 116444736000000000;
     pft->dwLowDateTime = (DWORD)ll;
     pft->dwHighDateTime = ll >> 32;
 }
 
 // allocate outstr
-void krb5TimestampToLocalizedString(krb5_timestamp t, LPTSTR *outStr)
+void TimestampToLocalizedString(time_t t, LPTSTR *outStr)
 {
     FILETIME ft, lft;
     SYSTEMTIME st;
-    krb5TimestampToFileTime(t, &ft);
+    TimestampToFileTime(t, &ft);
     FileTimeToLocalFileTime(&ft, &lft);
     FileTimeToSystemTime(&lft, &st);
     TCHAR timeFormat[80]; // 80 is max required for LOCALE_STIMEFORMAT
@@ -1125,9 +1125,9 @@ void CLeashView::AddDisplayItem(CListCtrl &list,
                                 CCacheDisplayData *elem,
                                 int iItem,
                                 char *principal,
-                                long issued,
-                                long valid_until,
-                                long renew_until,
+                                time_t issued,
+                                time_t valid_until,
+                                time_t renew_until,
                                 char *encTypes,
                                 unsigned long flags,
                                 char *ccache_name)
@@ -1145,7 +1145,7 @@ void CLeashView::AddDisplayItem(CListCtrl &list,
         if (issued == 0) {
             list.SetItemText(iItem, iSubItem++, "Unknown");
         } else {
-            krb5TimestampToLocalizedString(issued, &localTimeStr);
+            TimestampToLocalizedString(issued, &localTimeStr);
             list.SetItemText(iItem, iSubItem++, localTimeStr);
         }
     }
@@ -1155,7 +1155,7 @@ void CLeashView::AddDisplayItem(CListCtrl &list,
         } else if (valid_until < now) {
             list.SetItemText(iItem, iSubItem++, "Expired");
         } else if (renew_until) {
-            krb5TimestampToLocalizedString(renew_until, &localTimeStr);
+            TimestampToLocalizedString(renew_until, &localTimeStr);
             DurationToString(renew_until - now, &durationStr);
             if (localTimeStr && durationStr) {
                 _snprintf(tempStr, MAX_DURATION_STR, "%s %s", localTimeStr, durationStr);
@@ -1172,7 +1172,7 @@ void CLeashView::AddDisplayItem(CListCtrl &list,
         } else if (valid_until < now) {
             list.SetItemText(iItem, iSubItem++, "Expired");
         } else {
-            krb5TimestampToLocalizedString(valid_until, &localTimeStr);
+            TimestampToLocalizedString(valid_until, &localTimeStr);
             DurationToString(valid_until - now, &durationStr);
             if (localTimeStr && durationStr) {
                 _snprintf(tempStr, MAX_DURATION_STR, "%s %s", localTimeStr, durationStr);
diff --git a/src/windows/leashdll/lshfunc.c b/src/windows/leashdll/lshfunc.c
index 0f76cc334..8dafb7bed 100644
--- a/src/windows/leashdll/lshfunc.c
+++ b/src/windows/leashdll/lshfunc.c
@@ -2898,7 +2898,7 @@ static BOOL cc_have_tickets(krb5_context ctx, krb5_ccache cache)
     _tzset();
     while (!(code = pkrb5_cc_next_cred(ctx, cache, &cur, &creds))) {
         if ((!pkrb5_is_config_principal(ctx, creds.server)) &&
-            (creds.times.endtime - time(0) > 0))
+            ((time_t)(DWORD)creds.times.endtime - time(0) > 0))
             have_tickets = TRUE;
 
         pkrb5_free_cred_contents(ctx, &creds);
diff --git a/src/windows/ms2mit/ms2mit.c b/src/windows/ms2mit/ms2mit.c
index c3325034a..2b4373cc1 100644
--- a/src/windows/ms2mit/ms2mit.c
+++ b/src/windows/ms2mit/ms2mit.c
@@ -74,7 +74,7 @@ cc_has_tickets(krb5_context kcontext, krb5_ccache ccache, int *has_tickets)
             break;
 
         if (!krb5_is_config_principal(kcontext, creds.server) &&
-            creds.times.endtime > now)
+            ts_after(creds.times.endtime, now))
             *has_tickets = 1;
 
         krb5_free_cred_contents(kcontext, &creds);