From a1a2eeb278cd0b504c9229cd7152f74463232fc4 Mon Sep 17 00:00:00 2001
From: Nicolas Williams <nico@twosigma.com>
Date: Thu, 21 May 2015 14:24:38 -0500
Subject: [PATCH 2/4] CVE-2022-42898 source4/heimdal: Add
 krb5_ret/store_[u]int64()

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15203

[jsutton@samba.org backported from Heimdal commit
 996d4c5db3c8aee10b7496591db13f52a575cef5; removed changes to
 lib/krb5/libkrb5-exports.def.in which we don't have]
---
 source4/heimdal/lib/krb5/store-int.c        |  13 +-
 source4/heimdal/lib/krb5/store.c            | 132 +++++++++++++++++---
 source4/heimdal/lib/krb5/version-script.map |   4 +
 3 files changed, 133 insertions(+), 16 deletions(-)

diff --git a/source4/heimdal/lib/krb5/store-int.c b/source4/heimdal/lib/krb5/store-int.c
index d5776297181..542b99abc08 100644
--- a/source4/heimdal/lib/krb5/store-int.c
+++ b/source4/heimdal/lib/krb5/store-int.c
@@ -34,7 +34,7 @@
 #include "krb5_locl.h"
 
 KRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL
-_krb5_put_int(void *buffer, unsigned long value, size_t size)
+_krb5_put_int(void *buffer, uint64_t value, size_t size)
 {
     unsigned char *p = buffer;
     int i;
@@ -46,7 +46,7 @@ _krb5_put_int(void *buffer, unsigned long value, size_t size)
 }
 
 KRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL
-_krb5_get_int(void *buffer, unsigned long *value, size_t size)
+_krb5_get_int64(void *buffer, uint64_t *value, size_t size)
 {
     unsigned char *p = buffer;
     unsigned long v = 0;
@@ -56,3 +56,12 @@ _krb5_get_int(void *buffer, unsigned long *value, size_t size)
     *value = v;
     return size;
 }
+
+KRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL
+_krb5_get_int(void *buffer, unsigned long *value, size_t size)
+{
+    uint64_t v64;
+    krb5_ssize_t bytes = _krb5_get_int64(buffer, &v64, size);
+    *value = v64;
+    return bytes;
+}
diff --git a/source4/heimdal/lib/krb5/store.c b/source4/heimdal/lib/krb5/store.c
index 31afb23c983..df0227b39de 100644
--- a/source4/heimdal/lib/krb5/store.c
+++ b/source4/heimdal/lib/krb5/store.c
@@ -318,13 +318,13 @@ krb5_storage_to_data(krb5_storage *sp, krb5_data *data)
 
 static krb5_error_code
 krb5_store_int(krb5_storage *sp,
-	       int32_t value,
+	       int64_t value,
 	       size_t len)
 {
     int ret;
-    unsigned char v[16];
+    unsigned char v[8];
 
-    if(len > sizeof(v))
+    if (len > sizeof(v))
 	return EINVAL;
     _krb5_put_int(v, value, len);
     ret = sp->store(sp, v, len);
@@ -358,6 +358,33 @@ krb5_store_int32(krb5_storage *sp,
     return krb5_store_int(sp, value, 4);
 }
 
+/**
+ * Store a int64 to storage, byte order is controlled by the settings
+ * on the storage, see krb5_storage_set_byteorder().
+ *
+ * @param sp the storage to write too
+ * @param value the value to store
+ *
+ * @return 0 for success, or a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+krb5_store_int64(krb5_storage *sp,
+		 int64_t value)
+{
+    if (BYTEORDER_IS_HOST(sp))
+#ifdef WORDS_BIGENDIAN
+        ;
+#else
+	value = bswap64(value); /* There's no ntohll() */
+#endif
+    else if (BYTEORDER_IS_LE(sp))
+	value = bswap64(value);
+    return krb5_store_int(sp, value, 8);
+}
+
 /**
  * Store a uint32 to storage, byte order is controlled by the settings
  * on the storage, see krb5_storage_set_byteorder().
@@ -377,24 +404,99 @@ krb5_store_uint32(krb5_storage *sp,
     return krb5_store_int32(sp, (int32_t)value);
 }
 
+/**
+ * Store a uint64 to storage, byte order is controlled by the settings
+ * on the storage, see krb5_storage_set_byteorder().
+ *
+ * @param sp the storage to write too
+ * @param value the value to store
+ *
+ * @return 0 for success, or a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+krb5_store_uint64(krb5_storage *sp,
+		  uint64_t value)
+{
+    return krb5_store_int64(sp, (int64_t)value);
+}
+
 static krb5_error_code
 krb5_ret_int(krb5_storage *sp,
-	     int32_t *value,
+	     int64_t *value,
 	     size_t len)
 {
     int ret;
-    unsigned char v[4];
-    unsigned long w;
+    unsigned char v[8];
+    uint64_t w;
     ret = sp->fetch(sp, v, len);
     if (ret < 0)
 	return errno;
     if ((size_t)ret != len)
 	return sp->eof_code;
-    _krb5_get_int(v, &w, len);
+    _krb5_get_int64(v, &w, len);
     *value = w;
     return 0;
 }
 
+/**
+ * Read a int64 from storage, byte order is controlled by the settings
+ * on the storage, see krb5_storage_set_byteorder().
+ *
+ * @param sp the storage to write too
+ * @param value the value read from the buffer
+ *
+ * @return 0 for success, or a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+krb5_ret_int64(krb5_storage *sp,
+	       int64_t *value)
+{
+    krb5_error_code ret = krb5_ret_int(sp, value, 8);
+    if(ret)
+	return ret;
+    if(BYTEORDER_IS_HOST(sp))
+#ifdef WORDS_BIGENDIAN
+        ;
+#else
+	*value = bswap64(*value); /* There's no ntohll() */
+#endif
+    else if(BYTEORDER_IS_LE(sp))
+	*value = bswap64(*value);
+    return 0;
+}
+
+/**
+ * Read a uint64 from storage, byte order is controlled by the settings
+ * on the storage, see krb5_storage_set_byteorder().
+ *
+ * @param sp the storage to write too
+ * @param value the value read from the buffer
+ *
+ * @return 0 for success, or a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+krb5_ret_uint64(krb5_storage *sp,
+		uint64_t *value)
+{
+    krb5_error_code ret;
+    int64_t v;
+
+    ret = krb5_ret_int64(sp, &v);
+    if (ret == 0)
+	*value = (uint64_t)v;
+
+    return ret;
+}
+
 /**
  * Read a int32 from storage, byte order is controlled by the settings
  * on the storage, see krb5_storage_set_byteorder().
@@ -411,12 +513,15 @@ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
 krb5_ret_int32(krb5_storage *sp,
 	       int32_t *value)
 {
-    krb5_error_code ret = krb5_ret_int(sp, value, 4);
-    if(ret)
+    int64_t v;
+
+    krb5_error_code ret = krb5_ret_int(sp, &v, 4);
+    if (ret)
 	return ret;
-    if(BYTEORDER_IS_HOST(sp))
+    *value = v;
+    if (BYTEORDER_IS_HOST(sp))
 	*value = htonl(*value);
-    else if(BYTEORDER_IS_LE(sp))
+    else if (BYTEORDER_IS_LE(sp))
 	*value = bswap32(*value);
     return 0;
 }
@@ -434,8 +539,7 @@ krb5_ret_int32(krb5_storage *sp,
  */
 
 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
-krb5_ret_uint32(krb5_storage *sp,
-		uint32_t *value)
+krb5_ret_uint32(krb5_storage *sp, uint32_t *value)
 {
     krb5_error_code ret;
     int32_t v;
@@ -505,7 +609,7 @@ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
 krb5_ret_int16(krb5_storage *sp,
 	       int16_t *value)
 {
-    int32_t v = 0;
+    int64_t v;
     int ret;
     ret = krb5_ret_int(sp, &v, 2);
     if(ret)
diff --git a/source4/heimdal/lib/krb5/version-script.map b/source4/heimdal/lib/krb5/version-script.map
index 2359001e9da..d0412c08d59 100644
--- a/source4/heimdal/lib/krb5/version-script.map
+++ b/source4/heimdal/lib/krb5/version-script.map
@@ -550,6 +550,7 @@ HEIMDAL_KRB5_2.0 {
 		krb5_ret_data;
 		krb5_ret_int16;
 		krb5_ret_int32;
+		krb5_ret_int64;
 		krb5_ret_int8;
 		krb5_ret_keyblock;
 		krb5_ret_principal;
@@ -559,6 +560,7 @@ HEIMDAL_KRB5_2.0 {
 		krb5_ret_times;
 		krb5_ret_uint16;
 		krb5_ret_uint32;
+		krb5_ret_uint64;
 		krb5_ret_uint8;
 		krb5_salttype_to_string;
 		krb5_sendauth;
@@ -623,6 +625,7 @@ HEIMDAL_KRB5_2.0 {
 		krb5_store_data;
 		krb5_store_int16;
 		krb5_store_int32;
+		krb5_store_int64;
 		krb5_store_int8;
 		krb5_store_keyblock;
 		krb5_store_principal;
@@ -632,6 +635,7 @@ HEIMDAL_KRB5_2.0 {
 		krb5_store_times;
 		krb5_store_uint16;
 		krb5_store_uint32;
+		krb5_store_uint64;
 		krb5_store_uint8;
 		krb5_string_to_deltat;
 		krb5_string_to_enctype;
-- 
2.35.0

