Blame SOURCES/Add-timestamp-tests.patch

749169
From 88c93d33d66abe9811e478fd678ff2e5f38a29aa Mon Sep 17 00:00:00 2001
e58a44
From: Greg Hudson <ghudson@mit.edu>
e58a44
Date: Sat, 29 Apr 2017 17:30:36 -0400
e58a44
Subject: [PATCH] Add timestamp tests
e58a44
e58a44
Add a test program for krb5int_validate_times() covering cases before
e58a44
and across the y2038 boundary.  Add a GSSAPI test program to exercise
e58a44
lifetime queries, and tests using it in t_gssapi.py for ticket end
e58a44
times after y2038.  Add a new test script t_y2038.py which only runs
e58a44
on platforms with 64-bit time_t to exercise end-user operations across
e58a44
and after y2038.  Add an LDAP test case to test storage of post-y2038
e58a44
timestamps.
e58a44
e58a44
ticket: 8352
e58a44
(cherry picked from commit 8ca62e54e89e2fbd6a089e8ab20b4e374a486003)
e58a44
[rharwood@redhat.com: prune gitignore]
e58a44
---
e58a44
 src/Makefile.in                  |   1 +
e58a44
 src/config/pre.in                |   2 +
e58a44
 src/configure.in                 |   3 +
665228
 src/lib/krb5/krb/Makefile.in     |  14 +++-
665228
 src/lib/krb5/krb/t_valid_times.c | 109 ++++++++++++++++++++++++
e58a44
 src/tests/Makefile.in            |   1 +
665228
 src/tests/gssapi/Makefile.in     |  27 +++---
665228
 src/tests/gssapi/t_gssapi.py     |  32 +++++++
665228
 src/tests/gssapi/t_lifetime.c    | 140 +++++++++++++++++++++++++++++++
e58a44
 src/tests/t_kdb.py               |   7 ++
665228
 src/tests/t_y2038.py             |  75 +++++++++++++++++
e58a44
 11 files changed, 395 insertions(+), 16 deletions(-)
e58a44
 create mode 100644 src/lib/krb5/krb/t_valid_times.c
e58a44
 create mode 100644 src/tests/gssapi/t_lifetime.c
e58a44
 create mode 100644 src/tests/t_y2038.py
e58a44
e58a44
diff --git a/src/Makefile.in b/src/Makefile.in
e58a44
index b0249778c..ad8565056 100644
e58a44
--- a/src/Makefile.in
e58a44
+++ b/src/Makefile.in
e58a44
@@ -521,6 +521,7 @@ pyrunenv.vals: Makefile
e58a44
 	done > $@
e58a44
 	echo "tls_impl = '$(TLS_IMPL)'" >> $@
e58a44
 	echo "have_sasl = '$(HAVE_SASL)'" >> $@
e58a44
+	echo "sizeof_time_t = $(SIZEOF_TIME_T)" >> $@
e58a44
 
e58a44
 runenv.py: pyrunenv.vals
e58a44
 	echo 'env = {}' > $@
e58a44
diff --git a/src/config/pre.in b/src/config/pre.in
e58a44
index d961b5621..f23c07d9d 100644
e58a44
--- a/src/config/pre.in
e58a44
+++ b/src/config/pre.in
e58a44
@@ -452,6 +452,8 @@ HAVE_SASL = @HAVE_SASL@
e58a44
 # Whether we have libresolv 1.1.5 for URI discovery tests
e58a44
 HAVE_RESOLV_WRAPPER = @HAVE_RESOLV_WRAPPER@
e58a44
 
e58a44
+SIZEOF_TIME_T = @SIZEOF_TIME_T@
e58a44
+
e58a44
 # error table rules
e58a44
 #
e58a44
 ### /* these are invoked as $(...) foo.et, which works, but could be better */
e58a44
diff --git a/src/configure.in b/src/configure.in
e58a44
index 24f653f0d..4ae2c07d5 100644
e58a44
--- a/src/configure.in
e58a44
+++ b/src/configure.in
e58a44
@@ -744,6 +744,9 @@ fi
e58a44
 
e58a44
 AC_HEADER_TIME
e58a44
 AC_CHECK_TYPE(time_t, long)
e58a44
+AC_CHECK_SIZEOF(time_t)
e58a44
+SIZEOF_TIME_T=$ac_cv_sizeof_time_t
e58a44
+AC_SUBST(SIZEOF_TIME_T)
e58a44
 
e58a44
 # Determine where to put the replay cache.
e58a44
 
e58a44
diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in
e58a44
index 0fe02a95d..55f82b147 100644
e58a44
--- a/src/lib/krb5/krb/Makefile.in
e58a44
+++ b/src/lib/krb5/krb/Makefile.in
e58a44
@@ -364,6 +364,7 @@ SRCS=	$(srcdir)/addr_comp.c	\
e58a44
 	$(srcdir)/t_in_ccache.c	\
e58a44
 	$(srcdir)/t_response_items.c \
e58a44
 	$(srcdir)/t_sname_match.c \
e58a44
+	$(srcdir)/t_valid_times.c \
e58a44
 	$(srcdir)/t_vfy_increds.c
e58a44
 
e58a44
 # Someday, when we have a "maintainer mode", do this right:
e58a44
@@ -457,9 +458,12 @@ t_response_items: t_response_items.o response_items.o $(KRB5_BASE_DEPLIBS)
e58a44
 t_sname_match: t_sname_match.o sname_match.o $(KRB5_BASE_DEPLIBS)
e58a44
 	$(CC_LINK) -o $@ t_sname_match.o sname_match.o $(KRB5_BASE_LIBS)
e58a44
 
e58a44
+t_valid_times: t_valid_times.o valid_times.o $(KRB5_BASE_DEPLIBS)
e58a44
+	$(CC_LINK) -o $@ t_valid_times.o valid_times.o $(KRB5_BASE_LIBS)
e58a44
+
e58a44
 TEST_PROGS= t_walk_rtree t_kerb t_ser t_deltat t_expand t_authdata t_pac \
e58a44
-	t_in_ccache t_cc_config t_copy_context \
e58a44
-	t_princ t_etypes t_vfy_increds t_response_items t_sname_match
e58a44
+	t_in_ccache t_cc_config t_copy_context t_princ t_etypes t_vfy_increds \
e58a44
+	t_response_items t_sname_match t_valid_times
e58a44
 
e58a44
 check-unix: $(TEST_PROGS)
e58a44
 	$(RUN_TEST_LOCAL_CONF) ./t_kerb \
e58a44
@@ -496,6 +500,7 @@ check-unix: $(TEST_PROGS)
e58a44
 	$(RUN_TEST) ./t_response_items
e58a44
 	$(RUN_TEST) ./t_copy_context
e58a44
 	$(RUN_TEST) ./t_sname_match
e58a44
+	$(RUN_TEST) ./t_valid_times
e58a44
 
e58a44
 check-pytests: t_expire_warn t_vfy_increds
e58a44
 	$(RUNPYTEST) $(srcdir)/t_expire_warn.py $(PYTESTFLAGS)
e58a44
@@ -522,8 +527,9 @@ clean:
e58a44
 	$(OUTPRE)t_ad_fx_armor$(EXEEXT) $(OUTPRE)t_ad_fx_armor.$(OBJEXT) \
e58a44
 	$(OUTPRE)t_vfy_increds$(EXEEXT) $(OUTPRE)t_vfy_increds.$(OBJEXT) \
e58a44
 	$(OUTPRE)t_response_items$(EXEEXT) \
e58a44
-	$(OUTPRE)t_response_items.$(OBJEXT) $(OUTPRE)t_sname_match$(EXEEXT) \
e58a44
-	$(OUTPRE)t_sname_match.$(OBJEXT) \
e58a44
+	$(OUTPRE)t_response_items.$(OBJEXT) \
e58a44
+	$(OUTPRE)t_sname_match$(EXEEXT) $(OUTPRE)t_sname_match.$(OBJEXT) \
e58a44
+	$(OUTPRE)t_valid_times$(EXEEXT) $(OUTPRE)t_valid_times.$(OBJECT) \
e58a44
 	$(OUTPRE)t_parse_host_string$(EXEEXT) \
e58a44
 	$(OUTPRE)t_parse_host_string.$(OBJEXT)
e58a44
 
e58a44
diff --git a/src/lib/krb5/krb/t_valid_times.c b/src/lib/krb5/krb/t_valid_times.c
e58a44
new file mode 100644
e58a44
index 000000000..1b469ffc2
e58a44
--- /dev/null
e58a44
+++ b/src/lib/krb5/krb/t_valid_times.c
e58a44
@@ -0,0 +1,109 @@
e58a44
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
e58a44
+/* lib/krb5/krb/t_valid_times.c - test program for krb5int_validate_times() */
e58a44
+/*
e58a44
+ * Copyright (C) 2017 by the Massachusetts Institute of Technology.
e58a44
+ * All rights reserved.
e58a44
+ *
e58a44
+ * Redistribution and use in source and binary forms, with or without
e58a44
+ * modification, are permitted provided that the following conditions
e58a44
+ * are met:
e58a44
+ *
e58a44
+ * * Redistributions of source code must retain the above copyright
e58a44
+ *   notice, this list of conditions and the following disclaimer.
e58a44
+ *
e58a44
+ * * Redistributions in binary form must reproduce the above copyright
e58a44
+ *   notice, this list of conditions and the following disclaimer in
e58a44
+ *   the documentation and/or other materials provided with the
e58a44
+ *   distribution.
e58a44
+ *
e58a44
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
e58a44
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
e58a44
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
e58a44
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
e58a44
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
e58a44
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
e58a44
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
e58a44
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
e58a44
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
e58a44
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
e58a44
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
e58a44
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
e58a44
+ */
e58a44
+
e58a44
+#include "k5-int.h"
e58a44
+#include "int-proto.h"
e58a44
+
e58a44
+#define BOUNDARY (uint32_t)INT32_MIN
e58a44
+
e58a44
+int
e58a44
+main()
e58a44
+{
e58a44
+    krb5_error_code ret;
e58a44
+    krb5_context context;
e58a44
+    krb5_ticket_times times = { 0, 0, 0, 0 };
e58a44
+
e58a44
+    ret = krb5_init_context(&context);
e58a44
+    assert(!ret);
e58a44
+
e58a44
+    /* Current time is within authtime and end time. */
e58a44
+    ret = krb5_set_debugging_time(context, 1000, 0);
e58a44
+    times.authtime = 500;
e58a44
+    times.endtime = 1500;
e58a44
+    ret = krb5int_validate_times(context, ×);
e58a44
+    assert(!ret);
e58a44
+
e58a44
+    /* Current time is before starttime, but within clock skew. */
e58a44
+    times.starttime = 1100;
e58a44
+    ret = krb5int_validate_times(context, ×);
e58a44
+    assert(!ret);
e58a44
+
e58a44
+    /* Current time is before starttime by more than clock skew. */
e58a44
+    times.starttime = 1400;
e58a44
+    ret = krb5int_validate_times(context, ×);
e58a44
+    assert(ret == KRB5KRB_AP_ERR_TKT_NYV);
e58a44
+
e58a44
+    /* Current time is after end time, but within clock skew. */
e58a44
+    times.starttime = 500;
e58a44
+    times.endtime = 800;
e58a44
+    ret = krb5int_validate_times(context, ×);
e58a44
+    assert(!ret);
e58a44
+
e58a44
+    /* Current time is after end time by more than clock skew. */
e58a44
+    times.endtime = 600;
e58a44
+    ret = krb5int_validate_times(context, ×);
e58a44
+    assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED);
e58a44
+
e58a44
+    /* Current time is within starttime and endtime; current time and
e58a44
+     * endtime are across y2038 boundary. */
e58a44
+    ret = krb5_set_debugging_time(context, BOUNDARY - 100, 0);
e58a44
+    assert(!ret);
e58a44
+    times.starttime = BOUNDARY - 200;
e58a44
+    times.endtime = BOUNDARY + 500;
e58a44
+    ret = krb5int_validate_times(context, ×);
e58a44
+    assert(!ret);
e58a44
+
e58a44
+    /* Current time is before starttime, but by less than clock skew. */
e58a44
+    times.starttime = BOUNDARY + 100;
e58a44
+    ret = krb5int_validate_times(context, ×);
e58a44
+    assert(!ret);
e58a44
+
e58a44
+    /* Current time is before starttime by more than clock skew. */
e58a44
+    times.starttime = BOUNDARY + 250;
e58a44
+    ret = krb5int_validate_times(context, ×);
e58a44
+    assert(ret == KRB5KRB_AP_ERR_TKT_NYV);
e58a44
+
e58a44
+    /* Current time is after endtime, but by less than clock skew. */
e58a44
+    ret = krb5_set_debugging_time(context, BOUNDARY + 100, 0);
e58a44
+    assert(!ret);
e58a44
+    times.starttime = BOUNDARY - 1000;
e58a44
+    times.endtime = BOUNDARY - 100;
e58a44
+    ret = krb5int_validate_times(context, ×);
e58a44
+    assert(!ret);
e58a44
+
e58a44
+    /* Current time is after endtime by more than clock skew. */
e58a44
+    times.endtime = BOUNDARY - 300;
e58a44
+    ret = krb5int_validate_times(context, ×);
e58a44
+    assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED);
e58a44
+
e58a44
+    return 0;
e58a44
+}
e58a44
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
e58a44
index 0e93d6b59..2b3112537 100644
e58a44
--- a/src/tests/Makefile.in
e58a44
+++ b/src/tests/Makefile.in
e58a44
@@ -168,6 +168,7 @@ check-pytests: localauth plugorder rdreq responder s2p s4u2proxy unlockiter
e58a44
 	$(RUNPYTEST) $(srcdir)/t_princflags.py $(PYTESTFLAGS)
e58a44
 	$(RUNPYTEST) $(srcdir)/t_tabdump.py $(PYTESTFLAGS)
e58a44
 	$(RUNPYTEST) $(srcdir)/t_certauth.py $(PYTESTFLAGS)
e58a44
+	$(RUNPYTEST) $(srcdir)/t_y2038.py $(PYTESTFLAGS)
e58a44
 
e58a44
 clean:
e58a44
 	$(RM) adata etinfo forward gcred hist hooks hrealm icred kdbtest
e58a44
diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in
e58a44
index 6c1464297..604f926de 100644
e58a44
--- a/src/tests/gssapi/Makefile.in
e58a44
+++ b/src/tests/gssapi/Makefile.in
e58a44
@@ -15,15 +15,16 @@ SRCS=	$(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.c \
e58a44
 	$(srcdir)/t_gssexts.c $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c \
e58a44
 	$(srcdir)/t_invalid.c $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_ctx.c \
e58a44
 	$(srcdir)/t_inq_mechs_name.c $(srcdir)/t_iov.c \
e58a44
-	$(srcdir)/t_namingexts.c $(srcdir)/t_oid.c $(srcdir)/t_pcontok.c \
e58a44
-	$(srcdir)/t_prf.c $(srcdir)/t_s4u.c $(srcdir)/t_s4u2proxy_krb5.c \
e58a44
-	$(srcdir)/t_saslname.c $(srcdir)/t_spnego.c $(srcdir)/t_srcattrs.c
e58a44
+	$(srcdir)/t_lifetime.c $(srcdir)/t_namingexts.c $(srcdir)/t_oid.c \
e58a44
+	$(srcdir)/t_pcontok.c $(srcdir)/t_prf.c $(srcdir)/t_s4u.c \
e58a44
+	$(srcdir)/t_s4u2proxy_krb5.c $(srcdir)/t_saslname.c \
e58a44
+	$(srcdir)/t_spnego.c $(srcdir)/t_srcattrs.c
e58a44
 
e58a44
 OBJS=	ccinit.o ccrefresh.o common.o t_accname.o t_ccselect.o t_ciflags.o \
e58a44
 	t_credstore.o t_enctypes.o t_err.o t_export_cred.o t_export_name.o \
e58a44
 	t_gssexts.o t_imp_cred.o t_imp_name.o t_invalid.o t_inq_cred.o \
e58a44
-	t_inq_ctx.o t_inq_mechs_name.o t_iov.o t_namingexts.o t_oid.o \
e58a44
-	t_pcontok.o t_prf.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \
e58a44
+	t_inq_ctx.o t_inq_mechs_name.o t_iov.o t_lifetime.o t_namingexts.o \
e58a44
+	t_oid.o t_pcontok.o t_prf.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \
e58a44
 	t_spnego.o t_srcattrs.o
e58a44
 
e58a44
 COMMON_DEPS= common.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
e58a44
@@ -31,9 +32,9 @@ COMMON_LIBS= common.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
e58a44
 
e58a44
 all: ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore t_enctypes \
e58a44
 	t_err t_export_cred t_export_name t_gssexts t_imp_cred t_imp_name \
e58a44
-	t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_namingexts \
e58a44
-	t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5 t_saslname t_spnego \
e58a44
-	t_srcattrs
e58a44
+	t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime \
e58a44
+	t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5 t_saslname \
e58a44
+	t_spnego t_srcattrs
e58a44
 
e58a44
 check-unix: t_oid
e58a44
 	$(RUN_TEST) ./t_invalid
e58a44
@@ -42,8 +43,8 @@ check-unix: t_oid
e58a44
 
e58a44
 check-pytests: ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore \
e58a44
 	t_enctypes t_err t_export_cred t_export_name t_imp_cred t_inq_cred \
e58a44
-	t_inq_ctx t_inq_mechs_name t_iov t_pcontok t_s4u t_s4u2proxy_krb5 \
e58a44
-	t_spnego t_srcattrs
e58a44
+	t_inq_ctx t_inq_mechs_name t_iov t_lifetime t_pcontok t_s4u \
e58a44
+	t_s4u2proxy_krb5 t_spnego t_srcattrs
e58a44
 	$(RUNPYTEST) $(srcdir)/t_gssapi.py $(PYTESTFLAGS)
e58a44
 	$(RUNPYTEST) $(srcdir)/t_ccselect.py $(PYTESTFLAGS)
e58a44
 	$(RUNPYTEST) $(srcdir)/t_client_keytab.py $(PYTESTFLAGS)
e58a44
@@ -88,6 +89,8 @@ t_inq_mechs_name: t_inq_mechs_name.o $(COMMON_DEPS)
e58a44
 	$(CC_LINK) -o $@ t_inq_mechs_name.o $(COMMON_LIBS)
e58a44
 t_iov: t_iov.o $(COMMON_DEPS)
e58a44
 	$(CC_LINK) -o $@ t_iov.o $(COMMON_LIBS)
e58a44
+t_lifetime: t_lifetime.o $(COMMON_DEPS)
e58a44
+	$(CC_LINK) -o $@ t_lifetime.o $(COMMON_LIBS)
e58a44
 t_namingexts: t_namingexts.o $(COMMON_DEPS)
e58a44
 	$(CC_LINK) -o $@ t_namingexts.o $(COMMON_LIBS)
e58a44
 t_pcontok: t_pcontok.o $(COMMON_DEPS)
e58a44
@@ -111,5 +114,5 @@ clean:
e58a44
 	$(RM) ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore
e58a44
 	$(RM) t_enctypes t_err t_export_cred t_export_name t_gssexts t_imp_cred
e58a44
 	$(RM) t_imp_name t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov
e58a44
-	$(RM) t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5
e58a44
-	$(RM) t_saslname t_spnego t_srcattrs
e58a44
+	$(RM) t_lifetime t_namingexts t_oid t_pcontok t_prf t_s4u
e58a44
+	$(RM) t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs
e58a44
diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py
e58a44
index e23c936d7..fa214242f 100755
e58a44
--- a/src/tests/gssapi/t_gssapi.py
e58a44
+++ b/src/tests/gssapi/t_gssapi.py
e58a44
@@ -220,4 +220,36 @@ realm.run(['./t_ciflags', 'p:' + realm.host_princ])
e58a44
 # contexts.
e58a44
 realm.run(['./t_inq_ctx', 'user', password('user'), 'p:%s' % realm.host_princ])
e58a44
 
e58a44
+# Test lifetime results, using a realm with a large maximum lifetime
e58a44
+# so that we can test ticket end dates after y2038.  There are no
e58a44
+# time_t conversions involved, so we can run these tests on platforms
e58a44
+# with 32-bit time_t.
e58a44
+realm.stop()
e58a44
+conf = {'realms': {'$realm': {'max_life': '9000d'}}}
e58a44
+realm = K5Realm(kdc_conf=conf, get_creds=False)
e58a44
+
e58a44
+# Check a lifetime string result against an expected number value (or None).
e58a44
+# Allow some variance due to time elapsed during the tests.
e58a44
+def check_lifetime(msg, val, expected):
e58a44
+    if expected is None and val != 'indefinite':
e58a44
+        fail('%s: expected indefinite, got %s' % (msg, val))
e58a44
+    if expected is not None and val == 'indefinite':
e58a44
+        fail('%s: expected %d, got indefinite' % (msg, expected))
e58a44
+    if expected is not None and abs(int(val) - expected) > 100:
e58a44
+        fail('%s: expected %d, got %s' % (msg, expected, val))
e58a44
+
e58a44
+realm.kinit(realm.user_princ, password('user'), flags=['-l', '8500d'])
e58a44
+out = realm.run(['./t_lifetime', 'p:' + realm.host_princ, str(8000 * 86400)])
e58a44
+ln = out.split('\n')
e58a44
+check_lifetime('icred gss_acquire_cred', ln[0], 8500 * 86400)
e58a44
+check_lifetime('icred gss_inquire_cred', ln[1], 8500 * 86400)
e58a44
+check_lifetime('acred gss_acquire_cred', ln[2], None)
e58a44
+check_lifetime('acred gss_inquire_cred', ln[3], None)
e58a44
+check_lifetime('ictx gss_init_sec_context', ln[4], 8000 * 86400)
e58a44
+check_lifetime('ictx gss_inquire_context', ln[5], 8000 * 86400)
e58a44
+check_lifetime('ictx gss_context_time', ln[6], 8000 * 86400)
e58a44
+check_lifetime('actx gss_accept_sec_context', ln[7], 8000 * 86400 + 300)
e58a44
+check_lifetime('actx gss_inquire_context', ln[8], 8000 * 86400 + 300)
e58a44
+check_lifetime('actx gss_context_time', ln[9], 8000 * 86400 + 300)
e58a44
+
e58a44
 success('GSSAPI tests')
e58a44
diff --git a/src/tests/gssapi/t_lifetime.c b/src/tests/gssapi/t_lifetime.c
e58a44
new file mode 100644
e58a44
index 000000000..8dcf18621
e58a44
--- /dev/null
e58a44
+++ b/src/tests/gssapi/t_lifetime.c
e58a44
@@ -0,0 +1,140 @@
e58a44
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
e58a44
+/* tests/gssapi/t_lifetime.c - display cred and context lifetimes */
e58a44
+/*
e58a44
+ * Copyright (C) 2017 by the Massachusetts Institute of Technology.
e58a44
+ * All rights reserved.
e58a44
+ *
e58a44
+ * Redistribution and use in source and binary forms, with or without
e58a44
+ * modification, are permitted provided that the following conditions
e58a44
+ * are met:
e58a44
+ *
e58a44
+ * * Redistributions of source code must retain the above copyright
e58a44
+ *   notice, this list of conditions and the following disclaimer.
e58a44
+ *
e58a44
+ * * Redistributions in binary form must reproduce the above copyright
e58a44
+ *   notice, this list of conditions and the following disclaimer in
e58a44
+ *   the documentation and/or other materials provided with the
e58a44
+ *   distribution.
e58a44
+ *
e58a44
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
e58a44
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
e58a44
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
e58a44
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
e58a44
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
e58a44
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
e58a44
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
e58a44
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
e58a44
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
e58a44
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
e58a44
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
e58a44
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
e58a44
+ */
e58a44
+
e58a44
+#include <stdio.h>
e58a44
+#include <stdlib.h>
e58a44
+#include <assert.h>
e58a44
+#include "common.h"
e58a44
+
e58a44
+/*
e58a44
+ * Using the default credential, exercise the GSS functions which accept or
e58a44
+ * produce lifetimes.  Display the following results, one per line, as ASCII
e58a44
+ * integers or the string "indefinite":
e58a44
+ *
e58a44
+ *   initiator cred lifetime according to gss_acquire_cred()
e58a44
+ *   initiator cred lifetime according to gss_inquire_cred()
e58a44
+ *   acceptor cred lifetime according to gss_acquire_cred()
e58a44
+ *   acceptor cred lifetime according to gss_inquire_cred()
e58a44
+ *   initiator context lifetime according to gss_init_sec_context()
e58a44
+ *   initiator context lifetime according to gss_inquire_context()
e58a44
+ *   initiator context lifetime according to gss_context_time()
e58a44
+ *   acceptor context lifetime according to gss_init_sec_context()
e58a44
+ *   acceptor context lifetime according to gss_inquire_context()
e58a44
+ *   acceptor context lifetime according to gss_context_time()
e58a44
+ */
e58a44
+
e58a44
+static void
e58a44
+display_time(OM_uint32 tval)
e58a44
+{
e58a44
+    if (tval == GSS_C_INDEFINITE)
e58a44
+        puts("indefinite");
e58a44
+    else
e58a44
+        printf("%u\n", (unsigned int)tval);
e58a44
+}
e58a44
+
e58a44
+int
e58a44
+main(int argc, char *argv[])
e58a44
+{
e58a44
+    OM_uint32 minor, major;
e58a44
+    gss_cred_id_t icred, acred;
e58a44
+    gss_name_t tname;
e58a44
+    gss_ctx_id_t ictx = GSS_C_NO_CONTEXT, actx = GSS_C_NO_CONTEXT;
e58a44
+    gss_buffer_desc itok = GSS_C_EMPTY_BUFFER, atok = GSS_C_EMPTY_BUFFER;
e58a44
+    OM_uint32 time_req = GSS_C_INDEFINITE, time_rec;
e58a44
+
e58a44
+    if (argc < 2 || argc > 3) {
e58a44
+        fprintf(stderr, "Usage: %s targetname [time_req]\n", argv[0]);
e58a44
+        return 1;
e58a44
+    }
e58a44
+    tname = import_name(argv[1]);
e58a44
+    if (argc >= 3)
e58a44
+        time_req = atoll(argv[2]);
e58a44
+
e58a44
+    /* Get initiator cred and display its lifetime according to
e58a44
+     * gss_acquire_cred and gss_inquire_cred. */
e58a44
+    major = gss_acquire_cred(&minor, GSS_C_NO_NAME, time_req, &mechset_krb5,
e58a44
+                             GSS_C_INITIATE, &icred, NULL, &time_rec);
e58a44
+    check_gsserr("gss_acquire_cred(initiate)", major, minor);
e58a44
+    display_time(time_rec);
e58a44
+    major = gss_inquire_cred(&minor, icred, NULL, &time_rec, NULL, NULL);
e58a44
+    check_gsserr("gss_inquire_cred(initiate)", major, minor);
e58a44
+    display_time(time_rec);
e58a44
+
e58a44
+    /* Get acceptor cred and display its lifetime according to gss_acquire_cred
e58a44
+     * and gss_inquire_cred. */
e58a44
+    major = gss_acquire_cred(&minor, GSS_C_NO_NAME, time_req, &mechset_krb5,
e58a44
+                             GSS_C_ACCEPT, &acred, NULL, &time_rec);
e58a44
+    check_gsserr("gss_acquire_cred(accept)", major, minor);
e58a44
+    display_time(time_rec);
e58a44
+    major = gss_inquire_cred(&minor, acred, NULL, &time_rec, NULL, NULL);
e58a44
+    check_gsserr("gss_inquire_cred(accept)", major, minor);
e58a44
+    display_time(time_rec);
e58a44
+
e58a44
+    /* Make an initiator context and display its lifetime according to
e58a44
+     * gss_init_sec_context, gss_inquire_context, and gss_context_time. */
e58a44
+    major = gss_init_sec_context(&minor, icred, &ictx, tname, &mech_krb5, 0,
e58a44
+                                 time_req, GSS_C_NO_CHANNEL_BINDINGS, &atok,
e58a44
+                                 NULL, &itok, NULL, &time_rec);
e58a44
+    check_gsserr("gss_init_sec_context", major, minor);
e58a44
+    assert(major == GSS_S_COMPLETE);
e58a44
+    display_time(time_rec);
e58a44
+    major = gss_inquire_context(&minor, ictx, NULL, NULL, &time_rec, NULL,
e58a44
+                                NULL, NULL, NULL);
e58a44
+    check_gsserr("gss_inquire_context(initiate)", major, minor);
e58a44
+    display_time(time_rec);
e58a44
+    major = gss_context_time(&minor, ictx, &time_rec);
e58a44
+    check_gsserr("gss_context_time(initiate)", major, minor);
e58a44
+    display_time(time_rec);
e58a44
+
e58a44
+    major = gss_accept_sec_context(&minor, &actx, acred, &itok,
e58a44
+                                   GSS_C_NO_CHANNEL_BINDINGS, NULL,
e58a44
+                                   NULL, &atok, NULL, &time_rec, NULL);
e58a44
+    check_gsserr("gss_accept_sec_context", major, minor);
e58a44
+    assert(major == GSS_S_COMPLETE);
e58a44
+    display_time(time_rec);
e58a44
+    major = gss_inquire_context(&minor, actx, NULL, NULL, &time_rec, NULL,
e58a44
+                                NULL, NULL, NULL);
e58a44
+    check_gsserr("gss_inquire_context(accept)", major, minor);
e58a44
+    display_time(time_rec);
e58a44
+    major = gss_context_time(&minor, actx, &time_rec);
e58a44
+    check_gsserr("gss_context_time(accept)", major, minor);
e58a44
+    display_time(time_rec);
e58a44
+
e58a44
+    (void)gss_release_buffer(&minor, &itok);
e58a44
+    (void)gss_release_buffer(&minor, &atok);
e58a44
+    (void)gss_release_name(&minor, &tname);
e58a44
+    (void)gss_release_cred(&minor, &icred);
e58a44
+    (void)gss_release_cred(&minor, &acred);
e58a44
+    (void)gss_delete_sec_context(&minor, &ictx, NULL);
e58a44
+    (void)gss_delete_sec_context(&minor, &actx, NULL);
e58a44
+    return 0;
e58a44
+}
e58a44
diff --git a/src/tests/t_kdb.py b/src/tests/t_kdb.py
e58a44
index 185225afa..c0eeb0118 100755
e58a44
--- a/src/tests/t_kdb.py
e58a44
+++ b/src/tests/t_kdb.py
e58a44
@@ -446,6 +446,13 @@ realm.run([kadminl, 'addprinc', '-policy', 'keepoldpasspol', '-pw', 'aaaa',
e58a44
 for p in ('bbbb', 'cccc', 'aaaa'):
e58a44
     realm.run([kadminl, 'cpw', '-keepold', '-pw', p, 'keepoldpassprinc'])
e58a44
 
e58a44
+if runenv.sizeof_time_t <= 4:
e58a44
+    skipped('y2038 LDAP test', 'platform has 32-bit time_t')
e58a44
+else:
e58a44
+    # Test storage of timestamps after y2038.
e58a44
+    realm.run([kadminl, 'modprinc', '-pwexpire', '2040-02-03', 'user'])
e58a44
+    realm.run([kadminl, 'getprinc', 'user'], expected_msg=' 2040\n')
e58a44
+
e58a44
 realm.stop()
e58a44
 
e58a44
 # Briefly test dump and load.
e58a44
diff --git a/src/tests/t_y2038.py b/src/tests/t_y2038.py
e58a44
new file mode 100644
e58a44
index 000000000..02e946df4
e58a44
--- /dev/null
e58a44
+++ b/src/tests/t_y2038.py
e58a44
@@ -0,0 +1,75 @@
e58a44
+#!/usr/bin/python
e58a44
+from k5test import *
e58a44
+
e58a44
+# These tests will become much less important after the y2038 boundary
e58a44
+# has elapsed, and may start exhibiting problems around the year 2075.
e58a44
+
e58a44
+if runenv.sizeof_time_t <= 4:
e58a44
+    skip_rest('y2038 timestamp tests', 'platform has 32-bit time_t')
e58a44
+
e58a44
+# Start a KDC running roughly 21 years in the future, after the y2038
e58a44
+# boundary.  Set long maximum lifetimes for later tests.
e58a44
+conf = {'realms': {'$realm': {'max_life': '9000d',
e58a44
+                              'max_renewable_life': '9000d'}}}
e58a44
+realm = K5Realm(start_kdc=False, kdc_conf=conf)
e58a44
+realm.start_kdc(['-T', '662256000'])
e58a44
+
e58a44
+# kinit without preauth should succeed with clock skew correction, but
e58a44
+# will result in an expired ticket, because we sent an absolute end
e58a44
+# time and didn't get a chance to correct it..
e58a44
+realm.kinit(realm.user_princ, password('user'))
e58a44
+realm.run([kvno, realm.host_princ], expected_code=1,
e58a44
+          expected_msg='Ticket expired')
e58a44
+
e58a44
+# kinit with preauth should succeed and result in a valid ticket, as
e58a44
+# we get a chance to correct the end time based on the KDC time.  Try
e58a44
+# with encrypted timestamp and encrypted challenge.
e58a44
+realm.run([kadminl, 'modprinc', '+requires_preauth', 'user'])
e58a44
+realm.kinit(realm.user_princ, password('user'))
e58a44
+realm.run([kvno, realm.host_princ])
e58a44
+realm.kinit(realm.user_princ, password('user'), flags=['-T', realm.ccache])
e58a44
+realm.run([kvno, realm.host_princ])
e58a44
+
e58a44
+# Test that expiration warning works after y2038, by setting a
e58a44
+# password expiration time ten minutes after the KDC time.
e58a44
+realm.run([kadminl, 'modprinc', '-pwexpire', '662256600 seconds', 'user'])
e58a44
+out = realm.kinit(realm.user_princ, password('user'))
e58a44
+if 'will expire in less than one hour' not in out:
e58a44
+    fail('password expiration message')
e58a44
+year = int(out.split()[-1])
e58a44
+if year < 2038 or year > 9999:
e58a44
+    fail('password expiration year')
e58a44
+
e58a44
+realm.stop_kdc()
e58a44
+realm.start_kdc()
e58a44
+realm.start_kadmind()
e58a44
+realm.prep_kadmin()
e58a44
+
e58a44
+# Test getdate parsing of absolute timestamps after 2038 and
e58a44
+# marshalling over the kadmin protocol.  The local time zone will
e58a44
+# affect the display time by a little bit, so just look for the year.
e58a44
+realm.run_kadmin(['modprinc', '-pwexpire', '2040-02-03', realm.host_princ])
e58a44
+realm.run_kadmin(['getprinc', realm.host_princ], expected_msg=' 2040\n')
e58a44
+
e58a44
+# Get a ticket whose lifetime crosses the y2038 boundary and
e58a44
+# range-check the expiration year as reported by klist.
e58a44
+realm.kinit(realm.user_princ, password('user'),
e58a44
+            flags=['-l', '8000d', '-r', '8500d'])
e58a44
+realm.run([kvno, realm.host_princ])
e58a44
+out = realm.run([klist])
e58a44
+if int(out.split('\n')[4].split()[2].split('/')[2]) < 39:
e58a44
+    fail('unexpected tgt expiration year')
e58a44
+if int(out.split('\n')[5].split()[2].split('/')[2]) < 40:
e58a44
+    fail('unexpected tgt rtill year')
e58a44
+if int(out.split('\n')[6].split()[2].split('/')[2]) < 39:
e58a44
+    fail('unexpected service ticket expiration year')
e58a44
+if int(out.split('\n')[7].split()[2].split('/')[2]) < 40:
e58a44
+    fail('unexpected service ticket rtill year')
e58a44
+realm.kinit(realm.user_princ, None, ['-R'])
e58a44
+out = realm.run([klist])
e58a44
+if int(out.split('\n')[4].split()[2].split('/')[2]) < 39:
e58a44
+    fail('unexpected renewed tgt expiration year')
e58a44
+if int(out.split('\n')[5].split()[2].split('/')[2]) < 40:
e58a44
+    fail('unexpected renewed tgt rtill year')
e58a44
+
e58a44
+success('y2038 tests')