krb5 commit: Use cred marshalling functions in cc_file.c

Greg Hudson ghudson at MIT.EDU
Sat May 17 19:54:30 EDT 2014


https://github.com/krb5/krb5/commit/b99c7c79dee33de966c8bed02ac79439989f6f99
commit b99c7c79dee33de966c8bed02ac79439989f6f99
Author: Greg Hudson <ghudson at mit.edu>
Date:   Mon May 5 00:06:56 2014 -0400

    Use cred marshalling functions in cc_file.c
    
    Replace the cc_file.c credential and principal marshalling and
    unmarshalling functions with calls to the ccmarshal.c functions.  For
    unmarshalling, we still need code to read the appropriate amount of
    data into a memory buffer.  Because there is no outer length header
    for principals and credentials, this code needs to understand the
    credential and principal representations, but is much simpler than the
    old code as it only needs to store the data it reads, not assemble a
    data structure.

 src/lib/krb5/ccache/cc_file.c |  823 +++++++++--------------------------------
 1 files changed, 170 insertions(+), 653 deletions(-)

diff --git a/src/lib/krb5/ccache/cc_file.c b/src/lib/krb5/ccache/cc_file.c
index b2124f8..7b6279d 100644
--- a/src/lib/krb5/ccache/cc_file.c
+++ b/src/lib/krb5/ccache/cc_file.c
@@ -75,21 +75,6 @@ extern const krb5_cc_ops krb5_cc_file_ops;
 
 krb5_error_code krb5_change_cache(void);
 
-static krb5_error_code read_data(krb5_context, krb5_ccache id,
-                                 krb5_data *data);
-static krb5_error_code read32(krb5_context, krb5_ccache id, int32_t *i);
-static krb5_error_code read16(krb5_context, krb5_ccache id, uint16_t *i);
-static krb5_error_code read_addr(krb5_context context, krb5_ccache id,
-                                 krb5_address *addr);
-static krb5_error_code read_authdatum(krb5_context, krb5_ccache,
-                                      krb5_authdata *);
-static krb5_error_code store_data(krb5_context, krb5_ccache id,
-                                  krb5_data *data);
-static krb5_error_code store32(krb5_context, krb5_ccache id, uint32_t i);
-static krb5_error_code store16(krb5_context, krb5_ccache id, uint16_t i);
-static krb5_error_code store_addr(krb5_context, krb5_ccache, krb5_address *);
-static krb5_error_code store_authdatum(krb5_context, krb5_ccache,
-                                       krb5_authdata *);
 static krb5_error_code interpret_errno(krb5_context, int);
 
 #define FVNO_1 0x0501           /* krb v5, fcc v1 */
@@ -143,6 +128,24 @@ version(krb5_ccache id)
     return ((fcc_data *)id->data)->version - FVNO_1 + 1;
 }
 
+/* Get the size of the cache file as a size_t, or SIZE_MAX if it is too
+ * large to be represented as a size_t. */
+static krb5_error_code
+get_size(krb5_context context, krb5_ccache id, size_t *size_out)
+{
+    fcc_data *data = id->data;
+    struct stat sb;
+
+    k5_cc_mutex_assert_locked(context, &data->lock);
+    if (fstat(data->fd, &sb) == -1)
+        return interpret_errno(context, errno);
+    if (sizeof(off_t) > sizeof(size_t) && sb.st_size > (off_t)SIZE_MAX)
+        *size_out = SIZE_MAX;
+    else
+        *size_out = sb.st_size;
+    return 0;
+}
+
 /* Discard cached read information within data. */
 static inline void
 invalidate_cache(fcc_data *data)
@@ -207,8 +210,6 @@ typedef struct _krb5_fcc_cursor {
         }                                                               \
     }
 
-#define CHECK(ret) if (ret) goto errout;
-
 #define NO_FILE -1
 
 /* Read len bytes from the cache id, storing them in buf.  Return KRB5_CC_END
@@ -252,297 +253,10 @@ read_bytes(krb5_context context, krb5_ccache id, void *buf, unsigned int len)
     return 0;
 }
 
-/*
- * FOR ALL OF THE FOLLOWING FUNCTIONS:
- *
- * Requires:
- * id is open and set to read at the appropriate place in the file
- *
- * mutex is locked
- *
- * Effects:
- * Fills in the second argument with data of the appropriate type from
- * the file.  In some cases, the functions have to allocate space for
- * variable length fields; therefore, krb5_destroy_<type> must be
- * called for each filled in structure.
- *
- * Errors:
- * system errors (read errors)
- * KRB5_CC_NOMEM
- */
-
-#define ALLOC(NUM, TYPE)                            \
-    (((NUM) <= (((size_t)0 - 1) / sizeof(TYPE))) ?  \
-     (TYPE *)calloc((NUM), sizeof(TYPE)) :          \
-     (errno = ENOMEM, (TYPE *)0))
-
-static krb5_error_code
-read_principal(krb5_context context, krb5_ccache id, krb5_principal *princ)
-{
-    fcc_data *data = id->data;
-    krb5_error_code kret;
-    register krb5_principal tmpprinc;
-    int32_t length, type;
-    int i;
-
-    k5_cc_mutex_assert_locked(context, &data->lock);
-
-    *princ = NULL;
-
-    if (version(id) == 1) {
-        type = KRB5_NT_UNKNOWN;
-    } else {
-        /* Read principal type. */
-        kret = read32(context, id, &type);
-        if (kret)
-            return kret;
-    }
-
-    /* Read the number of components. */
-    kret = read32(context, id, &length);
-    if (kret)
-        return kret;
-
-    /*
-     * DCE includes the principal's realm in the count; the new format
-     * does not.
-     */
-    if (version(id) == 1)
-        length--;
-    if (length < 0)
-        return KRB5_CC_NOMEM;
-
-    tmpprinc = malloc(sizeof(*tmpprinc));
-    if (tmpprinc == NULL)
-        return KRB5_CC_NOMEM;
-    if (length) {
-        size_t msize = length;
-        if (msize != (uint32_t)length) {
-            free(tmpprinc);
-            return KRB5_CC_NOMEM;
-        }
-        tmpprinc->data = ALLOC(msize, krb5_data);
-        if (tmpprinc->data == 0) {
-            free(tmpprinc);
-            return KRB5_CC_NOMEM;
-        }
-    } else {
-        tmpprinc->data = 0;
-    }
-    tmpprinc->magic = KV5M_PRINCIPAL;
-    tmpprinc->length = length;
-    tmpprinc->type = type;
-
-    kret = read_data(context, id, &tmpprinc->realm);
-
-    i = 0;
-    CHECK(kret);
-
-    for (i = 0; i < length; i++) {
-        kret = read_data(context, id, &tmpprinc->data[i]);
-        CHECK(kret);
-    }
-    *princ = tmpprinc;
-    return 0;
-
-errout:
-    while (--i >= 0)
-        free(tmpprinc->data[i].data);
-    free(tmpprinc->realm.data);
-    free(tmpprinc->data);
-    free(tmpprinc);
-    return kret;
-}
-
-static krb5_error_code
-read_addrs(krb5_context context, krb5_ccache id, krb5_address ***addrs)
-{
-    krb5_error_code kret;
-    int32_t length;
-    size_t msize;
-    int i;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    *addrs = NULL;
-
-    /* Read the number of components */
-    kret = read32(context, id, &length);
-    CHECK(kret);
-
-    /* Make *addrs able to hold length pointers to krb5_address structs
-     * Add one extra for a null-terminated list */
-    msize = length;
-    msize += 1;
-    if (msize == 0 || msize - 1 != (uint32_t)length || length < 0)
-        return KRB5_CC_NOMEM;
-    *addrs = ALLOC(msize, krb5_address *);
-    if (*addrs == NULL)
-        return KRB5_CC_NOMEM;
-
-    for (i = 0; i < length; i++) {
-        (*addrs)[i] = malloc(sizeof(krb5_address));
-        if ((*addrs)[i] == NULL) {
-            krb5_free_addresses(context, *addrs);
-            *addrs = 0;
-            return KRB5_CC_NOMEM;
-        }
-        (*addrs)[i]->contents = NULL;
-        kret = read_addr(context, id, (*addrs)[i]);
-        CHECK(kret);
-    }
-
-    return 0;
-errout:
-    if (*addrs) {
-        krb5_free_addresses(context, *addrs);
-        *addrs = NULL;
-    }
-    return kret;
-}
-
-static krb5_error_code
-read_keyblock(krb5_context context, krb5_ccache id, krb5_keyblock *keyblock)
-{
-    krb5_error_code kret;
-    uint16_t ui2;
-    int32_t int32;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    keyblock->magic = KV5M_KEYBLOCK;
-    keyblock->contents = 0;
-
-    /* Enctype is signed, so sign-extend the 16-bit value we read. */
-    kret = read16(context, id, &ui2);
-    keyblock->enctype = (int16_t)ui2;
-    CHECK(kret);
-    if (version(id) == 3) {
-        /* This works because the old etype is the same as the new enctype. */
-        kret = read16(context, id, &ui2);
-        /* keyblock->enctype = ui2; */
-        CHECK(kret);
-    }
-
-    kret = read32(context, id, &int32);
-    CHECK(kret);
-    if (int32 < 0)
-        return KRB5_CC_NOMEM;
-    keyblock->length = int32;
-    /* Overflow check.  */
-    if (keyblock->length != (uint32_t)int32)
-        return KRB5_CC_NOMEM;
-    if (keyblock->length == 0)
-        return 0;
-    keyblock->contents = malloc(keyblock->length);
-    if (keyblock->contents == NULL)
-        return KRB5_CC_NOMEM;
-
-    kret = read_bytes(context, id, keyblock->contents, keyblock->length);
-    if (kret)
-        goto errout;
-
-    return 0;
-
-errout:
-    if (keyblock->contents) {
-        free(keyblock->contents);
-        keyblock->contents = NULL;
-    }
-    return kret;
-}
-
-static krb5_error_code
-read_data(krb5_context context, krb5_ccache id, krb5_data *data)
-{
-    krb5_error_code kret;
-    int32_t len;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    data->magic = KV5M_DATA;
-    data->data = 0;
-
-    kret = read32(context, id, &len);
-    CHECK(kret);
-    if (len < 0)
-        return KRB5_CC_NOMEM;
-    data->length = len;
-    if (data->length != (uint32_t)len || data->length + 1 == 0)
-        return KRB5_CC_NOMEM;
-
-    if (data->length == 0) {
-        data->data = NULL;
-        return 0;
-    }
-
-    data->data = malloc(data->length + 1);
-    if (data->data == NULL)
-        return KRB5_CC_NOMEM;
-
-    kret = read_bytes(context, id, data->data, data->length);
-    CHECK(kret);
-
-    data->data[data->length] = 0; /* Null terminate, just in case.... */
-    return 0;
-
-errout:
-    if (data->data) {
-        free(data->data);
-        data->data = NULL;
-    }
-    return kret;
-}
-
-static krb5_error_code
-read_addr(krb5_context context, krb5_ccache id, krb5_address *addr)
-{
-    krb5_error_code kret;
-    uint16_t ui2;
-    int32_t int32;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    addr->magic = KV5M_ADDRESS;
-    addr->contents = 0;
-
-    kret = read16(context, id, &ui2);
-    CHECK(kret);
-    addr->addrtype = ui2;
-
-    kret = read32(context, id, &int32);
-    CHECK(kret);
-    if ((int32 & VALID_INT_BITS) != int32)     /* Overflow int??? */
-        return KRB5_CC_NOMEM;
-    addr->length = int32;
-    /* Length field is "unsigned int", which may be smaller than 32 bits. */
-    if (addr->length != (uint32_t)int32)
-        return KRB5_CC_NOMEM;  /* XXX */
-
-    if (addr->length == 0)
-        return 0;
-
-    addr->contents = malloc(addr->length);
-    if (addr->contents == NULL)
-        return KRB5_CC_NOMEM;
-
-    kret = read_bytes(context, id, addr->contents, addr->length);
-    CHECK(kret);
-
-    return 0;
-
-errout:
-    if (addr->contents) {
-        free(addr->contents);
-        addr->contents = NULL;
-    }
-    return kret;
-}
-
 /* Load four bytes from the cache file and return their value as a 32-bit
- * signed integer according to the file format. */
+ * unsigned integer according to the file format.  Also append them to buf. */
 static krb5_error_code
-read32(krb5_context context, krb5_ccache id, int32_t *out)
+read32(krb5_context context, krb5_ccache id, struct k5buf *buf, uint32_t *out)
 {
     krb5_error_code ret;
     char bytes[4];
@@ -552,6 +266,8 @@ read32(krb5_context context, krb5_ccache id, int32_t *out)
     ret = read_bytes(context, id, bytes, 4);
     if (ret)
         return ret;
+    if (buf != NULL)
+        k5_buf_add_len(buf, bytes, 4);
     *out = (version(id) < 3) ? load_32_n(bytes) : load_32_be(bytes);
     return 0;
 }
@@ -573,142 +289,145 @@ read16(krb5_context context, krb5_ccache id, uint16_t *out)
     return 0;
 }
 
+/* Read len bytes from the cache file and add them to buf. */
 static krb5_error_code
-read_octet(krb5_context context, krb5_ccache id, unsigned char *i)
+load_bytes(krb5_context context, krb5_ccache id, size_t len, struct k5buf *buf)
 {
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-    return read_bytes(context, id, i, 1);
+    void *ptr;
+
+    ptr = k5_buf_get_space(buf, len);
+    return (ptr == NULL) ? ENOMEM : read_bytes(context, id, ptr, len);
 }
 
+/* Load a 32-bit length and data from the cache file into buf, but not more
+ * than maxsize bytes. */
 static krb5_error_code
-read_times(krb5_context context, krb5_ccache id, krb5_ticket_times *t)
+load_data(krb5_context context, krb5_ccache id, size_t maxsize,
+          struct k5buf *buf)
 {
-    fcc_data *data = id->data;
-    krb5_error_code retval;
-    int32_t i;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    if (data->version == FVNO_1 || data->version == FVNO_2) {
-        return read_bytes(context, id, t, sizeof(krb5_ticket_times));
-    } else {
-        retval = read32(context, id, &i);
-        CHECK(retval);
-        t->authtime = i;
+    krb5_error_code ret;
+    uint32_t count;
 
-        retval = read32(context, id, &i);
-        CHECK(retval);
-        t->starttime = i;
+    ret = read32(context, id, buf, &count);
+    if (ret)
+        return ret;
+    if (count > maxsize)
+        return KRB5_CC_FORMAT;
+    return load_bytes(context, id, count, buf);
+}
 
-        retval = read32(context, id, &i);
-        CHECK(retval);
-        t->endtime = i;
+/* Load a marshalled principal from the cache file into buf, without
+ * unmarshalling it. */
+static krb5_error_code
+load_principal(krb5_context context, krb5_ccache id, size_t maxsize,
+               struct k5buf *buf)
+{
+    krb5_error_code ret;
+    uint32_t count;
 
-        retval = read32(context, id, &i);
-        CHECK(retval);
-        t->renew_till = i;
+    if (version(id) > 1) {
+        ret = load_bytes(context, id, 4, buf);
+        if (ret)
+            return ret;
+    }
+    ret = read32(context, id, buf, &count);
+    if (ret)
+        return ret;
+    /* Add one for the realm (except in version 1 which already counts it). */
+    if (version(id) != 1)
+        count++;
+    while (count-- > 0) {
+        ret = load_data(context, id, maxsize, buf);
+        if (ret)
+            return ret;
     }
     return 0;
-errout:
-    return retval;
 }
 
+/* Load a marshalled credential from the cache file into buf, without
+ * unmarshalling it. */
 static krb5_error_code
-read_authdata(krb5_context context, krb5_ccache id, krb5_authdata ***a)
+load_cred(krb5_context context, krb5_ccache id, size_t maxsize,
+          struct k5buf *buf)
 {
-    krb5_error_code kret;
-    int32_t length;
-    size_t msize;
-    int i;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    *a = 0;
+    krb5_error_code ret;
+    uint32_t count, i;
 
-    /* Read the number of components */
-    kret = read32(context, id, &length);
-    CHECK(kret);
+    /* client and server */
+    ret = load_principal(context, id, maxsize, buf);
+    if (ret)
+        return ret;
+    ret = load_principal(context, id, maxsize, buf);
+    if (ret)
+        return ret;
 
-    if (length == 0)
-        return 0;
+    /* keyblock (enctype, enctype again for version 3, length, value) */
+    ret = load_bytes(context, id, (version(id) == 3) ? 4 : 2, buf);
+    if (ret)
+        return ret;
+    ret = load_data(context, id, maxsize, buf);
+    if (ret)
+        return ret;
 
-    /* Make *a able to hold length pointers to krb5_authdata structs
-     * Add one extra for a null-terminated list. */
-    msize = length;
-    msize += 1;
-    if (msize == 0 || msize - 1 != (uint32_t)length || length < 0)
-        return KRB5_CC_NOMEM;
-    *a = ALLOC(msize, krb5_authdata *);
-    if (*a == NULL)
-        return KRB5_CC_NOMEM;
+    /* times (4*4 bytes), is_skey (1 byte), ticket flags (4 bytes) */
+    ret = load_bytes(context, id, 4 * 4 + 1 + 4, buf);
+    if (ret)
+        return ret;
 
-    for (i = 0; i < length; i++) {
-        (*a)[i] = malloc(sizeof(krb5_authdata));
-        if ((*a)[i] == NULL) {
-            krb5_free_authdata(context, *a);
-            *a = NULL;
-            return KRB5_CC_NOMEM;
+    /* addresses and authdata, both lists of {type, length, data} */
+    for (i = 0; i < 2; i++) {
+        ret = read32(context, id, buf, &count);
+        if (ret)
+            return ret;
+        while (count-- > 0) {
+            ret = load_bytes(context, id, 2, buf);
+            if (ret)
+                return ret;
+            ret = load_data(context, id, maxsize, buf);
+            if (ret)
+                return ret;
         }
-        (*a)[i]->contents = NULL;
-        kret = read_authdatum(context, id, (*a)[i]);
-        CHECK(kret);
     }
 
-    return 0;
-errout:
-    if (*a) {
-        krb5_free_authdata(context, *a);
-        *a = NULL;
-    }
-    return kret;
+    /* ticket and second_ticket */
+    ret = load_data(context, id, maxsize, buf);
+    if (ret)
+        return ret;
+    return load_data(context, id, maxsize, buf);
 }
 
 static krb5_error_code
-read_authdatum(krb5_context context, krb5_ccache id, krb5_authdata *a)
+read_principal(krb5_context context, krb5_ccache id, krb5_principal *princ)
 {
-    krb5_error_code kret;
-    int32_t int32;
-    int16_t ui2; /* negative authorization data types are allowed */
+    krb5_error_code ret;
+    struct k5buf buf;
+    size_t maxsize;
+    unsigned char *bytes;
 
+    *princ = NULL;
     k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
+    k5_buf_init_dynamic(&buf);
 
-    a->magic = KV5M_AUTHDATA;
-    a->contents = NULL;
-
-    kret = read16(context, id, (uint16_t *)&ui2);
-    CHECK(kret);
-    a->ad_type = (krb5_authdatatype)ui2;
-    kret = read32(context, id, &int32);
-    CHECK(kret);
-    if ((int32 & VALID_INT_BITS) != int32)     /* Overflow int??? */
-        return KRB5_CC_NOMEM;
-    a->length = int32;
-    /* Value could have gotten truncated if int is smaller than 32 bits.  */
-    if (a->length != (uint32_t)int32)
-        return KRB5_CC_NOMEM;
-
-    if (a->length == 0)
-        return 0;
-
-    a->contents = malloc(a->length);
-    if (a->contents == NULL)
-        return KRB5_CC_NOMEM;
-
-    kret = read_bytes(context, id, a->contents, a->length);
-    CHECK(kret);
-
-    return 0;
-errout:
-    if (a->contents) {
-        free(a->contents);
-        a->contents = NULL;
+    /* Read the principal representation into memory. */
+    ret = get_size(context, id, &maxsize);
+    if (ret)
+        goto cleanup;
+    ret = load_principal(context, id, maxsize, &buf);
+    if (ret)
+        goto cleanup;
+    bytes = (unsigned char *)k5_buf_data(&buf);
+    if (bytes == NULL) {
+        ret = ENOMEM;
+        goto cleanup;
     }
-    return kret;
 
-}
-#undef CHECK
+    /* Unmarshal it from buf into princ. */
+    ret = k5_unmarshal_princ(bytes, k5_buf_len(&buf), version(id), princ);
 
-#define CHECK(ret) if (ret) return ret;
+cleanup:
+    k5_free_buf(&buf);
+    return ret;
+}
 
 /* Write len bytes from buf into the cache file.  Call with the mutex
  * locked. */
@@ -729,131 +448,6 @@ write_bytes(krb5_context context, krb5_ccache id, const void *buf,
     return 0;
 }
 
-/*
- * FOR ALL OF THE FOLLOWING FUNCTIONS:
- *
- * Requires:
- * ((fcc_data *)id->data)->fd is open and at the right position.
- *
- * mutex is locked
- *
- * Effects:
- * Stores an encoded version of the second argument in the
- * cache file.
- *
- * Errors:
- * system errors
- */
-
-static krb5_error_code
-store_principal(krb5_context context, krb5_ccache id, krb5_principal princ)
-{
-    fcc_data *data = id->data;
-    krb5_error_code ret;
-    int32_t i, length, tmp, type;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    type = princ->type;
-    tmp = length = princ->length;
-
-    if (data->version == FVNO_1) {
-        /*
-         * DCE-compatible format means that the length count
-         * includes the realm.  (It also doesn't include the
-         * principal type information.)
-         */
-        tmp++;
-    } else {
-        ret = store32(context, id, type);
-        CHECK(ret);
-    }
-
-    ret = store32(context, id, tmp);
-    CHECK(ret);
-
-    ret = store_data(context, id, &princ->realm);
-    CHECK(ret);
-
-    for (i = 0; i < length; i++) {
-        ret = store_data(context, id, &princ->data[i]);
-        CHECK(ret);
-    }
-
-    return 0;
-}
-
-static krb5_error_code
-store_addrs(krb5_context context, krb5_ccache id, krb5_address **addrs)
-{
-    krb5_error_code ret;
-    krb5_address **temp;
-    int32_t i, length = 0;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    /* Count the number of components */
-    if (addrs) {
-        temp = addrs;
-        while (*temp++)
-            length += 1;
-    }
-
-    ret = store32(context, id, length);
-    CHECK(ret);
-    for (i = 0; i < length; i++) {
-        ret = store_addr(context, id, addrs[i]);
-        CHECK(ret);
-    }
-
-    return 0;
-}
-
-static krb5_error_code
-store_keyblock(krb5_context context, krb5_ccache id, krb5_keyblock *keyblock)
-{
-    fcc_data *data = id->data;
-    krb5_error_code ret;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    ret = store16(context, id, keyblock->enctype);
-    CHECK(ret);
-    if (data->version == FVNO_3) {
-        ret = store16(context, id, keyblock->enctype);
-        CHECK(ret);
-    }
-    ret = store32(context, id, keyblock->length);
-    CHECK(ret);
-    return write_bytes(context, id, keyblock->contents, keyblock->length);
-}
-
-static krb5_error_code
-store_addr(krb5_context context, krb5_ccache id, krb5_address *addr)
-{
-    krb5_error_code ret;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    ret = store16(context, id, addr->addrtype);
-    CHECK(ret);
-    ret = store32(context, id, addr->length);
-    CHECK(ret);
-    return write_bytes(context, id, addr->contents, addr->length);
-}
-
-static krb5_error_code
-store_data(krb5_context context, krb5_ccache id, krb5_data *data)
-{
-    krb5_error_code ret;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    ret = store32(context, id, data->length);
-    CHECK(ret);
-    return write_bytes(context, id, data->data, data->length);
-}
-
 /* Store a 32-bit integer into the cache file according to the file format. */
 static krb5_error_code
 store32(krb5_context context, krb5_ccache id, uint32_t i)
@@ -885,73 +479,20 @@ store16(krb5_context context, krb5_ccache id, uint16_t i)
 }
 
 static krb5_error_code
-store_octet(krb5_context context, krb5_ccache id, unsigned char i)
-{
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    return write_bytes(context, id, &i, 1);
-}
-
-static krb5_error_code
-store_times(krb5_context context, krb5_ccache id, krb5_ticket_times *t)
-{
-    fcc_data *data = id->data;
-    krb5_error_code retval;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    if (data->version == FVNO_1 || data->version == FVNO_2) {
-        return write_bytes(context, id, t, sizeof(krb5_ticket_times));
-    } else {
-        retval = store32(context, id, t->authtime);
-        CHECK(retval);
-        retval = store32(context, id, t->starttime);
-        CHECK(retval);
-        retval = store32(context, id, t->endtime);
-        CHECK(retval);
-        retval = store32(context, id, t->renew_till);
-        CHECK(retval);
-        return 0;
-    }
-}
-
-static krb5_error_code
-store_authdata(krb5_context context, krb5_ccache id, krb5_authdata **a)
-{
-    krb5_error_code ret;
-    krb5_authdata **temp;
-    int32_t i, length = 0;
-
-    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    if (a != NULL) {
-        for (temp = a; *temp; temp++)
-            length++;
-    }
-
-    ret = store32(context, id, length);
-    CHECK(ret);
-    for (i = 0; i < length; i++) {
-        ret = store_authdatum(context, id, a[i]);
-        CHECK(ret);
-    }
-    return 0;
-}
-
-static krb5_error_code
-store_authdatum(krb5_context context, krb5_ccache id, krb5_authdata *a)
+store_principal(krb5_context context, krb5_ccache id, krb5_principal princ)
 {
     krb5_error_code ret;
+    unsigned char *bytes;
+    size_t len;
 
     k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);
-
-    ret = store16(context, id, a->ad_type);
-    CHECK(ret);
-    ret = store32(context, id, a->length);
-    CHECK(ret);
-    return write_bytes(context, id, a->contents, a->length);
+    ret = k5_marshal_princ(princ, version(id), &bytes, &len);
+    if (ret)
+        return ret;
+    ret = write_bytes(context, id, bytes, len);
+    free(bytes);
+    return ret;
 }
-#undef CHECK
 
 /* Unlock and close the cache file.  Call with the mutex locked. */
 static krb5_error_code
@@ -996,7 +537,7 @@ open_cache_file(krb5_context context, krb5_ccache id, int mode)
     fcc_data *data = id->data;
     char fcc_fvno[2];
     uint16_t fcc_flen, fcc_tag, fcc_taglen;
-    int32_t time_offset, usec_offset;
+    uint32_t time_offset, usec_offset;
     int f, open_flag, lock_flag, cnt;
     char buf[1024];
 
@@ -1139,8 +680,8 @@ open_cache_file(krb5_context context, krb5_ccache id, int mode)
                     }
                     break;
                 }
-                if (read32(context, id, &time_offset) ||
-                    read32(context, id, &usec_offset)) {
+                if (read32(context, id, NULL, &time_offset) ||
+                    read32(context, id, NULL, &usec_offset)) {
                     ret = KRB5_CC_FORMAT;
                     goto done;
                 }
@@ -1547,52 +1088,44 @@ static krb5_error_code KRB5_CALLCONV
 fcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor,
               krb5_creds *creds)
 {
-#define TCHECK(ret) if (ret) goto lose;
     krb5_error_code ret;
     krb5_fcc_cursor *fcursor = *cursor;
-    int32_t int32;
-    unsigned char octet;
     fcc_data *data = id->data;
+    struct k5buf buf;
+    size_t maxsize;
+    unsigned char *bytes;
 
     memset(creds, 0, sizeof(*creds));
     k5_cc_mutex_lock(context, &data->lock);
     MAYBE_OPEN(context, id, FCC_OPEN_RDONLY);
+    k5_buf_init_dynamic(&buf);
 
     if (fcc_lseek(data, fcursor->pos, SEEK_SET) == -1) {
         ret = interpret_errno(context, errno);
-        goto lose;
+        goto cleanup;
     }
 
-    ret = read_principal(context, id, &creds->client);
-    TCHECK(ret);
-    ret = read_principal(context, id, &creds->server);
-    TCHECK(ret);
-    ret = read_keyblock(context, id, &creds->keyblock);
-    TCHECK(ret);
-    ret = read_times(context, id, &creds->times);
-    TCHECK(ret);
-    ret = read_octet(context, id, &octet);
-    TCHECK(ret);
-    creds->is_skey = octet;
-    ret = read32(context, id, &int32);
-    TCHECK(ret);
-    creds->ticket_flags = int32;
-    ret = read_addrs(context, id, &creds->addresses);
-    TCHECK(ret);
-    ret = read_authdata(context, id, &creds->authdata);
-    TCHECK(ret);
-    ret = read_data(context, id, &creds->ticket);
-    TCHECK(ret);
-    ret = read_data(context, id, &creds->second_ticket);
-    TCHECK(ret);
+    /* Load a marshalled cred into memory. */
+    ret = get_size(context, id, &maxsize);
+    if (ret)
+        return ret;
+    ret = load_cred(context, id, maxsize, &buf);
+    if (ret)
+        goto cleanup;
+    bytes = (unsigned char *)k5_buf_data(&buf);
+    if (bytes == NULL) {
+        ret = ENOMEM;
+        goto cleanup;
+    }
 
+    /* Unmarshal it from buf into creds. */
     fcursor->pos = fcc_lseek(data, 0, SEEK_CUR);
+    ret = k5_unmarshal_cred(bytes, k5_buf_len(&buf), version(id), creds);
 
-lose:
+cleanup:
+    k5_free_buf(&buf);
     MAYBE_CLOSE(context, id, ret);
     k5_cc_mutex_unlock(context, &data->lock);
-    if (ret)
-        krb5_free_cred_contents(context, creds);
     return ret;
 }
 
@@ -1804,8 +1337,9 @@ fcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields,
 static krb5_error_code KRB5_CALLCONV
 fcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
 {
-#define TCHECK(ret) if (ret) goto lose;
     krb5_error_code ret;
+    unsigned char *bytes;
+    size_t len;
 
     k5_cc_mutex_lock(context, &((fcc_data *)id->data)->lock);
 
@@ -1821,33 +1355,16 @@ fcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
         return interpret_errno(context, errno);
     }
 
-    ret = store_principal(context, id, creds->client);
-    TCHECK(ret);
-    ret = store_principal(context, id, creds->server);
-    TCHECK(ret);
-    ret = store_keyblock(context, id, &creds->keyblock);
-    TCHECK(ret);
-    ret = store_times(context, id, &creds->times);
-    TCHECK(ret);
-    ret = store_octet(context, id, creds->is_skey);
-    TCHECK(ret);
-    ret = store32(context, id, creds->ticket_flags);
-    TCHECK(ret);
-    ret = store_addrs(context, id, creds->addresses);
-    TCHECK(ret);
-    ret = store_authdata(context, id, creds->authdata);
-    TCHECK(ret);
-    ret = store_data(context, id, &creds->ticket);
-    TCHECK(ret);
-    ret = store_data(context, id, &creds->second_ticket);
-    TCHECK(ret);
-
-lose:
+    ret = k5_marshal_cred(creds, version(id), &bytes, &len);
+    if (ret == 0) {
+        ret = write_bytes(context, id, bytes, len);
+        free(bytes);
+    }
+
     MAYBE_CLOSE(context, id, ret);
     k5_cc_mutex_unlock(context, &((fcc_data *)id->data)->lock);
     krb5_change_cache();
     return ret;
-#undef TCHECK
 }
 
 /* Non-functional stub for removing a cred from the cache file. */


More information about the cvs-krb5 mailing list