pull up r21927, r21928, r21940, r21969, r21981, r22004 from trunk
authorTom Yu <tlyu@mit.edu>
Mon, 13 Apr 2009 20:26:35 +0000 (20:26 +0000)
committerTom Yu <tlyu@mit.edu>
Mon, 13 Apr 2009 20:26:35 +0000 (20:26 +0000)
------------------------------------------------------------------------
r22004 | ghudson | 2009-02-13 17:05:48 -0500 (Fri, 13 Feb 2009) | 3 lines
Changed paths:
   M /trunk/src/lib/krb5/asn.1/asn1_k_decode.c
   M /trunk/src/lib/krb5/asn.1/asn1_k_decode.h
   M /trunk/src/lib/krb5/asn.1/krb5_decode.c

Correct numerous memory leaks on error conditions in the ASN.1
decoder functions.

------------------------------------------------------------------------
r21981 | ghudson | 2009-02-12 13:21:33 -0500 (Thu, 12 Feb 2009) | 4 lines
Changed paths:
   M /trunk/src/lib/krb5/asn.1/asn1_encode.c
   M /trunk/src/lib/krb5/asn.1/asn1buf.c

Modify asn12krb5_buf and asn1_do_full_encode to make output parameter
values well-defined on error.  Clean up memory handling and an unused
variable in asn1_do_full_encode.

------------------------------------------------------------------------
r21969 | ghudson | 2009-02-11 15:18:43 -0500 (Wed, 11 Feb 2009) | 6 lines
Changed paths:
   M /trunk/src/include/k5-int.h
   M /trunk/src/lib/krb5/krb/kfree.c
   M /trunk/src/lib/krb5/libkrb5.exports

Ensure we have a free function for every data type we have an ASN.1
decoder for.  Export the new free functions, but only declare them
in k5-int.h since they shouldn't be needed by applications.  Also
export a couple of encoder and decoder functions not previously
exported.

------------------------------------------------------------------------
r21940 | ghudson | 2009-02-09 21:01:58 -0500 (Mon, 09 Feb 2009) | 5 lines
Changed paths:
   M /trunk/src/lib/krb5/asn.1/krb5_decode.c

Adjust the structure of krb5_decode.c functions to initialize output
parameters to NULL and not set them to the real values until a
successful return is guaranteed.  Also fix get_eoc which was returning
without clean_return.

------------------------------------------------------------------------
r21928 | ghudson | 2009-02-09 16:25:53 -0500 (Mon, 09 Feb 2009) | 4 lines
Changed paths:
   M /trunk/src/lib/krb5/asn.1/asn1buf.c
   M /trunk/src/lib/krb5/asn.1/asn1buf.h
   M /trunk/src/lib/krb5/asn.1/krb5_encode.c

Make asn1buf_destroy return void, since it's a free function.  In
krb5_encode.c functions, make *code well-defined in case of error,
and clean up some memory leaks.

------------------------------------------------------------------------
r21927 | ghudson | 2009-02-09 16:23:00 -0500 (Mon, 09 Feb 2009) | 3 lines
Changed paths:
   M /trunk/src/lib/krb5/asn.1/asn1_k_encode.c

In asn1_k_encode.c, stop inconsistently destroying buf on some errors.
It belongs to the caller.

ticket: 6425
version_fixed: 1.7

git-svn-id: svn://anonsvn.mit.edu/krb5/branches/krb5-1-7@22207 dc483132-0cff-0310-8789-dd5450dbe970

src/include/k5-int.h
src/lib/krb5/asn.1/asn1_encode.c
src/lib/krb5/asn.1/asn1_k_decode.c
src/lib/krb5/asn.1/asn1_k_decode.h
src/lib/krb5/asn.1/asn1_k_encode.c
src/lib/krb5/asn.1/asn1buf.c
src/lib/krb5/asn.1/asn1buf.h
src/lib/krb5/asn.1/krb5_decode.c
src/lib/krb5/asn.1/krb5_encode.c
src/lib/krb5/krb/kfree.c
src/lib/krb5/libkrb5.exports

index 2a73127bd6e5a27e23ad81f2a9eadb48f6f322a7..2b937112d1faa708a74b68bf67784bd9b8d06587 100644 (file)
@@ -2537,6 +2537,12 @@ void KRB5_CALLCONV krb5_free_pwd_data
        (krb5_context, krb5_pwd_data *);
 void KRB5_CALLCONV krb5_free_pwd_sequences
        (krb5_context, passwd_phrase_element **);
+void KRB5_CALLCONV krb5_free_passwd_phrase_element
+       (krb5_context, passwd_phrase_element *);
+void KRB5_CALLCONV krb5_free_alt_method
+       (krb5_context, krb5_alt_method *);
+void KRB5_CALLCONV krb5_free_enc_data
+       (krb5_context, krb5_enc_data *);
 krb5_error_code krb5_set_config_files
        (krb5_context, const char **);
 
index d7954649397fe09cd7002befa653be8b0149d6b7..f67c8cfee13f0b2811b841db0c757ab9107440c8 100644 (file)
@@ -675,10 +675,13 @@ krb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
 {
     unsigned int length;
     asn1_error_code retval;
-    unsigned int sum = 0;
     asn1buf *buf = NULL;
+    krb5_data *d;
+
+    *code = NULL;
 
-    if (rep == NULL) return ASN1_MISSING_FIELD;
+    if (rep == NULL)
+        return ASN1_MISSING_FIELD;
 
     retval = asn1buf_create(&buf);
     if (retval)
@@ -686,9 +689,12 @@ krb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
 
     retval = krb5int_asn1_encode_a_thing(buf, rep, a, &length);
     if (retval)
-        return retval;
-    sum += length;
-    retval = asn12krb5_buf(buf, code);
+        goto cleanup;
+    retval = asn12krb5_buf(buf, &d);
+    if (retval)
+        goto cleanup;
+    *code = d;
+cleanup:
     asn1buf_destroy(&buf);
     return retval;
 }
index cc3168c005394790ec4395df1a2a71f131cdea56..c5d200628e107e2b64629bf8f7b4da669e808d45 100644 (file)
@@ -30,6 +30,8 @@
 #include "asn1_get.h"
 #include "asn1_misc.h"
 
+#define clean_return(val) { retval = val; goto error_out; }
+
 /* Declare useful decoder variables. */
 #define setup()                                 \
   asn1_error_code retval;                       \
@@ -44,7 +46,7 @@
 #define next_tag()                                                              \
 { taginfo t2;                                                                   \
   retval = asn1_get_tag_2(&subbuf, &t2);                                        \
-  if (retval) return retval;                                                    \
+  if (retval) clean_return(retval);                                             \
   /* Copy out to match previous functionality, until better integrated.  */     \
   asn1class = t2.asn1class;                                                     \
   construction = t2.construction;                                               \
@@ -71,21 +73,38 @@ asn1_get_eoc_tag (asn1buf *buf)
 #define get_eoc()                               \
     {                                           \
         retval = asn1_get_eoc_tag(&subbuf);     \
-        if (retval) return retval;              \
+        if (retval) clean_return(retval);       \
     }
 
-#define alloc_field(var, type)                  \
-  var = (type*)calloc(1, sizeof(type));         \
-  if ((var) == NULL) return ENOMEM
+#define alloc_field(var)                        \
+  var = calloc(1, sizeof(*var));                \
+  if ((var) == NULL) clean_return(ENOMEM)
+
+/*
+ * Allocate a principal and initialize enough fields for
+ * krb5_free_principal to have defined behavior.
+ */
+#define alloc_principal(var)                    \
+  alloc_field(var);                             \
+  var->realm.data = NULL;                       \
+  var->data = NULL
+
+/*
+ * Allocate a data structure and initialize enough fields for
+ * krb5_free_data to have defined behavior.
+ */
+#define alloc_data(var)                         \
+  alloc_field(var);                             \
+  var->data = NULL
 
 /* Fetch an expected APPLICATION class tag and verify. */
 #define apptag(tagexpect)                                                               \
   {                                                                                     \
       taginfo t1;                                                                       \
       retval = asn1_get_tag_2(buf, &t1);                                                \
-      if (retval) return retval;                                                        \
+      if (retval) clean_return(retval);                                                 \
       if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED ||              \
-          t1.tagnum != (tagexpect)) return ASN1_BAD_ID;                                 \
+          t1.tagnum != (tagexpect)) clean_return(ASN1_BAD_ID);                          \
       /* Copy out to match previous functionality, until better integrated.  */         \
       asn1class = t1.asn1class;                                                         \
       construction = t1.construction;                                                   \
@@ -104,7 +123,7 @@ asn1_get_eoc_tag (asn1buf *buf)
  */
 #define get_field_body(var, decoder)            \
   retval = decoder(&subbuf, &(var));            \
-  if (retval) return retval;                    \
+  if (retval) clean_return(retval);            \
   if (!taglen && indef) { get_eoc(); }          \
   next_tag()
 
@@ -115,7 +134,7 @@ asn1_get_eoc_tag (asn1buf *buf)
  * if not.
  */
 #define error_if_bad_tag(tagexpect) \
-  if (tagnum != (tagexpect)) { return (tagnum < (tagexpect)) ? ASN1_MISPLACED_FIELD : ASN1_MISSING_FIELD; }
+  if (tagnum != (tagexpect)) { clean_return((tagnum < (tagexpect)) ? ASN1_MISPLACED_FIELD : ASN1_MISSING_FIELD); }
 
 /*
  * get_field
@@ -128,7 +147,7 @@ asn1_get_eoc_tag (asn1buf *buf)
   error_if_bad_tag(tagexpect);                                          \
   if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)    \
       && (tagnum || taglen || asn1class != UNIVERSAL))                  \
-    return ASN1_BAD_ID;                                                 \
+    clean_return(ASN1_BAD_ID);                                          \
   get_field_body(var,decoder)
 
 /*
@@ -143,7 +162,7 @@ asn1_get_eoc_tag (asn1buf *buf)
   if (asn1buf_remains(&subbuf, seqindef)) {                             \
     if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)  \
         && (tagnum || taglen || asn1class != UNIVERSAL))                \
-      return ASN1_BAD_ID;                                               \
+      clean_return(ASN1_BAD_ID);                                        \
     if (tagnum == (tagexpect)) {                                        \
       get_field_body(var, decoder);                                     \
     } else var = optvalue;                                              \
@@ -154,7 +173,7 @@ asn1_get_eoc_tag (asn1buf *buf)
 /* similar to get_field_body */
 #define get_lenfield_body(len, var, decoder)    \
   retval = decoder(&subbuf, &(len), &(var));    \
-  if (retval) return retval;                    \
+  if (retval) clean_return(retval);             \
   if (!taglen && indef) { get_eoc(); }          \
   next_tag()
 
@@ -163,7 +182,7 @@ asn1_get_eoc_tag (asn1buf *buf)
   error_if_bad_tag(tagexpect);                                          \
   if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)    \
       && (tagnum || taglen || asn1class != UNIVERSAL))                  \
-    return ASN1_BAD_ID;                                                 \
+    clean_return(ASN1_BAD_ID);                                          \
   get_lenfield_body(len, var, decoder)
 
 /* similar to opt_field */
@@ -176,20 +195,20 @@ asn1_get_eoc_tag (asn1buf *buf)
  * Deal with implicitly tagged fields
  */
 #define get_implicit_octet_string(len, var, tagexpect)              \
-  if (tagnum != (tagexpect)) return ASN1_MISSING_FIELD;             \
+  if (tagnum != (tagexpect)) clean_return(ASN1_MISSING_FIELD);      \
   if (asn1class != CONTEXT_SPECIFIC || construction != PRIMITIVE)   \
-     return ASN1_BAD_ID;                                            \
+    clean_return(ASN1_BAD_ID);                                      \
   retval = asn1buf_remove_octetstring(&subbuf, taglen, &(var));     \
-  if (retval) return retval;                                        \
+  if (retval) clean_return(retval);                                 \
   (len) = taglen;                                                   \
   next_tag()
 
 #define opt_implicit_octet_string(len, var, tagexpect)              \
   if (tagnum == (tagexpect)) {                                      \
     if (asn1class != CONTEXT_SPECIFIC || construction != PRIMITIVE) \
-        return ASN1_BAD_ID;                                         \
+        clean_return(ASN1_BAD_ID);                                  \
     retval = asn1buf_remove_octetstring(&subbuf, taglen, &(var));   \
-    if (retval) return retval;                                      \
+    if (retval) clean_return(retval);                               \
     (len) = taglen;                                                 \
     next_tag();                                                     \
   } else { (len) = 0; (var) = NULL; }
@@ -206,9 +225,9 @@ asn1_get_eoc_tag (asn1buf *buf)
   int seqindef;                                                 \
   int indef;                                                    \
   retval = asn1_get_sequence(buf, &length, &seqindef);          \
-  if (retval) return retval;                                    \
+  if (retval) clean_return(retval);                             \
   retval = asn1buf_imbed(&subbuf, buf, length, seqindef);       \
-  if (retval) return retval;                                    \
+  if (retval) clean_return(retval);                             \
   next_tag()
 
 /*
@@ -221,15 +240,15 @@ asn1_get_eoc_tag (asn1buf *buf)
   int seqindef;                                                 \
   int indef;                                                    \
   retval = asn1_get_sequence(buf, &length, &seqindef);          \
-  if (retval) return retval;                                    \
+  if (retval) clean_return(retval);                             \
   retval = asn1buf_imbed(&subbuf, buf, length, seqindef);       \
-  if (retval) return retval
+  if (retval) clean_return(retval)
 
 /* skip trailing garbage */
 #define end_structure()                                         \
   retval = asn1buf_sync(buf, &subbuf, asn1class, tagnum,        \
                         length, indef, seqindef);               \
-  if (retval) return retval
+  if (retval) clean_return(retval)
 
 /*
  * begin_choice
@@ -244,7 +263,7 @@ asn1_get_eoc_tag (asn1buf *buf)
   int indef;                                                    \
   taginfo t;                                                    \
   retval = asn1_get_tag_2(buf, &t);                             \
-  if (retval) return retval;                                    \
+  if (retval) clean_return(retval);                             \
   tagnum = t.tagnum;                                            \
   taglen = t.length;                                            \
   indef = t.indef;                                              \
@@ -253,14 +272,14 @@ asn1_get_eoc_tag (asn1buf *buf)
   asn1class = t.asn1class;                                      \
   construction = t.construction;                                \
   retval = asn1buf_imbed(&subbuf, buf, length, seqindef);       \
-  if (retval) return retval
+  if (retval) clean_return(retval)
 
 /* skip trailing garbage */
 #define end_choice()                                            \
   length -= t.length;                                           \
   retval = asn1buf_sync(buf, &subbuf, t.asn1class, t.tagnum,    \
                         length, t.indef, seqindef);             \
-  if (retval) return retval
+  if (retval) clean_return(retval)
 
 /*
  * sequence_of
@@ -295,13 +314,12 @@ asn1_get_eoc_tag (asn1buf *buf)
  * does not prefetch the next tag.
  */
 #define sequence_of_common(buf)                                 \
-  int size = 0;                                                 \
   asn1buf seqbuf;                                               \
   int seqofindef;                                               \
   retval = asn1_get_sequence(buf, &length, &seqofindef);        \
-  if (retval) return retval;                                    \
+  if (retval) clean_return(retval);                             \
   retval = asn1buf_imbed(&seqbuf, buf, length, seqofindef);     \
-  if (retval) return retval
+  if (retval) clean_return(retval)
 
 /*
  * end_sequence_of
@@ -313,7 +331,7 @@ asn1_get_eoc_tag (asn1buf *buf)
   {                                                                             \
       taginfo t4;                                                               \
       retval = asn1_get_tag_2(&seqbuf, &t4);                                    \
-      if (retval) return retval;                                                \
+      if (retval) clean_return(retval);                                         \
       /* Copy out to match previous functionality, until better integrated.  */ \
       asn1class = t4.asn1class;                                                 \
       construction = t4.construction;                                           \
@@ -323,7 +341,7 @@ asn1_get_eoc_tag (asn1buf *buf)
   }                                                                             \
   retval = asn1buf_sync(buf, &seqbuf, asn1class, tagnum,                        \
                         length, indef, seqofindef);                             \
-  if (retval) return retval;
+  if (retval) clean_return(retval);
 
 /*
  * end_sequence_of_no_tagvars
@@ -348,8 +366,28 @@ end_sequence_of_no_tagvars_helper(asn1buf *buf, asn1buf *seqbufp,
 #define end_sequence_of_no_tagvars(buf) \
     end_sequence_of_no_tagvars_helper(buf, &seqbuf, seqofindef)
 
-#define cleanup()                               \
-  return 0
+/*
+ * Function body for a pointer decoder, which allocates a pointer
+ * field and invokes a structure decoder to fill it in.  Pointer
+ * decoders always fill in their output parameters with NULL (on
+ * error) or a valid constructed structure, making cleanup easier on
+ * callers.
+ */
+#define decode_ptr(type, structure_decoder) \
+    type val; \
+    asn1_error_code retval; \
+\
+    *valptr = NULL; \
+    val = calloc(1, sizeof(*val)); \
+    if (!val) \
+        return ENOMEM; \
+    retval = structure_decoder(buf, val); \
+    if (retval) { \
+        free(val); \
+        return retval; \
+    } \
+    *valptr = val; \
+    return 0;
 
 /* scalars */
 asn1_error_code asn1_decode_kerberos_time(asn1buf *buf, krb5_timestamp *val)
@@ -430,25 +468,27 @@ asn1_error_code asn1_decode_realm(asn1buf *buf, krb5_principal *val)
 
 asn1_error_code asn1_decode_principal_name(asn1buf *buf, krb5_principal *val)
 {
+    int size = 0, i;
+    krb5_data *array = NULL, *new_array;
+
     setup();
     { begin_structure();
         get_field((*val)->type,0,asn1_decode_int32);
 
         { sequence_of_no_tagvars(&subbuf);
             while (asn1buf_remains(&seqbuf,seqofindef) > 0) {
+                unsigned int len;
+                char *str;
+
+                new_array = realloc(array, (size + 1) * sizeof(krb5_data));
+                if (new_array == NULL) clean_return(ENOMEM);
+                array = new_array;
+                retval = asn1_decode_generalstring(&seqbuf, &len, &str);
+                if (retval) clean_return(retval);
+                array[size].data = str;
+                array[size].length = len;
                 size++;
-                if ((*val)->data == NULL)
-                    (*val)->data = (krb5_data*)malloc(size*sizeof(krb5_data));
-                else
-                    (*val)->data = (krb5_data*)realloc((*val)->data,
-                                                       size*sizeof(krb5_data));
-                if ((*val)->data == NULL) return ENOMEM;
-                retval = asn1_decode_generalstring(&seqbuf,
-                                                   &((*val)->data[size-1].length),
-                                                   &((*val)->data[size-1].data));
-                if (retval) return retval;
             }
-            (*val)->length = size;
             end_sequence_of_no_tagvars(&subbuf);
         }
         if (indef) {
@@ -456,38 +496,65 @@ asn1_error_code asn1_decode_principal_name(asn1buf *buf, krb5_principal *val)
         }
         next_tag();
         end_structure();
-        (*val)->magic = KV5M_PRINCIPAL;
     }
-    cleanup();
+    (*val)->data = array;
+    (*val)->length = size;
+    (*val)->magic = KV5M_PRINCIPAL;
+    return 0;
+error_out:
+    for (i = 0; i < size; i++)
+        free(array[i].data);
+    free(array);
+    return retval;
 }
 
 asn1_error_code asn1_decode_checksum(asn1buf *buf, krb5_checksum *val)
 {
     setup();
+    val->contents = NULL;
     { begin_structure();
         get_field(val->checksum_type,0,asn1_decode_cksumtype);
         get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
         end_structure();
         val->magic = KV5M_CHECKSUM;
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->contents);
+    return retval;
+}
+
+asn1_error_code asn1_decode_checksum_ptr(asn1buf *buf, krb5_checksum **valptr)
+{
+    decode_ptr(krb5_checksum *, asn1_decode_checksum);
 }
 
 asn1_error_code asn1_decode_encryption_key(asn1buf *buf, krb5_keyblock *val)
 {
     setup();
+    val->contents = NULL;
     { begin_structure();
         get_field(val->enctype,0,asn1_decode_enctype);
         get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
         end_structure();
         val->magic = KV5M_KEYBLOCK;
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->contents);
+    return retval;
+}
+
+asn1_error_code
+asn1_decode_encryption_key_ptr(asn1buf *buf, krb5_keyblock **valptr)
+{
+    decode_ptr(krb5_keyblock *, asn1_decode_encryption_key);
 }
 
 asn1_error_code asn1_decode_encrypted_data(asn1buf *buf, krb5_enc_data *val)
 {
     setup();
+    val->ciphertext.data = NULL;
     { begin_structure();
         get_field(val->enctype,0,asn1_decode_enctype);
         opt_field(val->kvno,1,asn1_decode_kvno,0);
@@ -495,7 +562,11 @@ asn1_error_code asn1_decode_encrypted_data(asn1buf *buf, krb5_enc_data *val)
         end_structure();
         val->magic = KV5M_ENC_DATA;
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->ciphertext.data);
+    val->ciphertext.data = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_krb5_flags(asn1buf *buf, krb5_flags *val)
@@ -551,21 +622,28 @@ asn1_error_code asn1_decode_kdc_options(asn1buf *buf, krb5_flags *val)
 asn1_error_code asn1_decode_transited_encoding(asn1buf *buf, krb5_transited *val)
 {
     setup();
+    val->tr_contents.data = NULL;
     { begin_structure();
         get_field(val->tr_type,0,asn1_decode_octet);
         get_lenfield(val->tr_contents.length,val->tr_contents.data,1,asn1_decode_charstring);
         end_structure();
         val->magic = KV5M_TRANSITED;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_data_contents(NULL, &val->tr_contents);
+    return retval;
 }
 
 asn1_error_code asn1_decode_enc_kdc_rep_part(asn1buf *buf, krb5_enc_kdc_rep_part *val)
 {
     setup();
+    val->session = NULL;
+    val->last_req = NULL;
+    val->server = NULL;
+    val->caddrs = NULL;
     { begin_structure();
-        alloc_field(val->session,krb5_keyblock);
-        get_field(*(val->session),0,asn1_decode_encryption_key);
+        get_field(val->session,0,asn1_decode_encryption_key_ptr);
         get_field(val->last_req,1,asn1_decode_last_req);
         get_field(val->nonce,2,asn1_decode_int32);
         opt_field(val->key_exp,3,asn1_decode_kerberos_time,0);
@@ -575,7 +653,7 @@ asn1_error_code asn1_decode_enc_kdc_rep_part(asn1buf *buf, krb5_enc_kdc_rep_part
         opt_field(val->times.starttime,6,asn1_decode_kerberos_time,val->times.authtime);
         get_field(val->times.endtime,7,asn1_decode_kerberos_time);
         opt_field(val->times.renew_till,8,asn1_decode_kerberos_time,0);
-        alloc_field(val->server,krb5_principal_data);
+        alloc_principal(val->server);
         get_field(val->server,9,asn1_decode_realm);
         get_field(val->server,10,asn1_decode_principal_name);
         opt_field(val->caddrs,11,asn1_decode_host_addresses,NULL);
@@ -583,7 +661,17 @@ asn1_error_code asn1_decode_enc_kdc_rep_part(asn1buf *buf, krb5_enc_kdc_rep_part
         end_structure();
         val->magic = KV5M_ENC_KDC_REP_PART;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_keyblock(NULL, val->session);
+    krb5_free_last_req(NULL, val->last_req);
+    krb5_free_principal(NULL, val->server);
+    krb5_free_addresses(NULL, val->caddrs);
+    val->session = NULL;
+    val->last_req = NULL;
+    val->server = NULL;
+    val->caddrs = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_ticket(asn1buf *buf, krb5_ticket *val)
@@ -591,11 +679,14 @@ asn1_error_code asn1_decode_ticket(asn1buf *buf, krb5_ticket *val)
     setup();
     unsigned int applen;
     apptag(1);
+    val->server = NULL;
+    val->enc_part.ciphertext.data = NULL;
+    val->enc_part2 = NULL;
     { begin_structure();
         { krb5_kvno vno;
             get_field(vno,0,asn1_decode_kvno);
-            if (vno != KVNO) return KRB5KDC_ERR_BAD_PVNO; }
-        alloc_field(val->server,krb5_principal_data);
+            if (vno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
+        alloc_principal(val->server);
         get_field(val->server,1,asn1_decode_realm);
         get_field(val->server,2,asn1_decode_principal_name);
         get_field(val->enc_part,3,asn1_decode_encrypted_data);
@@ -605,41 +696,64 @@ asn1_error_code asn1_decode_ticket(asn1buf *buf, krb5_ticket *val)
     if (!applen) {
         taginfo t;
         retval = asn1_get_tag_2(buf, &t);
-        if (retval) return retval;
+        if (retval) clean_return(retval);
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_principal(NULL, val->server);
+    krb5_free_data_contents(NULL, &val->enc_part.ciphertext);
+    val->server = NULL;
+    return retval;
+}
+
+asn1_error_code
+asn1_decode_ticket_ptr(asn1buf *buf, krb5_ticket **valptr)
+{
+    decode_ptr(krb5_ticket *, asn1_decode_ticket);
 }
 
 asn1_error_code asn1_decode_kdc_req(asn1buf *buf, krb5_kdc_req *val)
 {
     setup();
+    val->padata = NULL;
     { begin_structure();
         { krb5_kvno kvno;
             get_field(kvno,1,asn1_decode_kvno);
-            if (kvno != KVNO) return KRB5KDC_ERR_BAD_PVNO; }
+            if (kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
         get_field(val->msg_type,2,asn1_decode_msgtype);
         opt_field(val->padata,3,asn1_decode_sequence_of_pa_data,NULL);
         get_field(*val,4,asn1_decode_kdc_req_body);
         end_structure();
         val->magic = KV5M_KDC_REQ;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_pa_data(NULL, val->padata);
+    val->padata = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_kdc_req_body(asn1buf *buf, krb5_kdc_req *val)
 {
     setup();
+    val->client = NULL;
+    val->server = NULL;
+    val->ktype = NULL;
+    val->addresses = NULL;
+    val->authorization_data.ciphertext.data = NULL;
+    val->unenc_authdata = NULL;
+    val->second_ticket = NULL;
     {
         krb5_principal psave;
         begin_structure();
         get_field(val->kdc_options,0,asn1_decode_kdc_options);
-        if (tagnum == 1) { alloc_field(val->client,krb5_principal_data); }
+        if (tagnum == 1) { alloc_principal(val->client); }
         opt_field(val->client,1,asn1_decode_principal_name,NULL);
-        alloc_field(val->server,krb5_principal_data);
+        alloc_principal(val->server);
         get_field(val->server,2,asn1_decode_realm);
         if (val->client != NULL) {
             retval = asn1_krb5_realm_copy(val->client,val->server);
-            if (retval) return retval; }
+            if (retval) clean_return(retval); }
 
         /* If opt_field server is missing, memory reference to server is
            lost and results in memory leak */
@@ -672,72 +786,119 @@ asn1_error_code asn1_decode_kdc_req_body(asn1buf *buf, krb5_kdc_req *val)
         end_structure();
         val->magic = KV5M_KDC_REQ;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_principal(NULL, val->client);
+    krb5_free_principal(NULL, val->server);
+    free(val->ktype);
+    krb5_free_addresses(NULL, val->addresses);
+    krb5_free_data_contents(NULL, &val->authorization_data.ciphertext);
+    krb5_free_tickets(NULL, val->second_ticket);
+    val->client = NULL;
+    val->server = NULL;
+    val->ktype = NULL;
+    val->addresses = NULL;
+    val->unenc_authdata = NULL;
+    val->second_ticket = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_krb_safe_body(asn1buf *buf, krb5_safe *val)
 {
     setup();
+    val->user_data.data = NULL;
+    val->r_address = NULL;
+    val->s_address = NULL;
+    val->checksum = NULL;
     { begin_structure();
         get_lenfield(val->user_data.length,val->user_data.data,0,asn1_decode_charstring);
         opt_field(val->timestamp,1,asn1_decode_kerberos_time,0);
         opt_field(val->usec,2,asn1_decode_int32,0);
         opt_field(val->seq_number,3,asn1_decode_seqnum,0);
-        alloc_field(val->s_address,krb5_address);
-        get_field(*(val->s_address),4,asn1_decode_host_address);
+        get_field(val->s_address,4,asn1_decode_host_address_ptr);
         if (tagnum == 5) {
-            alloc_field(val->r_address,krb5_address);
-            get_field(*(val->r_address),5,asn1_decode_host_address);
-        } else val->r_address = NULL;
+            get_field(val->r_address,5,asn1_decode_host_address_ptr);
+        }
         end_structure();
         val->magic = KV5M_SAFE;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_data_contents(NULL, &val->user_data);
+    krb5_free_address(NULL, val->r_address);
+    krb5_free_address(NULL, val->s_address);
+    val->r_address = NULL;
+    val->s_address = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_host_address(asn1buf *buf, krb5_address *val)
 {
     setup();
+    val->contents = NULL;
     { begin_structure();
         get_field(val->addrtype,0,asn1_decode_addrtype);
         get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
         end_structure();
         val->magic = KV5M_ADDRESS;
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->contents);
+    val->contents = NULL;
+    return retval;
+}
+
+asn1_error_code
+asn1_decode_host_address_ptr(asn1buf *buf, krb5_address **valptr)
+{
+    decode_ptr(krb5_address *, asn1_decode_host_address);
 }
 
 asn1_error_code asn1_decode_kdc_rep(asn1buf *buf, krb5_kdc_rep *val)
 {
     setup();
+    val->padata = NULL;
+    val->client = NULL;
+    val->ticket = NULL;
+    val->enc_part.ciphertext.data = NULL;
+    val->enc_part2 = NULL;
     { begin_structure();
         { krb5_kvno pvno;
             get_field(pvno,0,asn1_decode_kvno);
-            if (pvno != KVNO) return KRB5KDC_ERR_BAD_PVNO; }
+            if (pvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
         get_field(val->msg_type,1,asn1_decode_msgtype);
         opt_field(val->padata,2,asn1_decode_sequence_of_pa_data,NULL);
-        alloc_field(val->client,krb5_principal_data);
+        alloc_principal(val->client);
         get_field(val->client,3,asn1_decode_realm);
         get_field(val->client,4,asn1_decode_principal_name);
-        alloc_field(val->ticket,krb5_ticket);
-        get_field(*(val->ticket),5,asn1_decode_ticket);
+        get_field(val->ticket,5,asn1_decode_ticket_ptr);
         get_field(val->enc_part,6,asn1_decode_encrypted_data);
         end_structure();
         val->magic = KV5M_KDC_REP;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_pa_data(NULL, val->padata);
+    krb5_free_principal(NULL, val->client);
+    krb5_free_ticket(NULL, val->ticket);
+    krb5_free_data_contents(NULL, &val->enc_part.ciphertext);
+    val->padata = NULL;
+    val->client = NULL;
+    val->ticket = NULL;
+    val->enc_part.ciphertext.data = NULL;
+    return retval;
 }
 
 
 /* arrays */
 #define get_element(element,decoder)\
-retval = decoder(&seqbuf,element);\
-if (retval) return retval
+retval = decoder(&seqbuf,&element);\
+if (retval) clean_return(retval)
 
 static void *
 array_expand (void *array, int n_elts, size_t elt_size)
 {
-    void *new_array;
     size_t new_size;
 
     if (n_elts <= 0)
@@ -749,74 +910,120 @@ array_expand (void *array, int n_elts, size_t elt_size)
         return NULL;
     if (new_size / elt_size != (unsigned int) n_elts)
         return NULL;
-    new_array = realloc(array, new_size);
-    return new_array;
+    return realloc(array, new_size);
 }
 
 #define array_append(array,size,element,type)\
-size++;\
-*(array) = array_expand(*(array), (size+1), sizeof(type*));\
-if (*(array) == NULL) return ENOMEM;\
-(*(array))[(size)-1] = elt
+  {\
+    void *new_array = array_expand(*(array), (size)+2, sizeof(type*));\
+    if (new_array == NULL) clean_return(ENOMEM);\
+    *(array) = new_array;\
+    (*(array))[(size)++] = elt;\
+  }
 
-#define decode_array_body(type,decoder)\
+/*
+ * Function body for array decoders.  freefn is expected to look like
+ * a krb5_free_ function, so we pass a null first argument.
+ */
+#define decode_array_body(type,decoder,freefn)\
   asn1_error_code retval;\
-  type *elt;\
+  type *elt = NULL, **array;\
+  int size = 0, i; \
 \
+  array = *val = NULL;\
   { sequence_of(buf);\
     while (asn1buf_remains(&seqbuf,seqofindef) > 0) {\
-      alloc_field(elt,type);\
       get_element(elt,decoder);\
-      array_append(val,size,elt,type);\
+      array_append(&array,size,elt,type);\
+      elt = NULL;\
     }\
-    if (*val == NULL)\
-        *val = (type **)malloc(sizeof(type*));\
-    (*val)[size] = NULL;\
+    if (array == NULL)\
+        array = malloc(sizeof(type*));\
+    array[size] = NULL;\
     end_sequence_of(buf);\
   }\
-  cleanup()
+  *val = array;\
+  return 0;\
+error_out:\
+  if (elt)\
+      freefn(NULL,elt);\
+  for (i = 0; i < size; i++)\
+      freefn(NULL,array[i]);\
+  free(array);\
+  return retval
 
+static void free_authdata_elt(void *dummy, krb5_authdata *val)
+{
+    free(val->contents);
+    free(val);
+}
 
 asn1_error_code asn1_decode_authorization_data(asn1buf *buf, krb5_authdata ***val)
 {
-    decode_array_body(krb5_authdata,asn1_decode_authdata_elt);
+    decode_array_body(krb5_authdata,asn1_decode_authdata_elt_ptr,
+                      free_authdata_elt);
 }
 
 asn1_error_code asn1_decode_authdata_elt(asn1buf *buf, krb5_authdata *val)
 {
     setup();
+    val->contents = NULL;
     { begin_structure();
         get_field(val->ad_type,0,asn1_decode_authdatatype);
         get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
         end_structure();
         val->magic = KV5M_AUTHDATA;
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->contents);
+    val->contents = NULL;
+    return retval;
+}
+
+asn1_error_code
+asn1_decode_authdata_elt_ptr(asn1buf *buf, krb5_authdata **valptr)
+{
+    decode_ptr(krb5_authdata *, asn1_decode_authdata_elt);
 }
 
 asn1_error_code asn1_decode_host_addresses(asn1buf *buf, krb5_address ***val)
 {
-    decode_array_body(krb5_address,asn1_decode_host_address);
+    decode_array_body(krb5_address,asn1_decode_host_address_ptr,
+                      krb5_free_address);
 }
 
 asn1_error_code asn1_decode_sequence_of_ticket(asn1buf *buf, krb5_ticket ***val)
 {
-    decode_array_body(krb5_ticket,asn1_decode_ticket);
+    decode_array_body(krb5_ticket,asn1_decode_ticket_ptr,krb5_free_ticket);
+}
+
+static void free_cred_info(void *dummy, krb5_cred_info *val)
+{
+    krb5_free_keyblock(NULL, val->session);
+    krb5_free_principal(NULL, val->client);
+    krb5_free_principal(NULL, val->server);
+    krb5_free_addresses(NULL, val->caddrs);
+    free(val);
 }
 
 asn1_error_code asn1_decode_sequence_of_krb_cred_info(asn1buf *buf, krb5_cred_info ***val)
 {
-    decode_array_body(krb5_cred_info,asn1_decode_krb_cred_info);
+    decode_array_body(krb5_cred_info,asn1_decode_krb_cred_info_ptr,
+                      free_cred_info);
 }
 
 asn1_error_code asn1_decode_krb_cred_info(asn1buf *buf, krb5_cred_info *val)
 {
     setup();
+    val->session = NULL;
+    val->client = NULL;
+    val->server = NULL;
+    val->caddrs = NULL;
     { begin_structure();
-        alloc_field(val->session,krb5_keyblock);
-        get_field(*(val->session),0,asn1_decode_encryption_key);
+        get_field(val->session,0,asn1_decode_encryption_key_ptr);
         if (tagnum == 1) {
-            alloc_field(val->client,krb5_principal_data);
+            alloc_principal(val->client);
             opt_field(val->client,1,asn1_decode_realm,NULL);
             opt_field(val->client,2,asn1_decode_principal_name,NULL); }
         opt_field(val->flags,3,asn1_decode_ticket_flags,0);
@@ -825,36 +1032,74 @@ asn1_error_code asn1_decode_krb_cred_info(asn1buf *buf, krb5_cred_info *val)
         opt_field(val->times.endtime,6,asn1_decode_kerberos_time,0);
         opt_field(val->times.renew_till,7,asn1_decode_kerberos_time,0);
         if (tagnum == 8) {
-            alloc_field(val->server,krb5_principal_data);
+            alloc_principal(val->server);
             opt_field(val->server,8,asn1_decode_realm,NULL);
             opt_field(val->server,9,asn1_decode_principal_name,NULL); }
         opt_field(val->caddrs,10,asn1_decode_host_addresses,NULL);
         end_structure();
         val->magic = KV5M_CRED_INFO;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_keyblock(NULL, val->session);
+    krb5_free_principal(NULL, val->client);
+    krb5_free_principal(NULL, val->server);
+    krb5_free_addresses(NULL, val->caddrs);
+    val->session = NULL;
+    val->client = NULL;
+    val->server = NULL;
+    val->caddrs = NULL;
+    return retval;
+}
+
+asn1_error_code
+asn1_decode_krb_cred_info_ptr(asn1buf *buf, krb5_cred_info **valptr)
+{
+    decode_ptr(krb5_cred_info *, asn1_decode_krb_cred_info);
+}
+
+static void free_pa_data(void *dummy, krb5_pa_data *val)
+{
+    free(val->contents);
+    free(val);
 }
 
 asn1_error_code asn1_decode_sequence_of_pa_data(asn1buf *buf, krb5_pa_data ***val)
 {
-    decode_array_body(krb5_pa_data,asn1_decode_pa_data);
+    decode_array_body(krb5_pa_data,asn1_decode_pa_data_ptr,free_pa_data);
 }
 
 asn1_error_code asn1_decode_pa_data(asn1buf *buf, krb5_pa_data *val)
 {
     setup();
+    val->contents = NULL;
     { begin_structure();
         get_field(val->pa_type,1,asn1_decode_int32);
         get_lenfield(val->length,val->contents,2,asn1_decode_octetstring);
         end_structure();
         val->magic = KV5M_PA_DATA;
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->contents);
+    val->contents = NULL;
+    return retval;
+}
+
+asn1_error_code asn1_decode_pa_data_ptr(asn1buf *buf, krb5_pa_data **valptr)
+{
+    decode_ptr(krb5_pa_data *, asn1_decode_pa_data);
+}
+
+static void free_last_req_entry(void *dummy, krb5_last_req_entry *val)
+{
+    free(val);
 }
 
 asn1_error_code asn1_decode_last_req(asn1buf *buf, krb5_last_req_entry ***val)
 {
-    decode_array_body(krb5_last_req_entry,asn1_decode_last_req_entry);
+    decode_array_body(krb5_last_req_entry,asn1_decode_last_req_entry_ptr,
+                      free_last_req_entry);
 }
 
 asn1_error_code asn1_decode_last_req_entry(asn1buf *buf, krb5_last_req_entry *val)
@@ -871,147 +1116,222 @@ asn1_error_code asn1_decode_last_req_entry(asn1buf *buf, krb5_last_req_entry *va
         if ((val->lr_type & 0xffffff80U) == 0x80) val->lr_type |= 0xffffff00U;
 #endif
     }
-    cleanup();
+    return 0;
+error_out:
+    return retval;
+}
+
+asn1_error_code
+asn1_decode_last_req_entry_ptr(asn1buf *buf, krb5_last_req_entry **valptr)
+{
+    decode_ptr(krb5_last_req_entry *, asn1_decode_last_req_entry);
 }
 
 asn1_error_code asn1_decode_sequence_of_enctype(asn1buf *buf, int *num, krb5_enctype **val)
 {
+    int size = 0;
+    krb5_enctype *array = NULL, *new_array;
+
     asn1_error_code retval;
     { sequence_of(buf);
         while (asn1buf_remains(&seqbuf,seqofindef) > 0) {
             size++;
-            if (*val == NULL)
-                *val = (krb5_enctype*)malloc(size*sizeof(krb5_enctype));
-            else
-                *val = (krb5_enctype*)realloc(*val,size*sizeof(krb5_enctype));
-            if (*val == NULL) return ENOMEM;
-            retval = asn1_decode_enctype(&seqbuf,&((*val)[size-1]));
-            if (retval) return retval;
+            new_array = realloc(array,size*sizeof(krb5_enctype));
+            if (new_array == NULL) clean_return(ENOMEM);
+            array = new_array;
+            retval = asn1_decode_enctype(&seqbuf,&array[size-1]);
+            if (retval) clean_return(retval);
         }
-        *num = size;
         end_sequence_of(buf);
     }
-    cleanup();
+    *num = size;
+    *val = array;
+    return 0;
+error_out:
+    free(array);
+    return retval;
 }
 
 asn1_error_code asn1_decode_sequence_of_checksum(asn1buf *buf, krb5_checksum ***val)
 {
-    decode_array_body(krb5_checksum, asn1_decode_checksum);
+    decode_array_body(krb5_checksum, asn1_decode_checksum_ptr,
+                      krb5_free_checksum);
+}
+
+static void free_etype_info_entry(void *dummy, krb5_etype_info_entry *val)
+{
+    krb5_free_data_contents(NULL, &val->s2kparams);
+    free(val->salt);
+    free(val);
 }
 
 static asn1_error_code asn1_decode_etype_info2_entry(asn1buf *buf, krb5_etype_info_entry *val )
 {
+    char *salt = NULL;
+    krb5_octet *params = NULL;
     setup();
+    val->salt = NULL;
+    val->s2kparams.data = NULL;
     { begin_structure();
         get_field(val->etype,0,asn1_decode_enctype);
         if (tagnum == 1) {
-            char *salt;
             get_lenfield(val->length,salt,1,asn1_decode_generalstring);
             val->salt = (krb5_octet *) salt;
-        } else {
+            salt = NULL;
+        } else
             val->length = KRB5_ETYPE_NO_SALT;
-            val->salt = 0;
-        }
         if ( tagnum ==2) {
-            krb5_octet *params ;
             get_lenfield( val->s2kparams.length, params,
                           2, asn1_decode_octetstring);
             val->s2kparams.data = ( char *) params;
-        } else {
-            val->s2kparams.data = NULL;
+            params = NULL;
+        } else
             val->s2kparams.length = 0;
-        }
         end_structure();
         val->magic = KV5M_ETYPE_INFO_ENTRY;
     }
-    cleanup();
+    return 0;
+error_out:
+    free(salt);
+    free(params);
+    krb5_free_data_contents(NULL, &val->s2kparams);
+    free(val->salt);
+    val->salt = NULL;
+    return retval;
+}
+
+static asn1_error_code
+asn1_decode_etype_info2_entry_ptr(asn1buf *buf, krb5_etype_info_entry **valptr)
+{
+    decode_ptr(krb5_etype_info_entry *, asn1_decode_etype_info2_entry);
 }
 
 static asn1_error_code asn1_decode_etype_info2_entry_1_3(asn1buf *buf, krb5_etype_info_entry *val )
 {
     setup();
+    val->salt = NULL;
+    val->s2kparams.data = NULL;
     { begin_structure();
         get_field(val->etype,0,asn1_decode_enctype);
         if (tagnum == 1) {
             get_lenfield(val->length,val->salt,1,asn1_decode_octetstring);
-        } else {
+        } else
             val->length = KRB5_ETYPE_NO_SALT;
-            val->salt = 0;
-        }
         if ( tagnum ==2) {
             krb5_octet *params ;
             get_lenfield( val->s2kparams.length, params,
                           2, asn1_decode_octetstring);
             val->s2kparams.data = ( char *) params;
-        } else {
-            val->s2kparams.data = NULL;
+        } else
             val->s2kparams.length = 0;
-        }
         end_structure();
         val->magic = KV5M_ETYPE_INFO_ENTRY;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_data_contents(NULL, &val->s2kparams);
+    free(val->salt);
+    val->salt = NULL;
+    return retval;
 }
 
+static asn1_error_code
+asn1_decode_etype_info2_entry_1_3_ptr(asn1buf *buf,
+                                      krb5_etype_info_entry **valptr)
+{
+    decode_ptr(krb5_etype_info_entry *, asn1_decode_etype_info2_entry_1_3);
+}
 
 static asn1_error_code asn1_decode_etype_info_entry(asn1buf *buf, krb5_etype_info_entry *val )
 {
     setup();
+    val->salt = NULL;
+    val->s2kparams.data = NULL;
     { begin_structure();
         get_field(val->etype,0,asn1_decode_enctype);
         if (tagnum == 1) {
             get_lenfield(val->length,val->salt,1,asn1_decode_octetstring);
-        } else {
+        } else
             val->length = KRB5_ETYPE_NO_SALT;
-            val->salt = 0;
-        }
-        val->s2kparams.data = NULL;
         val->s2kparams.length = 0;
 
         end_structure();
         val->magic = KV5M_ETYPE_INFO_ENTRY;
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->salt);
+    val->salt = NULL;
+    return retval;
+}
+
+static asn1_error_code
+asn1_decode_etype_info_entry_ptr(asn1buf *buf, krb5_etype_info_entry **valptr)
+{
+    decode_ptr(krb5_etype_info_entry *, asn1_decode_etype_info_entry);
 }
 
 asn1_error_code asn1_decode_etype_info(asn1buf *buf, krb5_etype_info_entry ***val )
 {
-    decode_array_body(krb5_etype_info_entry,asn1_decode_etype_info_entry);
+    decode_array_body(krb5_etype_info_entry,asn1_decode_etype_info_entry_ptr,
+                      free_etype_info_entry);
+}
+
+static asn1_error_code decode_etype_info2_13(asn1buf *buf, krb5_etype_info_entry ***val)
+{
+    decode_array_body(krb5_etype_info_entry,
+                      asn1_decode_etype_info2_entry_1_3_ptr,
+                      free_etype_info_entry);
 }
 
 asn1_error_code asn1_decode_etype_info2(asn1buf *buf, krb5_etype_info_entry ***val ,
                                         krb5_boolean v1_3_behavior)
 {
-    if (v1_3_behavior) {
+    if (v1_3_behavior)
+        return decode_etype_info2_13(buf, val);
+    else {
         decode_array_body(krb5_etype_info_entry,
-                          asn1_decode_etype_info2_entry_1_3);
-    } else {
-        decode_array_body(krb5_etype_info_entry,
-                          asn1_decode_etype_info2_entry);
+                          asn1_decode_etype_info2_entry_ptr,
+                          free_etype_info_entry);
     }
 }
 
 asn1_error_code asn1_decode_passwdsequence(asn1buf *buf, passwd_phrase_element *val)
 {
     setup();
+    val->passwd = NULL;
+    val->phrase = NULL;
     { begin_structure();
-        alloc_field(val->passwd,krb5_data);
+        alloc_data(val->passwd);
         get_lenfield(val->passwd->length,val->passwd->data,
                      0,asn1_decode_charstring);
         val->passwd->magic = KV5M_DATA;
-        alloc_field(val->phrase,krb5_data);
+        alloc_data(val->phrase);
         get_lenfield(val->phrase->length,val->phrase->data,
                      1,asn1_decode_charstring);
         val->phrase->magic = KV5M_DATA;
         end_structure();
         val->magic = KV5M_PASSWD_PHRASE_ELEMENT;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_data(NULL, val->passwd);
+    krb5_free_data(NULL, val->phrase);
+    val->passwd = NULL;
+    val->phrase = NULL;
+    return 0;
+}
+
+asn1_error_code
+asn1_decode_passwdsequence_ptr(asn1buf *buf, passwd_phrase_element **valptr)
+{
+    decode_ptr(passwd_phrase_element *, asn1_decode_passwdsequence);
 }
 
 asn1_error_code asn1_decode_sequence_of_passwdsequence(asn1buf *buf, passwd_phrase_element ***val)
 {
-    decode_array_body(passwd_phrase_element,asn1_decode_passwdsequence);
+    decode_array_body(passwd_phrase_element,asn1_decode_passwdsequence_ptr,
+                      krb5_free_passwd_phrase_element);
 }
 
 asn1_error_code asn1_decode_sam_flags(asn1buf *buf, krb5_flags *val)
@@ -1026,6 +1346,12 @@ else var.length = 0
 asn1_error_code asn1_decode_sam_challenge(asn1buf *buf, krb5_sam_challenge *val)
 {
     setup();
+    val->sam_type_name.data = NULL;
+    val->sam_track_id.data = NULL;
+    val->sam_challenge_label.data = NULL;
+    val->sam_response_prompt.data = NULL;
+    val->sam_pk_for_sad.data = NULL;
+    val->sam_cksum.contents = NULL;
     { begin_structure();
         get_field(val->sam_type,0,asn1_decode_int32);
         get_field(val->sam_flags,1,asn1_decode_sam_flags);
@@ -1040,37 +1366,58 @@ asn1_error_code asn1_decode_sam_challenge(asn1buf *buf, krb5_sam_challenge *val)
         end_structure();
         val->magic = KV5M_SAM_CHALLENGE;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_sam_challenge_contents(NULL, val);
+    return retval;
 }
 asn1_error_code asn1_decode_sam_challenge_2(asn1buf *buf, krb5_sam_challenge_2 *val)
 {
+    krb5_checksum **cksump;
     setup();
+    val->sam_challenge_2_body.data = NULL;
+    val->sam_cksum = NULL;
     { char *save, *end;
         size_t alloclen;
         begin_structure();
-        if (tagnum != 0) return ASN1_MISSING_FIELD;
+        if (tagnum != 0) clean_return(ASN1_MISSING_FIELD);
         if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
-            return ASN1_BAD_ID;
+            clean_return(ASN1_BAD_ID);
         save = subbuf.next;
         { sequence_of_no_tagvars(&subbuf);
-            unused_var(size);
             end_sequence_of_no_tagvars(&subbuf);
         }
         end = subbuf.next;
         alloclen = end - save;
-        if ((val->sam_challenge_2_body.data = (char *) malloc(alloclen)) == NULL)
-            return ENOMEM;
+        val->sam_challenge_2_body.data = malloc(alloclen);
+        if (!val->sam_challenge_2_body.data)
+            clean_return(ENOMEM);
         val->sam_challenge_2_body.length = alloclen;
         memcpy(val->sam_challenge_2_body.data, save, alloclen);
         next_tag();
         get_field(val->sam_cksum, 1, asn1_decode_sequence_of_checksum);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_data_contents(NULL, &val->sam_challenge_2_body);
+    if (val->sam_cksum) {
+        for (cksump = val->sam_cksum; *cksump; cksump++)
+            krb5_free_checksum(NULL, *cksump);
+        free(val->sam_cksum);
+        val->sam_cksum = NULL;
+    }
+    return retval;
 }
 asn1_error_code asn1_decode_sam_challenge_2_body(asn1buf *buf, krb5_sam_challenge_2_body *val)
 {
     setup();
+    val->sam_type_name.data = NULL;
+    val->sam_track_id.data = NULL;
+    val->sam_challenge_label.data = NULL;
+    val->sam_challenge.data = NULL;
+    val->sam_response_prompt.data = NULL;
+    val->sam_pk_for_sad.data = NULL;
     { begin_structure();
         get_field(val->sam_type,0,asn1_decode_int32);
         get_field(val->sam_flags,1,asn1_decode_sam_flags);
@@ -1085,23 +1432,30 @@ asn1_error_code asn1_decode_sam_challenge_2_body(asn1buf *buf, krb5_sam_challeng
         end_structure();
         val->magic = KV5M_SAM_CHALLENGE;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_sam_challenge_2_body_contents(NULL, val);
+    return retval;
 }
 asn1_error_code asn1_decode_enc_sam_key(asn1buf *buf, krb5_sam_key *val)
 {
     setup();
+    val->sam_key.contents = NULL;
     { begin_structure();
-        /* alloc_field(val->sam_key,krb5_keyblock); */
         get_field(val->sam_key,0,asn1_decode_encryption_key);
         end_structure();
         val->magic = KV5M_SAM_KEY;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_keyblock_contents(NULL, &val->sam_key);
+    return retval;
 }
 
 asn1_error_code asn1_decode_enc_sam_response_enc(asn1buf *buf, krb5_enc_sam_response_enc *val)
 {
     setup();
+    val->sam_sad.data = NULL;
     { begin_structure();
         opt_field(val->sam_nonce,0,asn1_decode_int32,0);
         opt_field(val->sam_timestamp,1,asn1_decode_kerberos_time,0);
@@ -1110,19 +1464,26 @@ asn1_error_code asn1_decode_enc_sam_response_enc(asn1buf *buf, krb5_enc_sam_resp
         end_structure();
         val->magic = KV5M_ENC_SAM_RESPONSE_ENC;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_enc_sam_response_enc_contents(NULL, val);
+    return retval;
 }
 
 asn1_error_code asn1_decode_enc_sam_response_enc_2(asn1buf *buf, krb5_enc_sam_response_enc_2 *val)
 {
     setup();
+    val->sam_sad.data = NULL;
     { begin_structure();
         get_field(val->sam_nonce,0,asn1_decode_int32);
         opt_string(val->sam_sad,1,asn1_decode_charstring);
         end_structure();
         val->magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_enc_sam_response_enc_2_contents(NULL, val);
+    return retval;
 }
 
 #define opt_encfield(fld,tag,fn) \
@@ -1139,6 +1500,9 @@ asn1_error_code asn1_decode_enc_sam_response_enc_2(asn1buf *buf, krb5_enc_sam_re
 asn1_error_code asn1_decode_sam_response(asn1buf *buf, krb5_sam_response *val)
 {
     setup();
+    val->sam_track_id.data = NULL;
+    val->sam_enc_key.ciphertext.data = NULL;
+    val->sam_enc_nonce_or_ts.ciphertext.data = NULL;
     { begin_structure();
         get_field(val->sam_type,0,asn1_decode_int32);
         get_field(val->sam_flags,1,asn1_decode_sam_flags);
@@ -1150,12 +1514,17 @@ asn1_error_code asn1_decode_sam_response(asn1buf *buf, krb5_sam_response *val)
         end_structure();
         val->magic = KV5M_SAM_RESPONSE;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_sam_response_contents(NULL, val);
+    return retval;
 }
 
 asn1_error_code asn1_decode_sam_response_2(asn1buf *buf, krb5_sam_response_2 *val)
 {
     setup();
+    val->sam_track_id.data = NULL;
+    val->sam_enc_nonce_or_sad.ciphertext.data = NULL;
     { begin_structure();
         get_field(val->sam_type,0,asn1_decode_int32);
         get_field(val->sam_flags,1,asn1_decode_sam_flags);
@@ -1165,57 +1534,82 @@ asn1_error_code asn1_decode_sam_response_2(asn1buf *buf, krb5_sam_response_2 *va
         end_structure();
         val->magic = KV5M_SAM_RESPONSE;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_sam_response_2_contents(NULL, val);
+    return retval;
 }
 
 
 asn1_error_code asn1_decode_predicted_sam_response(asn1buf *buf, krb5_predicted_sam_response *val)
 {
     setup();
+    val->sam_key.contents = NULL;
+    val->client = NULL;
+    val->msd.data = NULL;
     { begin_structure();
         get_field(val->sam_key,0,asn1_decode_encryption_key);
         get_field(val->sam_flags,1,asn1_decode_sam_flags);
         get_field(val->stime,2,asn1_decode_kerberos_time);
         get_field(val->susec,3,asn1_decode_int32);
-        alloc_field(val->client,krb5_principal_data);
+        alloc_principal(val->client);
         get_field(val->client,4,asn1_decode_realm);
         get_field(val->client,5,asn1_decode_principal_name);
         opt_string(val->msd,6,asn1_decode_charstring); /* should be octet */
         end_structure();
         val->magic = KV5M_PREDICTED_SAM_RESPONSE;
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_predicted_sam_response_contents(NULL, val);
+    return retval;
 }
 
 asn1_error_code asn1_decode_setpw_req(asn1buf *buf, krb5_data *newpasswd, krb5_principal *principal)
 {
+    krb5_principal princ = NULL;
     setup();
     *principal = NULL;
 
+    newpasswd->data = NULL;
     { begin_structure();
         get_lenfield(newpasswd->length, newpasswd->data, 0, asn1_decode_charstring);
         if (tagnum == 1) {
-            alloc_field(*principal, krb5_principal_data);
-            opt_field(*principal, 1, asn1_decode_principal_name, 0);
-            opt_field(*principal, 2, asn1_decode_realm, 0);
+            alloc_principal(princ);
+            opt_field(princ, 1, asn1_decode_principal_name, 0);
+            opt_field(princ, 2, asn1_decode_realm, 0);
         }
         end_structure();
     }
-    cleanup();
+    *principal = princ;
+    return 0;
+error_out:
+    krb5_free_data_contents(NULL, newpasswd);
+    krb5_free_principal(NULL, princ);
+    return retval;
 }
 
 asn1_error_code asn1_decode_pa_for_user(asn1buf *buf, krb5_pa_for_user *val)
 {
     setup();
+    val->user = NULL;
+    val->cksum.contents = NULL;
+    val->auth_package.data = NULL;
     { begin_structure();
-       alloc_field(val->user, krb5_principal_data);
+        alloc_principal(val->user);
         get_field(val->user,0,asn1_decode_principal_name);
         get_field(val->user,1,asn1_decode_realm);
         get_field(val->cksum,2,asn1_decode_checksum);
         get_lenfield(val->auth_package.length,val->auth_package.data,3,asn1_decode_generalstring);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_principal(NULL, val->user);
+    krb5_free_checksum_contents(NULL, &val->cksum);
+    krb5_free_data_contents(NULL, &val->auth_package);
+    val->user = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_pa_pac_req(asn1buf *buf, krb5_pa_pac_req *val)
@@ -1225,7 +1619,9 @@ asn1_error_code asn1_decode_pa_pac_req(asn1buf *buf, krb5_pa_pac_req *val)
         get_field(val->include_pac,0,asn1_decode_boolean);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    return retval;
 }
 
 #ifndef DISABLE_PKINIT
@@ -1234,6 +1630,9 @@ asn1_error_code asn1_decode_pa_pac_req(asn1buf *buf, krb5_pa_pac_req *val)
 asn1_error_code asn1_decode_external_principal_identifier(asn1buf *buf, krb5_external_principal_identifier *val)
 {
     setup();
+    val->subjectName.data = NULL;
+    val->issuerAndSerialNumber.data = NULL;
+    val->subjectKeyIdentifier.data = NULL;
     {
         begin_structure();
         opt_implicit_octet_string(val->subjectName.length, val->subjectName.data, 0);
@@ -1241,17 +1640,49 @@ asn1_error_code asn1_decode_external_principal_identifier(asn1buf *buf, krb5_ext
         opt_implicit_octet_string(val->subjectKeyIdentifier.length, val->subjectKeyIdentifier.data, 2);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->subjectName.data);
+    free(val->issuerAndSerialNumber.data);
+    free(val->subjectKeyIdentifier.data);
+    val->subjectName.data = NULL;
+    val->issuerAndSerialNumber.data = NULL;
+    val->subjectKeyIdentifier.data = NULL;
+    return retval;
+}
+
+asn1_error_code
+asn1_decode_external_principal_identifier_ptr
+       (asn1buf *buf,
+         krb5_external_principal_identifier **valptr)
+{
+    decode_ptr(krb5_external_principal_identifier *,
+               asn1_decode_external_principal_identifier);
+}
+
+static void
+free_external_principal_identifier(void *dummy,
+                                   krb5_external_principal_identifier *val)
+{
+    free(val->subjectName.data);
+    free(val->issuerAndSerialNumber.data);
+    free(val->subjectKeyIdentifier.data);
+    free(val);
 }
 
 asn1_error_code asn1_decode_sequence_of_external_principal_identifier(asn1buf *buf, krb5_external_principal_identifier ***val)
 {
-    decode_array_body(krb5_external_principal_identifier,asn1_decode_external_principal_identifier);
+    decode_array_body(krb5_external_principal_identifier,
+                      asn1_decode_external_principal_identifier_ptr,
+                      free_external_principal_identifier);
 }
 
 asn1_error_code asn1_decode_pa_pk_as_req(asn1buf *buf, krb5_pa_pk_as_req *val)
 {
     setup();
+    val->signedAuthPack.data = NULL;
+    val->trustedCertifiers = NULL;
+    val->kdcPkId.data = NULL;
     {
         begin_structure();
         get_implicit_octet_string(val->signedAuthPack.length, val->signedAuthPack.data, 0);
@@ -1259,13 +1690,22 @@ asn1_error_code asn1_decode_pa_pk_as_req(asn1buf *buf, krb5_pa_pk_as_req *val)
         opt_implicit_octet_string(val->kdcPkId.length, val->kdcPkId.data, 2);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->signedAuthPack.data);
+    free(val->trustedCertifiers);
+    free(val->kdcPkId.data);
+    val->signedAuthPack.data = NULL;
+    val->trustedCertifiers = NULL;
+    val->kdcPkId.data = NULL;
+    return retval;
 }
 
 #if 0   /* XXX   This needs to be tested!!! XXX */
 asn1_error_code asn1_decode_trusted_ca(asn1buf *buf, krb5_trusted_ca *val)
 {
     setup();
+    val->choice = choice_trusted_cas_UNKNOWN;
     {
         char *start, *end;
         size_t alloclen;
@@ -1275,6 +1715,7 @@ asn1_error_code asn1_decode_trusted_ca(asn1buf *buf, krb5_trusted_ca *val)
             val->choice = choice_trusted_cas_principalName;
         } else if (t.tagnum == choice_trusted_cas_caName) {
             val->choice = choice_trusted_cas_caName;
+            val->u.caName.data = NULL;
             start = subbuf.next;
             {
                 sequence_of_no_tagvars(&subbuf);
@@ -1285,12 +1726,13 @@ asn1_error_code asn1_decode_trusted_ca(asn1buf *buf, krb5_trusted_ca *val)
             alloclen = end - start;
             val->u.caName.data = malloc(alloclen);
             if (val->u.caName.data == NULL)
-                return ENOMEM;
+                clean_return(ENOMEM);
             memcpy(val->u.caName.data, start, alloclen);
             val->u.caName.length = alloclen;
             next_tag();
         } else if (t.tagnum == choice_trusted_cas_issuerAndSerial) {
             val->choice = choice_trusted_cas_issuerAndSerial;
+            val->u.issuerAndSerial.data = NULL;
             start = subbuf.next;
             {
                 sequence_of_no_tagvars(&subbuf);
@@ -1301,45 +1743,84 @@ asn1_error_code asn1_decode_trusted_ca(asn1buf *buf, krb5_trusted_ca *val)
             alloclen = end - start;
             val->u.issuerAndSerial.data = malloc(alloclen);
             if (val->u.issuerAndSerial.data == NULL)
-                return ENOMEM;
+                clean_return(ENOMEM);
             memcpy(val->u.issuerAndSerial.data, start, alloclen);
             val->u.issuerAndSerial.length = alloclen;
             next_tag();
-        } else return ASN1_BAD_ID;
+        } else clean_return(ASN1_BAD_ID);
         end_explicit_choice();
     }
-    cleanup();
+    return 0;
+error_out:
+    if (val->choice == choice_trusted_cas_caName)
+        free(val->u.caName.data);
+    else if (val->choice == choice_trusted_cas_issuerAndSerial)
+        free(val->u.issuerAndSerial.data);
+    val->choice = choice_trusted_cas_UNKNOWN;
+    return retval;
 }
 #else
 asn1_error_code asn1_decode_trusted_ca(asn1buf *buf, krb5_trusted_ca *val)
 {
     setup();
+    val->choice = choice_trusted_cas_UNKNOWN;
     { begin_choice();
         if (tagnum == choice_trusted_cas_principalName) {
             val->choice = choice_trusted_cas_principalName;
+            val->u.principalName = NULL;
             asn1_decode_krb5_principal_name(&subbuf, &(val->u.principalName));
         } else if (tagnum == choice_trusted_cas_caName) {
             val->choice = choice_trusted_cas_caName;
+            val->u.caName.data = NULL;
             get_implicit_octet_string(val->u.caName.length, val->u.caName.data, choice_trusted_cas_caName);
         } else if (tagnum == choice_trusted_cas_issuerAndSerial) {
             val->choice = choice_trusted_cas_issuerAndSerial;
+            val->u.issuerAndSerial.data = NULL;
             get_implicit_octet_string(val->u.issuerAndSerial.length, val->u.issuerAndSerial.data,
                                       choice_trusted_cas_issuerAndSerial);
-        } else return ASN1_BAD_ID;
+        } else clean_return(ASN1_BAD_ID);
         end_choice();
     }
-    cleanup();
+    return 0;
+error_out:
+    if (val->choice == choice_trusted_cas_caName)
+        free(val->u.caName.data);
+    else if (val->choice == choice_trusted_cas_issuerAndSerial)
+        free(val->u.issuerAndSerial.data);
+    val->choice = choice_trusted_cas_UNKNOWN;
+    return retval;
 }
 #endif
 
+asn1_error_code
+asn1_decode_trusted_ca_ptr(asn1buf *buf, krb5_trusted_ca **valptr)
+{
+    decode_ptr(krb5_trusted_ca *, asn1_decode_trusted_ca);
+}
+
+static void free_trusted_ca(void *dummy, krb5_trusted_ca *val)
+{
+    if (val->choice == choice_trusted_cas_caName)
+        free(val->u.caName.data);
+    else if (val->choice == choice_trusted_cas_issuerAndSerial)
+        free(val->u.issuerAndSerial.data);
+    free(val);
+}
+
 asn1_error_code asn1_decode_sequence_of_trusted_ca(asn1buf *buf, krb5_trusted_ca ***val)
 {
-    decode_array_body(krb5_trusted_ca, asn1_decode_trusted_ca);
+    decode_array_body(krb5_trusted_ca, asn1_decode_trusted_ca_ptr,
+                      free_trusted_ca);
 }
 
 asn1_error_code asn1_decode_pa_pk_as_req_draft9(asn1buf *buf, krb5_pa_pk_as_req_draft9 *val)
 {
+    int i;
     setup();
+    val->signedAuthPack.data = NULL;
+    val->kdcCert.data = NULL;
+    val->encryptionCert.data = NULL;
+    val->trustedCertifiers = NULL;
     { begin_structure();
         get_implicit_octet_string(val->signedAuthPack.length, val->signedAuthPack.data, 0);
         opt_field(val->trustedCertifiers, 1, asn1_decode_sequence_of_trusted_ca, NULL);
@@ -1347,24 +1828,47 @@ asn1_error_code asn1_decode_pa_pk_as_req_draft9(asn1buf *buf, krb5_pa_pk_as_req_
         opt_lenfield(val->encryptionCert.length, val->encryptionCert.data, 2, asn1_decode_octetstring);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->signedAuthPack.data);
+    free(val->kdcCert.data);
+    free(val->encryptionCert.data);
+    if (val->trustedCertifiers) {
+        for (i = 0; val->trustedCertifiers[i]; i++)
+            free_trusted_ca(NULL, val->trustedCertifiers[i]);
+        free(val->trustedCertifiers);
+    }
+    val->signedAuthPack.data = NULL;
+    val->kdcCert.data = NULL;
+    val->encryptionCert.data = NULL;
+    val->trustedCertifiers = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_dh_rep_info(asn1buf *buf, krb5_dh_rep_info *val)
 {
     setup();
+    val->dhSignedData.data = NULL;
+    val->serverDHNonce.data = NULL;
     { begin_structure();
         get_implicit_octet_string(val->dhSignedData.length, val->dhSignedData.data, 0);
 
         opt_lenfield(val->serverDHNonce.length, val->serverDHNonce.data, 1, asn1_decode_octetstring);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->dhSignedData.data);
+    free(val->serverDHNonce.data);
+    val->dhSignedData.data = NULL;
+    val->serverDHNonce.data = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_pk_authenticator(asn1buf *buf, krb5_pk_authenticator *val)
 {
     setup();
+    val->paChecksum.contents = NULL;
     { begin_structure();
         get_field(val->cusec, 0, asn1_decode_int32);
         get_field(val->ctime, 1, asn1_decode_kerberos_time);
@@ -1372,14 +1876,19 @@ asn1_error_code asn1_decode_pk_authenticator(asn1buf *buf, krb5_pk_authenticator
         opt_lenfield(val->paChecksum.length, val->paChecksum.contents, 3, asn1_decode_octetstring);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_checksum_contents(NULL, &val->paChecksum);
+    return retval;
 }
 
 asn1_error_code asn1_decode_pk_authenticator_draft9(asn1buf *buf, krb5_pk_authenticator_draft9 *val)
 {
     setup();
+    val->kdcName = NULL;
+    val->kdcRealm.data = NULL;
     { begin_structure();
-        alloc_field(val->kdcName,krb5_principal_data);
+        alloc_principal(val->kdcName);
         get_field(val->kdcName, 0, asn1_decode_principal_name);
         get_field(val->kdcName, 1, asn1_decode_realm);
         get_field(val->cusec, 2, asn1_decode_int32);
@@ -1387,19 +1896,24 @@ asn1_error_code asn1_decode_pk_authenticator_draft9(asn1buf *buf, krb5_pk_authen
         get_field(val->nonce, 4, asn1_decode_int32);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_principal(NULL, val->kdcName);
+    return retval;
 }
 
 asn1_error_code asn1_decode_algorithm_identifier(asn1buf *buf,  krb5_algorithm_identifier *val) {
 
     setup();
+    val->algorithm.data = NULL;
+    val->parameters.data = NULL;
     { begin_structure_no_tag();
         /*
          * Forbid indefinite encoding because we don't read enough tag
          * information from the trailing octets ("ANY DEFINED BY") to
          * synchronize EOC tags, etc.
          */
-        if (seqindef) return ASN1_BAD_FORMAT;
+        if (seqindef) clean_return(ASN1_BAD_FORMAT);
         /*
          * Set up tag variables because we don't actually call anything
          * that fetches tag info for us; it's all buried in the decoder
@@ -1412,7 +1926,7 @@ asn1_error_code asn1_decode_algorithm_identifier(asn1buf *buf,  krb5_algorithm_i
         indef = 0;
         retval = asn1_decode_oid(&subbuf, &val->algorithm.length,
                                  &val->algorithm.data);
-        if (retval) return retval;
+        if (retval) clean_return(retval);
         val->parameters.length = 0;
         val->parameters.data = NULL;
 
@@ -1421,43 +1935,59 @@ asn1_error_code asn1_decode_algorithm_identifier(asn1buf *buf,  krb5_algorithm_i
             unsigned int size = length - (subbuf.next - subbuf.base);
             retval = asn1buf_remove_octetstring(&subbuf, size,
                                                 &val->parameters.data);
-            if (retval) return retval;
+            if (retval) clean_return(retval);
             val->parameters.length = size;
         }
 
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->algorithm.data);
+    free(val->parameters.data);
+    val->algorithm.data = NULL;
+    val->parameters.data = NULL;
+    return retval;
+}
+
+asn1_error_code
+asn1_decode_algorithm_identifier_ptr(asn1buf *buf,
+                                     krb5_algorithm_identifier **valptr)
+{
+    decode_ptr(krb5_algorithm_identifier *, asn1_decode_algorithm_identifier);
 }
 
 asn1_error_code asn1_decode_subject_pk_info(asn1buf *buf, krb5_subject_pk_info *val)
 {
     asn1_octet unused;
     setup();
+    val->algorithm.algorithm.data = NULL;
+    val->algorithm.parameters.data = NULL;
+    val->subjectPublicKey.data = NULL;
     { begin_structure_no_tag();
 
         retval = asn1_decode_algorithm_identifier(&subbuf, &val->algorithm);
-        if (retval) return retval;
+        if (retval) clean_return(retval);
 
         /* SubjectPublicKey encoded as a BIT STRING */
         next_tag();
         if (asn1class != UNIVERSAL || construction != PRIMITIVE ||
             tagnum != ASN1_BITSTRING)
-            return ASN1_BAD_ID;
+            clean_return(ASN1_BAD_ID);
 
         retval = asn1buf_remove_octet(&subbuf, &unused);
-        if (retval) return retval;
+        if (retval) clean_return(retval);
 
         /* Number of unused bits must be between 0 and 7. */
         /* What to do if unused is not zero? */
-        if (unused > 7) return ASN1_BAD_FORMAT;
+        if (unused > 7) clean_return(ASN1_BAD_FORMAT);
         taglen--;
 
         val->subjectPublicKey.length = 0;
         val->subjectPublicKey.data = NULL;
         retval = asn1buf_remove_octetstring(&subbuf, taglen,
                                             &val->subjectPublicKey.data);
-        if (retval) return retval;
+        if (retval) clean_return(retval);
         val->subjectPublicKey.length = taglen;
         /*
          * We didn't call any macro that does next_tag(); do so now to
@@ -1466,77 +1996,137 @@ asn1_error_code asn1_decode_subject_pk_info(asn1buf *buf, krb5_subject_pk_info *
         next_tag();
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->algorithm.algorithm.data);
+    free(val->algorithm.parameters.data);
+    free(val->subjectPublicKey.data);
+    val->algorithm.algorithm.data = NULL;
+    val->algorithm.parameters.data = NULL;
+    val->subjectPublicKey.data = NULL;
+    return 0;
+}
+
+static void
+free_algorithm_identifier(void *dummy, krb5_algorithm_identifier *val)
+{
+    free(val->algorithm.data);
+    free(val->parameters.data);
+    free(val);
 }
 
 asn1_error_code asn1_decode_sequence_of_algorithm_identifier(asn1buf *buf, krb5_algorithm_identifier ***val)
 {
-    decode_array_body(krb5_algorithm_identifier, asn1_decode_algorithm_identifier);
+    decode_array_body(krb5_algorithm_identifier,
+                      asn1_decode_algorithm_identifier_ptr,
+                      free_algorithm_identifier);
 }
 
 asn1_error_code asn1_decode_kdc_dh_key_info (asn1buf *buf, krb5_kdc_dh_key_info *val)
 {
     setup();
+    val->subjectPublicKey.data = NULL;
     { begin_structure();
         retval = asn1buf_remove_octetstring(&subbuf, taglen, &val->subjectPublicKey.data);
-        if (retval) return retval;
+        if (retval) clean_return(retval);
         val->subjectPublicKey.length = taglen;
         next_tag();
         get_field(val->nonce, 1, asn1_decode_int32);
         opt_field(val->dhKeyExpiration, 2, asn1_decode_kerberos_time, 0);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->subjectPublicKey.data);
+    val->subjectPublicKey.data = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_reply_key_pack (asn1buf *buf, krb5_reply_key_pack *val)
 {
     setup();
+    val->replyKey.contents = NULL;
+    val->asChecksum.contents = NULL;
     { begin_structure();
         get_field(val->replyKey, 0, asn1_decode_encryption_key);
         get_field(val->asChecksum, 1, asn1_decode_checksum);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->replyKey.contents);
+    free(val->asChecksum.contents);
+    val->replyKey.contents = NULL;
+    val->asChecksum.contents = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_reply_key_pack_draft9 (asn1buf *buf, krb5_reply_key_pack_draft9 *val)
 {
     setup();
+    val->replyKey.contents = NULL;
     { begin_structure();
         get_field(val->replyKey, 0, asn1_decode_encryption_key);
         get_field(val->nonce, 1, asn1_decode_int32);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->replyKey.contents);
+    val->replyKey.contents = NULL;
+    return retval;
 }
 
 
 asn1_error_code asn1_decode_krb5_principal_name (asn1buf *buf, krb5_principal *val)
 {
+    int i;
     setup();
+    (*val)->realm.data = NULL;
+    (*val)->data = NULL;
     { begin_structure();
         get_field(*val, 0, asn1_decode_realm);
         get_field(*val, 1, asn1_decode_principal_name);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    krb5_free_data_contents(NULL, &(*val)->realm);
+    if ((*val)->data) {
+        for (i = 0; i < (*val)->length; i++)
+            krb5_free_data_contents(NULL, &(*val)->data[i]);
+        free((*val)->data);
+    }
+    (*val)->realm.data = NULL;
+    (*val)->data = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_auth_pack(asn1buf *buf, krb5_auth_pack *val)
 {
+    int i;
     setup();
+    val->clientPublicValue = NULL;
+    val->pkAuthenticator.paChecksum.contents = NULL;
+    val->supportedCMSTypes = NULL;
+    val->clientDHNonce.data = NULL;
     { begin_structure();
         get_field(val->pkAuthenticator, 0, asn1_decode_pk_authenticator);
-        if (tagnum == 1) { alloc_field(val->clientPublicValue, krb5_subject_pk_info); }
+        if (tagnum == 1) {
+            alloc_field(val->clientPublicValue);
+            val->clientPublicValue->algorithm.algorithm.data = NULL;
+            val->clientPublicValue->algorithm.parameters.data = NULL;
+            val->clientPublicValue->subjectPublicKey.data = NULL;
+        }
         /* can't call opt_field because it does decoder(&subbuf, &(val)); */
         if (asn1buf_remains(&subbuf, seqindef)) {
             if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
                 && (tagnum || taglen || asn1class != UNIVERSAL))
-                return ASN1_BAD_ID;
+                clean_return(ASN1_BAD_ID);
             if (tagnum == 1) {
                 retval = asn1_decode_subject_pk_info(&subbuf,
                                                      val->clientPublicValue);
+                if (retval) clean_return(retval);
                 if (!taglen && indef) { get_eoc(); }
                 next_tag();
             } else val->clientPublicValue = NULL;
@@ -1544,7 +2134,8 @@ asn1_error_code asn1_decode_auth_pack(asn1buf *buf, krb5_auth_pack *val)
         /* can't call opt_field because it does decoder(&subbuf, &(val)); */
         if (asn1buf_remains(&subbuf, seqindef)) {
             if (tagnum == 2) {
-                asn1_decode_sequence_of_algorithm_identifier(&subbuf, &val->supportedCMSTypes);
+                retval = asn1_decode_sequence_of_algorithm_identifier(&subbuf, &val->supportedCMSTypes);
+                if (retval) clean_return(retval);
                 if (!taglen && indef) { get_eoc(); }
                 next_tag();
             } else val->supportedCMSTypes = NULL;
@@ -1552,24 +2143,49 @@ asn1_error_code asn1_decode_auth_pack(asn1buf *buf, krb5_auth_pack *val)
         opt_lenfield(val->clientDHNonce.length, val->clientDHNonce.data, 3, asn1_decode_octetstring);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    if (val->clientPublicValue) {
+        free(val->clientPublicValue->algorithm.algorithm.data);
+        free(val->clientPublicValue->algorithm.parameters.data);
+        free(val->clientPublicValue->subjectPublicKey.data);
+        free(val->clientPublicValue);
+    }
+    free(val->pkAuthenticator.paChecksum.contents);
+    if (val->supportedCMSTypes) {
+        for (i = 0; val->supportedCMSTypes[i]; i++)
+            free_algorithm_identifier(NULL, val->supportedCMSTypes[i]);
+        free(val->supportedCMSTypes);
+    }
+    free(val->clientDHNonce.data);
+    val->clientPublicValue = NULL;
+    val->pkAuthenticator.paChecksum.contents = NULL;
+    val->supportedCMSTypes = NULL;
+    val->clientDHNonce.data = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_auth_pack_draft9(asn1buf *buf, krb5_auth_pack_draft9 *val)
 {
     setup();
+    val->pkAuthenticator.kdcName = NULL;
+    val->clientPublicValue = NULL;
     { begin_structure();
         get_field(val->pkAuthenticator, 0, asn1_decode_pk_authenticator_draft9);
         if (tagnum == 1) {
-            alloc_field(val->clientPublicValue, krb5_subject_pk_info);
+            alloc_field(val->clientPublicValue);
+            val->clientPublicValue->algorithm.algorithm.data = NULL;
+            val->clientPublicValue->algorithm.parameters.data = NULL;
+            val->clientPublicValue->subjectPublicKey.data = NULL;
             /* can't call opt_field because it does decoder(&subbuf, &(val)); */
             if (asn1buf_remains(&subbuf, seqindef)) {
                 if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
                     && (tagnum || taglen || asn1class != UNIVERSAL))
-                    return ASN1_BAD_ID;
+                    clean_return(ASN1_BAD_ID);
                 if (tagnum == 1) {
                     retval = asn1_decode_subject_pk_info(&subbuf,
                                                          val->clientPublicValue);
+                    if (retval) clean_return(retval);
                     if (!taglen && indef) { get_eoc(); }
                     next_tag();
                 } else val->clientPublicValue = NULL;
@@ -1577,18 +2193,33 @@ asn1_error_code asn1_decode_auth_pack_draft9(asn1buf *buf, krb5_auth_pack_draft9
         }
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->pkAuthenticator.kdcName);
+    if (val->clientPublicValue) {
+        free(val->clientPublicValue->algorithm.algorithm.data);
+        free(val->clientPublicValue->algorithm.parameters.data);
+        free(val->clientPublicValue->subjectPublicKey.data);
+        free(val->clientPublicValue);
+    }
+    val->pkAuthenticator.kdcName = NULL;
+    val->clientPublicValue = NULL;
+    return retval;
 }
 
 asn1_error_code asn1_decode_pa_pk_as_rep(asn1buf *buf, krb5_pa_pk_as_rep *val)
 {
     setup();
+    val->choice = choice_pa_pk_as_rep_UNKNOWN;
     { begin_choice();
         if (tagnum == choice_pa_pk_as_rep_dhInfo) {
             val->choice = choice_pa_pk_as_rep_dhInfo;
+            val->u.dh_Info.dhSignedData.data = NULL;
+            val->u.dh_Info.serverDHNonce.data = NULL;
             get_field_body(val->u.dh_Info, asn1_decode_dh_rep_info);
         } else if (tagnum == choice_pa_pk_as_rep_encKeyPack) {
             val->choice = choice_pa_pk_as_rep_encKeyPack;
+            val->u.encKeyPack.data = NULL;
             get_implicit_octet_string(val->u.encKeyPack.length, val->u.encKeyPack.data,
                                       choice_pa_pk_as_rep_encKeyPack);
         } else {
@@ -1596,19 +2227,31 @@ asn1_error_code asn1_decode_pa_pk_as_rep(asn1buf *buf, krb5_pa_pk_as_rep *val)
         }
         end_choice();
     }
-    cleanup();
+    return 0;
+error_out:
+    if (val->choice == choice_pa_pk_as_rep_dhInfo) {
+        free(val->u.dh_Info.dhSignedData.data);
+        free(val->u.dh_Info.serverDHNonce.data);
+    } else if (val->choice == choice_pa_pk_as_rep_encKeyPack) {
+        free(val->u.encKeyPack.data);
+    }
+    val->choice = choice_pa_pk_as_rep_UNKNOWN;
+    return retval;
 }
 
 asn1_error_code asn1_decode_pa_pk_as_rep_draft9(asn1buf *buf, krb5_pa_pk_as_rep_draft9 *val)
 {
     setup();
+    val->choice = choice_pa_pk_as_rep_draft9_UNKNOWN;
     { begin_structure();
         if (tagnum == choice_pa_pk_as_rep_draft9_dhSignedData) {
             val->choice = choice_pa_pk_as_rep_draft9_dhSignedData;
+            val->u.dhSignedData.data = NULL;
             get_lenfield(val->u.dhSignedData.length, val->u.dhSignedData.data,
                          choice_pa_pk_as_rep_draft9_dhSignedData, asn1_decode_octetstring);
         } else if (tagnum == choice_pa_pk_as_rep_draft9_encKeyPack) {
             val->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
+            val->u.encKeyPack.data = NULL;
             get_lenfield(val->u.encKeyPack.length, val->u.encKeyPack.data,
                          choice_pa_pk_as_rep_draft9_encKeyPack, asn1_decode_octetstring);
         } else {
@@ -1616,22 +2259,47 @@ asn1_error_code asn1_decode_pa_pk_as_rep_draft9(asn1buf *buf, krb5_pa_pk_as_rep_
         }
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    if (val->choice == choice_pa_pk_as_rep_draft9_dhSignedData)
+        free(val->u.dhSignedData.data);
+    else if (val->choice == choice_pa_pk_as_rep_draft9_encKeyPack)
+        free(val->u.encKeyPack.data);
+    val->choice = choice_pa_pk_as_rep_draft9_UNKNOWN;
+    return retval;
+}
+
+static void free_typed_data(void *dummy, krb5_typed_data *val)
+{
+    free(val->data);
+    free(val);
 }
 
 asn1_error_code asn1_decode_sequence_of_typed_data(asn1buf *buf, krb5_typed_data ***val)
 {
-    decode_array_body(krb5_typed_data,asn1_decode_typed_data);
+    decode_array_body(krb5_typed_data,asn1_decode_typed_data_ptr,
+                      free_typed_data);
 }
 
 asn1_error_code asn1_decode_typed_data(asn1buf *buf, krb5_typed_data *val)
 {
     setup();
+    val->data = NULL;
     { begin_structure();
         get_field(val->type,0,asn1_decode_int32);
         get_lenfield(val->length,val->data,1,asn1_decode_octetstring);
         end_structure();
     }
-    cleanup();
+    return 0;
+error_out:
+    free(val->data);
+    val->data = NULL;
+    return retval;
+}
+
+asn1_error_code
+asn1_decode_typed_data_ptr(asn1buf *buf, krb5_typed_data **valptr)
+{
+    decode_ptr(krb5_typed_data *, asn1_decode_typed_data);
 }
 #endif /* DISABLE_PKINIT */
index 3ec84c051eba28086e0ade36f8415c11c73101fc..f258f65c4d592a0472b68e6e3eb8d067e9dfb268 100644 (file)
@@ -104,8 +104,12 @@ asn1_error_code asn1_decode_principal_name
         (asn1buf *buf, krb5_principal *val);
 asn1_error_code asn1_decode_checksum
         (asn1buf *buf, krb5_checksum *val);
+asn1_error_code asn1_decode_checksum_ptr
+        (asn1buf *buf, krb5_checksum **valptr);
 asn1_error_code asn1_decode_encryption_key
         (asn1buf *buf, krb5_keyblock *val);
+asn1_error_code asn1_decode_encryption_key_ptr
+       (asn1buf *buf, krb5_keyblock **valptr);
 asn1_error_code asn1_decode_encrypted_data
         (asn1buf *buf, krb5_enc_data *val);
 asn1_error_code asn1_decode_ticket_flags
@@ -122,6 +126,8 @@ asn1_error_code asn1_decode_kdc_options
         (asn1buf *buf, krb5_flags *val);
 asn1_error_code asn1_decode_ticket
         (asn1buf *buf, krb5_ticket *val);
+asn1_error_code asn1_decode_ticket_ptr
+       (asn1buf *buf, krb5_ticket **valptr);
 asn1_error_code asn1_decode_kdc_req
         (asn1buf *buf, krb5_kdc_req *val);
 asn1_error_code asn1_decode_kdc_req_body
@@ -130,18 +136,30 @@ asn1_error_code asn1_decode_krb_safe_body
         (asn1buf *buf, krb5_safe *val);
 asn1_error_code asn1_decode_host_address
         (asn1buf *buf, krb5_address *val);
+asn1_error_code asn1_decode_host_address_ptr
+       (asn1buf *buf, krb5_address **valptr);
 asn1_error_code asn1_decode_kdc_rep
         (asn1buf *buf, krb5_kdc_rep *val);
 asn1_error_code asn1_decode_last_req_entry
         (asn1buf *buf, krb5_last_req_entry *val);
+asn1_error_code asn1_decode_last_req_entry_ptr
+        (asn1buf *buf, krb5_last_req_entry **valptr);
 asn1_error_code asn1_decode_authdata_elt
         (asn1buf *buf, krb5_authdata *val);
+asn1_error_code asn1_decode_authdata_elt_ptr
+        (asn1buf *buf, krb5_authdata **valptr);
 asn1_error_code asn1_decode_krb_cred_info
         (asn1buf *buf, krb5_cred_info *val);
+asn1_error_code asn1_decode_krb_cred_info_ptr
+        (asn1buf *buf, krb5_cred_info **valptr);
 asn1_error_code asn1_decode_pa_data
         (asn1buf *buf, krb5_pa_data *val);
+asn1_error_code asn1_decode_pa_data_ptr
+       (asn1buf *buf, krb5_pa_data **valptr);
 asn1_error_code asn1_decode_passwdsequence
         (asn1buf *buf, passwd_phrase_element *val);
+asn1_error_code asn1_decode_passwdsequence_ptr
+        (asn1buf *buf, passwd_phrase_element **valptr);
 asn1_error_code asn1_decode_sam_challenge
         (asn1buf *buf, krb5_sam_challenge *val);
 asn1_error_code asn1_decode_sam_challenge_2
@@ -162,10 +180,14 @@ asn1_error_code asn1_decode_predicted_sam_response
         (asn1buf *buf, krb5_predicted_sam_response *val);
 asn1_error_code asn1_decode_external_principal_identifier
         (asn1buf *buf, krb5_external_principal_identifier *val);
+asn1_error_code asn1_decode_external_principal_identifier_ptr
+        (asn1buf *buf, krb5_external_principal_identifier **valptr);
 asn1_error_code asn1_decode_pa_pk_as_req
         (asn1buf *buf, krb5_pa_pk_as_req *val);
 asn1_error_code asn1_decode_trusted_ca
         (asn1buf *buf, krb5_trusted_ca *val);
+asn1_error_code asn1_decode_trusted_ca_ptr
+        (asn1buf *buf, krb5_trusted_ca **valptr);
 asn1_error_code asn1_decode_pa_pk_as_req_draft9
         (asn1buf *buf, krb5_pa_pk_as_req_draft9 *val);
 asn1_error_code asn1_decode_dh_rep_info
@@ -178,6 +200,8 @@ asn1_error_code asn1_decode_subject_pk_info
         (asn1buf *buf, krb5_subject_pk_info *val);
 asn1_error_code asn1_decode_algorithm_identifier
         (asn1buf *buf, krb5_algorithm_identifier *val);
+asn1_error_code asn1_decode_algorithm_identifier_ptr
+        (asn1buf *buf, krb5_algorithm_identifier **valptr);
 asn1_error_code asn1_decode_auth_pack
         (asn1buf *buf, krb5_auth_pack *val);
 asn1_error_code asn1_decode_auth_pack_draft9
@@ -198,6 +222,8 @@ asn1_error_code asn1_decode_sequence_of_typed_data
         (asn1buf *buf, krb5_typed_data ***val);
 asn1_error_code asn1_decode_typed_data
         (asn1buf *buf, krb5_typed_data *val);
+asn1_error_code asn1_decode_typed_data_ptr
+        (asn1buf *buf, krb5_typed_data **valptr);
 
 /* arrays */
 asn1_error_code asn1_decode_authorization_data
index 1f2cce803eb0d41af338c3a00930223a87e07cef..57a83f1f8eb52ef9721b4ea13447eb6837f58927 100644 (file)
@@ -1304,12 +1304,10 @@ MAKE_FULL_ENCODER(encode_krb5_etype_list, etype_list);
 { unsigned int length; \
   retval = encoder(buf,len,value,&length);      \
   if (retval) {\
-    asn1buf_destroy(&buf);\
     return retval; }\
   sum += length;\
   retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
   if (retval) {\
-    asn1buf_destroy(&buf);\
     return retval; }\
   sum += length; }
 
@@ -1402,10 +1400,8 @@ asn1_error_code asn1_encode_algorithm_identifier(asn1buf *buf, const krb5_algori
     if (val->parameters.length != 0) {
         retval = asn1buf_insert_octetstring(buf, val->parameters.length,
                                             val->parameters.data);
-        if (retval) {
-            asn1buf_destroy(&buf);
+        if (retval)
             return retval;
-        }
         sum += val->parameters.length;
     }
 
@@ -1415,10 +1411,8 @@ asn1_error_code asn1_encode_algorithm_identifier(asn1buf *buf, const krb5_algori
                                  val->algorithm.data,
                                  &length);
 
-        if (retval) {
-            asn1buf_destroy(&buf);
+        if (retval)
             return retval;
-        }
         sum += length;
     }
 
@@ -1440,20 +1434,16 @@ asn1_error_code asn1_encode_subject_pk_info(asn1buf *buf, const krb5_subject_pk_
 
         retval = asn1buf_insert_octetstring(buf, val->algorithm.parameters.length,
                                             val->algorithm.parameters.data);
-        if (retval) {
-            asn1buf_destroy(&buf);
+        if (retval)
             return retval;
-        }
         sum += val->algorithm.parameters.length;
 
         retval = asn1_encode_oid(buf, val->algorithm.algorithm.length,
                                  val->algorithm.algorithm.data,
                                  &length);
 
-        if (retval) {
-            asn1buf_destroy(&buf);
+        if (retval)
             return retval;
-        }
         sum += length;
 
 
@@ -1461,10 +1451,8 @@ asn1_error_code asn1_encode_subject_pk_info(asn1buf *buf, const krb5_subject_pk_
                                 val->algorithm.parameters.length + length,
                                 &length);
 
-        if (retval) {
-            asn1buf_destroy(&buf);
+        if (retval)
             return retval;
-        }
         sum += length;
     }
 
@@ -1661,10 +1649,8 @@ asn1_error_code asn1_encode_kdc_dh_key_info(asn1buf *buf, const krb5_kdc_dh_key_
         retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0,
                                 val->subjectPublicKey.length + 1 + length,
                                 &length);
-        if (retval) {
-            asn1buf_destroy(&buf);
+        if (retval)
             return retval;
-        }
         sum += length;
     }
 
@@ -1738,10 +1724,8 @@ asn1_error_code asn1_encode_td_trusted_certifiers(asn1buf *buf, const krb5_exter
     {
         unsigned int length;
         retval = asn1_encode_sequence_of_external_principal_identifier(buf, val, &length);
-        if (retval) {
-            asn1buf_destroy(&buf);
+        if (retval)
             return retval;
-        }
         /* length set but ignored?  sum not updated?  */
     }
     asn1_cleanup();
index 71ad03b2460d829ca98363eacd1dbb3e9c4b2938..5793a0303ab3b21c33120a96b4c1a16416f2064c 100644 (file)
@@ -154,14 +154,13 @@ asn1_error_code asn1buf_skiptail(asn1buf *buf, const unsigned int length, const
     return 0;
 }
 
-asn1_error_code asn1buf_destroy(asn1buf **buf)
+void asn1buf_destroy(asn1buf **buf)
 {
     if (*buf != NULL) {
         free((*buf)->base);
         free(*buf);
         *buf = NULL;
     }
-    return 0;
 }
 
 #ifdef asn1buf_insert_octet
@@ -254,21 +253,24 @@ int asn1buf_remains(asn1buf *buf, int indef)
 asn1_error_code asn12krb5_buf(const asn1buf *buf, krb5_data **code)
 {
     unsigned int i;
-    *code = (krb5_data*)calloc(1,sizeof(krb5_data));
-    if (*code == NULL) return ENOMEM;
-    (*code)->magic = KV5M_DATA;
-    (*code)->data = NULL;
-    (*code)->length = 0;
-    (*code)->length = asn1buf_len(buf);
-    (*code)->data = (char*)malloc((((*code)->length)+1)*sizeof(char));
-    if ((*code)->data == NULL) {
-        free(*code);
-        *code = NULL;
+    krb5_data *d;
+
+    *code = NULL;
+
+    d = calloc(1, sizeof(krb5_data));
+    if (d == NULL)
+        return ENOMEM;
+    d->length = asn1buf_len(buf);
+    d->data = malloc(d->length + 1);
+    if (d->data == NULL) {
+        free(d);
         return ENOMEM;
     }
-    for (i=0; i < (*code)->length; i++)
-        ((*code)->data)[i] = (buf->base)[((*code)->length)-i-1];
-    ((*code)->data)[(*code)->length] = '\0';
+    for (i=0; i < d->length; i++)
+        d->data[i] = buf->base[d->length - i - 1];
+    d->data[d->length] = '\0';
+    d->magic = KV5M_DATA;
+    *code = d;
     return 0;
 }
 
index 874d6db5cc131d17b7c6d76501c01b8d43a440de..33affbb07f67ce4d97a6e545c33c0c37c706ed1a 100644 (file)
@@ -129,7 +129,7 @@ asn1_error_code asn1buf_skiptail
              constructed indefinite sequence.
    effects   skips trailing fields. */
 
-asn1_error_code asn1buf_destroy
+void asn1buf_destroy
         (asn1buf **buf);
 /* effects   Deallocates **buf, sets *buf to NULL. */
 
index 2d9a3daf7fc5ae82fd27f653d25a89fa1120fc70..b118c453c3d919e28edcbb61b23b7689d3cda5fb 100644 (file)
 /* set up variables */
 /* the setup* macros can return, but are always used at function start
    and thus need no malloc cleanup */
-#define setup_buf_only()\
+#define setup_buf_only(type)\
 asn1_error_code retval;\
 asn1buf buf;\
+type rep = NULL;\
 \
+*repptr = NULL;\
 retval = asn1buf_wrap_data(&buf,code);\
 if (retval) return retval
 
-#define setup_no_tagnum()\
+#define setup_no_tagnum(type)\
 asn1_class asn1class;\
 asn1_construction construction;\
-setup_buf_only()
+setup_buf_only(type)
 
-#define setup_no_length()\
+#define setup_no_length(type)\
 asn1_tagnum tagnum;\
-setup_no_tagnum()
+setup_no_tagnum(type)
 
-#define setup()\
+#define setup(type)\
 unsigned int length;\
-setup_no_length()
+setup_no_length(type)
 
 /* helper macros for cleanup */
 #define clean_return(val) { retval = val; goto error_out; }
 
 /* alloc_field is the first thing to allocate storage that may need cleanup */
-#define alloc_field(var,type)\
-var = (type*)calloc(1,sizeof(type));\
+#define alloc_field(var)\
+var = calloc(1,sizeof(*var));\
 if ((var) == NULL) clean_return(ENOMEM)
 
+/*
+ * Allocate a principal and initialize enough fields for
+ * krb5_free_principal to have defined behavior.
+ */
+#define alloc_principal(var)                    \
+  alloc_field(var);                             \
+  var->realm.data = NULL;                       \
+  var->data = NULL
+
 /* process encoding header ***************************************/
 /* decode tag and check that it == [APPLICATION tagnum] */
 #define check_apptag(tagexpect)                                         \
@@ -111,7 +122,7 @@ asn1_get_eoc_tag (asn1buf *buf)
 #define get_eoc()                       \
 {                                       \
     retval = asn1_get_eoc_tag(&subbuf); \
-    if (retval) return retval;          \
+    if (retval) clean_return(retval);   \
 }
 
 /* decode sequence header and initialize tagnum with the first field */
@@ -196,79 +207,76 @@ get_lenfield_body(len,var,decoder)
 /* finish up */
 /* to make things less painful, assume the cleanup is passed rep */
 #define cleanup(cleanup_routine)\
+   *repptr = rep; \
    return 0; \
 error_out: \
-   if (rep && *rep) { \
-        cleanup_routine(*rep); \
-        *rep = NULL; \
-   } \
+   if (rep) \
+        cleanup_routine(rep); \
    return retval;
 
 #define cleanup_none()\
+   *repptr = rep; \
    return 0; \
 error_out: \
    return retval;
 
 #define cleanup_manual()\
+   *repptr = rep; \
    return 0;
 
 #define free_field(rep,f) free((rep)->f)
-#define clear_field(rep,f) (*(rep))->f = 0
+#define clear_field(rep,f) (rep)->f = 0
 
 #ifndef LEAN_CLIENT
-krb5_error_code decode_krb5_authenticator(const krb5_data *code, krb5_authenticator **rep)
+krb5_error_code
+decode_krb5_authenticator(const krb5_data *code, krb5_authenticator **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_authenticator);
+    setup(krb5_authenticator *);
+    alloc_field(rep);
     clear_field(rep,subkey);
     clear_field(rep,checksum);
     clear_field(rep,client);
+    clear_field(rep,authorization_data);
 
     check_apptag(2);
     { begin_structure();
         { krb5_kvno kvno;
             get_field(kvno,0,asn1_decode_kvno);
             if (kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
-        alloc_field((*rep)->client,krb5_principal_data);
-        get_field((*rep)->client,1,asn1_decode_realm);
-        get_field((*rep)->client,2,asn1_decode_principal_name);
-        if (tagnum == 3) {
-            alloc_field((*rep)->checksum,krb5_checksum);
-            get_field(*((*rep)->checksum),3,asn1_decode_checksum); }
-        get_field((*rep)->cusec,4,asn1_decode_int32);
-        get_field((*rep)->ctime,5,asn1_decode_kerberos_time);
-        if (tagnum == 6) { alloc_field((*rep)->subkey,krb5_keyblock); }
-        opt_field(*((*rep)->subkey),6,asn1_decode_encryption_key);
-        opt_field((*rep)->seq_number,7,asn1_decode_seqnum);
-        opt_field((*rep)->authorization_data,8,asn1_decode_authorization_data);
-        (*rep)->magic = KV5M_AUTHENTICATOR;
+        alloc_principal(rep->client);
+        get_field(rep->client,1,asn1_decode_realm);
+        get_field(rep->client,2,asn1_decode_principal_name);
+        opt_field(rep->checksum,3,asn1_decode_checksum_ptr);
+        get_field(rep->cusec,4,asn1_decode_int32);
+        get_field(rep->ctime,5,asn1_decode_kerberos_time);
+        opt_field(rep->subkey,6,asn1_decode_encryption_key_ptr);
+        opt_field(rep->seq_number,7,asn1_decode_seqnum);
+        opt_field(rep->authorization_data,8,asn1_decode_authorization_data);
+        rep->magic = KV5M_AUTHENTICATOR;
         end_structure();
     }
     cleanup_manual();
 error_out:
-    if (rep && *rep) {
-        free_field(*rep,subkey);
-        free_field(*rep,checksum);
-        free_field(*rep,client);
-        free(*rep);
-        *rep = NULL;
-    }
+    krb5_free_authenticator(NULL, rep);
     return retval;
 }
 #endif
 
 krb5_error_code
 KRB5_CALLCONV
-krb5_decode_ticket(const krb5_data *code, krb5_ticket **rep)
+krb5_decode_ticket(const krb5_data *code, krb5_ticket **repptr)
 {
-    return decode_krb5_ticket(code, rep);
+    return decode_krb5_ticket(code, repptr);
 }
 
-krb5_error_code decode_krb5_ticket(const krb5_data *code, krb5_ticket **rep)
+krb5_error_code
+decode_krb5_ticket(const krb5_data *code, krb5_ticket **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_ticket);
+    setup(krb5_ticket *);
+    alloc_field(rep);
     clear_field(rep,server);
+    clear_field(rep,enc_part.ciphertext.data);
+    clear_field(rep,enc_part2);
 
     check_apptag(1);
     { begin_structure();
@@ -276,131 +284,152 @@ krb5_error_code decode_krb5_ticket(const krb5_data *code, krb5_ticket **rep)
             get_field(kvno,0,asn1_decode_kvno);
             if (kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO);
         }
-        alloc_field((*rep)->server,krb5_principal_data);
-        get_field((*rep)->server,1,asn1_decode_realm);
-        get_field((*rep)->server,2,asn1_decode_principal_name);
-        get_field((*rep)->enc_part,3,asn1_decode_encrypted_data);
-        (*rep)->magic = KV5M_TICKET;
+        alloc_principal(rep->server);
+        get_field(rep->server,1,asn1_decode_realm);
+        get_field(rep->server,2,asn1_decode_principal_name);
+        get_field(rep->enc_part,3,asn1_decode_encrypted_data);
+        rep->magic = KV5M_TICKET;
         end_structure();
     }
     cleanup_manual();
 error_out:
-    if (rep && *rep) {
-        free_field(*rep,server);
-        free(*rep);
-        *rep = NULL;
-    }
+    krb5_free_ticket(NULL, rep);
     return retval;
 }
 
-krb5_error_code decode_krb5_encryption_key(const krb5_data *code, krb5_keyblock **rep)
+krb5_error_code
+decode_krb5_encryption_key(const krb5_data *code, krb5_keyblock **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_keyblock);
+    setup(krb5_keyblock *);
+    alloc_field(rep);
+    clear_field(rep,contents);
 
     { begin_structure();
-        get_field((*rep)->enctype,0,asn1_decode_enctype);
-        get_lenfield((*rep)->length,(*rep)->contents,1,asn1_decode_octetstring);
+        get_field(rep->enctype,0,asn1_decode_enctype);
+        get_lenfield(rep->length,rep->contents,1,asn1_decode_octetstring);
         end_structure();
-        (*rep)->magic = KV5M_KEYBLOCK;
+        rep->magic = KV5M_KEYBLOCK;
     }
-    cleanup(free);
+    cleanup_manual();
+error_out:
+    krb5_free_keyblock(NULL, rep);
+    return retval;
 }
 
-krb5_error_code decode_krb5_enc_tkt_part(const krb5_data *code, krb5_enc_tkt_part **rep)
+krb5_error_code
+decode_krb5_enc_tkt_part(const krb5_data *code, krb5_enc_tkt_part **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_enc_tkt_part);
+    setup(krb5_enc_tkt_part *);
+    alloc_field(rep);
     clear_field(rep,session);
     clear_field(rep,client);
+    clear_field(rep,transited.tr_contents.data);
+    clear_field(rep,caddrs);
+    clear_field(rep,authorization_data);
 
     check_apptag(3);
     { begin_structure();
-        get_field((*rep)->flags,0,asn1_decode_ticket_flags);
-        alloc_field((*rep)->session,krb5_keyblock);
-        get_field(*((*rep)->session),1,asn1_decode_encryption_key);
-        alloc_field((*rep)->client,krb5_principal_data);
-        get_field((*rep)->client,2,asn1_decode_realm);
-        get_field((*rep)->client,3,asn1_decode_principal_name);
-        get_field((*rep)->transited,4,asn1_decode_transited_encoding);
-        get_field((*rep)->times.authtime,5,asn1_decode_kerberos_time);
+        get_field(rep->flags,0,asn1_decode_ticket_flags);
+        get_field(rep->session,1,asn1_decode_encryption_key_ptr);
+        alloc_principal(rep->client);
+        get_field(rep->client,2,asn1_decode_realm);
+        get_field(rep->client,3,asn1_decode_principal_name);
+        get_field(rep->transited,4,asn1_decode_transited_encoding);
+        get_field(rep->times.authtime,5,asn1_decode_kerberos_time);
         if (tagnum == 6)
-        { get_field((*rep)->times.starttime,6,asn1_decode_kerberos_time); }
+        { get_field(rep->times.starttime,6,asn1_decode_kerberos_time); }
         else
-            (*rep)->times.starttime=(*rep)->times.authtime;
-        get_field((*rep)->times.endtime,7,asn1_decode_kerberos_time);
-        opt_field((*rep)->times.renew_till,8,asn1_decode_kerberos_time);
-        opt_field((*rep)->caddrs,9,asn1_decode_host_addresses);
-        opt_field((*rep)->authorization_data,10,asn1_decode_authorization_data);
-        (*rep)->magic = KV5M_ENC_TKT_PART;
+            rep->times.starttime=rep->times.authtime;
+        get_field(rep->times.endtime,7,asn1_decode_kerberos_time);
+        opt_field(rep->times.renew_till,8,asn1_decode_kerberos_time);
+        opt_field(rep->caddrs,9,asn1_decode_host_addresses);
+        opt_field(rep->authorization_data,10,asn1_decode_authorization_data);
+        rep->magic = KV5M_ENC_TKT_PART;
         end_structure();
     }
     cleanup_manual();
 error_out:
-    if (rep && *rep) {
-        free_field(*rep,session);
-        free_field(*rep,client);
-        free(*rep);
-        *rep = NULL;
-    }
+    krb5_free_enc_tkt_part(NULL, rep);
     return retval;
 }
 
-krb5_error_code decode_krb5_enc_kdc_rep_part(const krb5_data *code, krb5_enc_kdc_rep_part **rep)
+krb5_error_code
+decode_krb5_enc_kdc_rep_part(const krb5_data *code,
+                             krb5_enc_kdc_rep_part **repptr)
 {
     taginfo t4;
-    setup_buf_only();
-    alloc_field(*rep,krb5_enc_kdc_rep_part);
+    setup_buf_only(krb5_enc_kdc_rep_part *);
+    alloc_field(rep);
 
     retval = asn1_get_tag_2(&buf, &t4);
     if (retval) clean_return(retval);
     if (t4.asn1class != APPLICATION || t4.construction != CONSTRUCTED) clean_return(ASN1_BAD_ID);
-    if (t4.tagnum == 25) (*rep)->msg_type = KRB5_AS_REP;
-    else if (t4.tagnum == 26) (*rep)->msg_type = KRB5_TGS_REP;
+    if (t4.tagnum == 25) rep->msg_type = KRB5_AS_REP;
+    else if (t4.tagnum == 26) rep->msg_type = KRB5_TGS_REP;
     else clean_return(KRB5_BADMSGTYPE);
 
-    retval = asn1_decode_enc_kdc_rep_part(&buf,*rep);
+    retval = asn1_decode_enc_kdc_rep_part(&buf,rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_as_rep(const krb5_data *code, krb5_kdc_rep **rep)
+krb5_error_code
+decode_krb5_as_rep(const krb5_data *code, krb5_kdc_rep **repptr)
 {
-    setup_no_length();
-    alloc_field(*rep,krb5_kdc_rep);
+    setup_no_length(krb5_kdc_rep *);
+    alloc_field(rep);
+    clear_field(rep,padata);
+    clear_field(rep,client);
+    clear_field(rep,ticket);
+    clear_field(rep,enc_part.ciphertext.data);
+    clear_field(rep,enc_part2);
 
     check_apptag(11);
-    retval = asn1_decode_kdc_rep(&buf,*rep);
+    retval = asn1_decode_kdc_rep(&buf,rep);
     if (retval) clean_return(retval);
 #ifdef KRB5_MSGTYPE_STRICT
-    if ((*rep)->msg_type != KRB5_AS_REP)
+    if (rep->msg_type != KRB5_AS_REP)
         clean_return(KRB5_BADMSGTYPE);
 #endif
 
-    cleanup(free);
+    cleanup_manual();
+error_out:
+    krb5_free_kdc_rep(NULL, rep);
+    return retval;
 }
 
-krb5_error_code decode_krb5_tgs_rep(const krb5_data *code, krb5_kdc_rep **rep)
+krb5_error_code
+decode_krb5_tgs_rep(const krb5_data *code, krb5_kdc_rep **repptr)
 {
-    setup_no_length();
-    alloc_field(*rep,krb5_kdc_rep);
+    setup_no_length(krb5_kdc_rep *);
+    alloc_field(rep);
+    clear_field(rep,padata);
+    clear_field(rep,client);
+    clear_field(rep,ticket);
+    clear_field(rep,enc_part.ciphertext.data);
+    clear_field(rep,enc_part2);
 
     check_apptag(13);
-    retval = asn1_decode_kdc_rep(&buf,*rep);
+    retval = asn1_decode_kdc_rep(&buf,rep);
     if (retval) clean_return(retval);
 #ifdef KRB5_MSGTYPE_STRICT
-    if ((*rep)->msg_type != KRB5_TGS_REP) clean_return(KRB5_BADMSGTYPE);
+    if (rep->msg_type != KRB5_TGS_REP) clean_return(KRB5_BADMSGTYPE);
 #endif
 
-    cleanup(free);
+    cleanup_manual();
+error_out:
+    krb5_free_kdc_rep(NULL, rep);
+    return retval;
 }
 
-krb5_error_code decode_krb5_ap_req(const krb5_data *code, krb5_ap_req **rep)
+krb5_error_code
+decode_krb5_ap_req(const krb5_data *code, krb5_ap_req **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_ap_req);
+    setup(krb5_ap_req *);
+    alloc_field(rep);
     clear_field(rep,ticket);
+    clear_field(rep,authenticator.ciphertext.data);
 
     check_apptag(14);
     { begin_structure();
@@ -413,27 +442,24 @@ krb5_error_code decode_krb5_ap_req(const krb5_data *code, krb5_ap_req **rep)
             if (msg_type != KRB5_AP_REQ) clean_return(KRB5_BADMSGTYPE);
 #endif
         }
-        get_field((*rep)->ap_options,2,asn1_decode_ap_options);
-        alloc_field((*rep)->ticket,krb5_ticket);
-        get_field(*((*rep)->ticket),3,asn1_decode_ticket);
-        get_field((*rep)->authenticator,4,asn1_decode_encrypted_data);
+        get_field(rep->ap_options,2,asn1_decode_ap_options);
+        get_field(rep->ticket,3,asn1_decode_ticket_ptr);
+        get_field(rep->authenticator,4,asn1_decode_encrypted_data);
         end_structure();
-        (*rep)->magic = KV5M_AP_REQ;
+        rep->magic = KV5M_AP_REQ;
     }
     cleanup_manual();
 error_out:
-    if (rep && *rep) {
-        free_field(*rep,ticket);
-        free(*rep);
-        *rep = NULL;
-    }
+    krb5_free_ap_req(NULL, rep);
     return retval;
 }
 
-krb5_error_code decode_krb5_ap_rep(const krb5_data *code, krb5_ap_rep **rep)
+krb5_error_code
+decode_krb5_ap_rep(const krb5_data *code, krb5_ap_rep **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_ap_rep);
+    setup(krb5_ap_rep *);
+    alloc_field(rep);
+    clear_field(rep,enc_part.ciphertext.data);
 
     check_apptag(15);
     { begin_structure();
@@ -446,75 +472,100 @@ krb5_error_code decode_krb5_ap_rep(const krb5_data *code, krb5_ap_rep **rep)
             if (msg_type != KRB5_AP_REP) clean_return(KRB5_BADMSGTYPE);
 #endif
         }
-        get_field((*rep)->enc_part,2,asn1_decode_encrypted_data);
+        get_field(rep->enc_part,2,asn1_decode_encrypted_data);
         end_structure();
-        (*rep)->magic = KV5M_AP_REP;
+        rep->magic = KV5M_AP_REP;
     }
-    cleanup(free);
+    cleanup_manual();
+error_out:
+    krb5_free_ap_rep(NULL, rep);
+    return retval;
 }
 
-krb5_error_code decode_krb5_ap_rep_enc_part(const krb5_data *code, krb5_ap_rep_enc_part **rep)
+krb5_error_code
+decode_krb5_ap_rep_enc_part(const krb5_data *code,
+                            krb5_ap_rep_enc_part **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_ap_rep_enc_part);
+    setup(krb5_ap_rep_enc_part *);
+    alloc_field(rep);
     clear_field(rep,subkey);
 
     check_apptag(27);
     { begin_structure();
-        get_field((*rep)->ctime,0,asn1_decode_kerberos_time);
-        get_field((*rep)->cusec,1,asn1_decode_int32);
-        if (tagnum == 2) { alloc_field((*rep)->subkey,krb5_keyblock); }
-        opt_field(*((*rep)->subkey),2,asn1_decode_encryption_key);
-        opt_field((*rep)->seq_number,3,asn1_decode_seqnum);
+        get_field(rep->ctime,0,asn1_decode_kerberos_time);
+        get_field(rep->cusec,1,asn1_decode_int32);
+        opt_field(rep->subkey,2,asn1_decode_encryption_key_ptr);
+        opt_field(rep->seq_number,3,asn1_decode_seqnum);
         end_structure();
-        (*rep)->magic = KV5M_AP_REP_ENC_PART;
+        rep->magic = KV5M_AP_REP_ENC_PART;
     }
     cleanup_manual();
 error_out:
-    if (rep && *rep) {
-        free_field(*rep,subkey);
-        free(*rep);
-        *rep = NULL;
-    }
+    krb5_free_ap_rep_enc_part(NULL, rep);
     return retval;
 }
 
-krb5_error_code decode_krb5_as_req(const krb5_data *code, krb5_kdc_req **rep)
+krb5_error_code
+decode_krb5_as_req(const krb5_data *code, krb5_kdc_req **repptr)
 {
-    setup_no_length();
-    alloc_field(*rep,krb5_kdc_req);
+    setup_no_length(krb5_kdc_req *);
+    alloc_field(rep);
+    clear_field(rep,padata);
+    clear_field(rep,client);
+    clear_field(rep,server);
+    clear_field(rep,ktype);
+    clear_field(rep,addresses);
+    clear_field(rep,authorization_data.ciphertext.data);
+    clear_field(rep,unenc_authdata);
+    clear_field(rep,second_ticket);
 
     check_apptag(10);
-    retval = asn1_decode_kdc_req(&buf,*rep);
+    retval = asn1_decode_kdc_req(&buf,rep);
     if (retval) clean_return(retval);
 #ifdef KRB5_MSGTYPE_STRICT
-    if ((*rep)->msg_type != KRB5_AS_REQ) clean_return(KRB5_BADMSGTYPE);
+    if (rep->msg_type != KRB5_AS_REQ) clean_return(KRB5_BADMSGTYPE);
 #endif
 
-    cleanup(free);
+    cleanup_manual();
+error_out:
+    krb5_free_kdc_req(NULL, rep);
+    return retval;
 }
 
-krb5_error_code decode_krb5_tgs_req(const krb5_data *code, krb5_kdc_req **rep)
+krb5_error_code
+decode_krb5_tgs_req(const krb5_data *code, krb5_kdc_req **repptr)
 {
-    setup_no_length();
-    alloc_field(*rep,krb5_kdc_req);
+    setup_no_length(krb5_kdc_req *);
+    alloc_field(rep);
+    clear_field(rep,padata);
+    clear_field(rep,client);
+    clear_field(rep,server);
+    clear_field(rep,ktype);
+    clear_field(rep,addresses);
+    clear_field(rep,authorization_data.ciphertext.data);
+    clear_field(rep,unenc_authdata);
+    clear_field(rep,second_ticket);
 
     check_apptag(12);
-    retval = asn1_decode_kdc_req(&buf,*rep);
+    retval = asn1_decode_kdc_req(&buf,rep);
     if (retval) clean_return(retval);
 #ifdef KRB5_MSGTYPE_STRICT
-    if ((*rep)->msg_type != KRB5_TGS_REQ) clean_return(KRB5_BADMSGTYPE);
+    if (rep->msg_type != KRB5_TGS_REQ) clean_return(KRB5_BADMSGTYPE);
 #endif
 
-    cleanup(free);
+    cleanup_manual();
+error_out:
+    krb5_free_kdc_req(NULL, rep);
+    return retval;
 }
 
-krb5_error_code decode_krb5_kdc_req_body(const krb5_data *code, krb5_kdc_req **rep)
+krb5_error_code
+decode_krb5_kdc_req_body(const krb5_data *code, krb5_kdc_req **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep,krb5_kdc_req);
+    setup_buf_only(krb5_kdc_req *);
+    alloc_field(rep);
 
-    retval = asn1_decode_kdc_req_body(&buf,*rep);
+    retval = asn1_decode_kdc_req_body(&buf,rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
@@ -534,14 +585,16 @@ krb5_error_code decode_krb5_kdc_req_body(const krb5_data *code, krb5_kdc_req **r
  * This does *not* perform any copying; the returned pointer to the
  * encoded KRB-SAFE-BODY points into the input buffer.
  */
-krb5_error_code decode_krb5_safe_with_body(
-    const krb5_data *code,
-    krb5_safe **rep,
-    krb5_data *body)
+krb5_error_code
+decode_krb5_safe_with_body(const krb5_data *code, krb5_safe **repptr,
+                           krb5_data *body)
 {
     krb5_data tmpbody;
-    setup();
-    alloc_field(*rep,krb5_safe);
+    setup(krb5_safe *);
+    alloc_field(rep);
+    clear_field(rep,user_data.data);
+    clear_field(rep,r_address);
+    clear_field(rep,s_address);
     clear_field(rep,checksum);
     tmpbody.magic = 0;
 
@@ -568,33 +621,31 @@ krb5_error_code decode_krb5_safe_with_body(
             tmpbody.length = 0;
             tmpbody.data = NULL;
         }
-        get_field(**rep,2,asn1_decode_krb_safe_body);
-        alloc_field((*rep)->checksum,krb5_checksum);
-        get_field(*((*rep)->checksum),3,asn1_decode_checksum);
-        (*rep)->magic = KV5M_SAFE;
+        get_field(*rep,2,asn1_decode_krb_safe_body);
+        get_field(rep->checksum,3,asn1_decode_checksum_ptr);
+        rep->magic = KV5M_SAFE;
         end_structure();
     }
     if (body != NULL)
         *body = tmpbody;
     cleanup_manual();
 error_out:
-    if (rep && *rep) {
-        free_field(*rep,checksum);
-        free(*rep);
-        *rep = NULL;
-    }
+    krb5_free_safe(NULL, rep);
     return retval;
 }
 
-krb5_error_code decode_krb5_safe(const krb5_data *code, krb5_safe **rep)
+krb5_error_code
+decode_krb5_safe(const krb5_data *code, krb5_safe **repptr)
 {
-    return decode_krb5_safe_with_body(code, rep, NULL);
+    return decode_krb5_safe_with_body(code, repptr, NULL);
 }
 
-krb5_error_code decode_krb5_priv(const krb5_data *code, krb5_priv **rep)
+krb5_error_code
+decode_krb5_priv(const krb5_data *code, krb5_priv **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_priv);
+    setup(krb5_priv *);
+    alloc_field(rep);
+    clear_field(rep,enc_part.ciphertext.data);
 
     check_apptag(21);
     { begin_structure();
@@ -607,48 +658,49 @@ krb5_error_code decode_krb5_priv(const krb5_data *code, krb5_priv **rep)
             if (msg_type != KRB5_PRIV) clean_return(KRB5_BADMSGTYPE);
 #endif
         }
-        get_field((*rep)->enc_part,3,asn1_decode_encrypted_data);
-        (*rep)->magic = KV5M_PRIV;
+        get_field(rep->enc_part,3,asn1_decode_encrypted_data);
+        rep->magic = KV5M_PRIV;
         end_structure();
     }
-    cleanup(free);
+    cleanup_manual();
+error_out:
+    krb5_free_priv(NULL, rep);
+    return retval;
 }
 
-krb5_error_code decode_krb5_enc_priv_part(const krb5_data *code, krb5_priv_enc_part **rep)
+krb5_error_code
+decode_krb5_enc_priv_part(const krb5_data *code, krb5_priv_enc_part **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_priv_enc_part);
+    setup(krb5_priv_enc_part *);
+    alloc_field(rep);
+    clear_field(rep,user_data.data);
     clear_field(rep,r_address);
     clear_field(rep,s_address);
 
     check_apptag(28);
     { begin_structure();
-        get_lenfield((*rep)->user_data.length,(*rep)->user_data.data,0,asn1_decode_charstring);
-        opt_field((*rep)->timestamp,1,asn1_decode_kerberos_time);
-        opt_field((*rep)->usec,2,asn1_decode_int32);
-        opt_field((*rep)->seq_number,3,asn1_decode_seqnum);
-        alloc_field((*rep)->s_address,krb5_address);
-        get_field(*((*rep)->s_address),4,asn1_decode_host_address);
-        if (tagnum == 5) { alloc_field((*rep)->r_address,krb5_address); }
-        opt_field(*((*rep)->r_address),5,asn1_decode_host_address);
-        (*rep)->magic = KV5M_PRIV_ENC_PART;
+        get_lenfield(rep->user_data.length,rep->user_data.data,0,asn1_decode_charstring);
+        opt_field(rep->timestamp,1,asn1_decode_kerberos_time);
+        opt_field(rep->usec,2,asn1_decode_int32);
+        opt_field(rep->seq_number,3,asn1_decode_seqnum);
+        get_field(rep->s_address,4,asn1_decode_host_address_ptr);
+        opt_field(rep->r_address,5,asn1_decode_host_address_ptr);
+        rep->magic = KV5M_PRIV_ENC_PART;
         end_structure();
     }
     cleanup_manual();
 error_out:
-    if (rep && *rep) {
-        free_field(*rep,r_address);
-        free_field(*rep,s_address);
-        free(*rep);
-        *rep = NULL;
-    }
+    krb5_free_priv_enc_part(NULL, rep);
     return retval;
 }
 
-krb5_error_code decode_krb5_cred(const krb5_data *code, krb5_cred **rep)
+krb5_error_code
+decode_krb5_cred(const krb5_data *code, krb5_cred **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_cred);
+    setup(krb5_cred *);
+    alloc_field(rep);
+    clear_field(rep,tickets);
+    clear_field(rep,enc_part.ciphertext.data);
 
     check_apptag(22);
     { begin_structure();
@@ -661,52 +713,55 @@ krb5_error_code decode_krb5_cred(const krb5_data *code, krb5_cred **rep)
             if (msg_type != KRB5_CRED) clean_return(KRB5_BADMSGTYPE);
 #endif
         }
-        get_field((*rep)->tickets,2,asn1_decode_sequence_of_ticket);
-        get_field((*rep)->enc_part,3,asn1_decode_encrypted_data);
-        (*rep)->magic = KV5M_CRED;
+        get_field(rep->tickets,2,asn1_decode_sequence_of_ticket);
+        get_field(rep->enc_part,3,asn1_decode_encrypted_data);
+        rep->magic = KV5M_CRED;
         end_structure();
     }
-    cleanup(free);
+    cleanup_manual();
+error_out:
+    krb5_free_cred(NULL, rep);
+    return retval;
 }
 
-krb5_error_code decode_krb5_enc_cred_part(const krb5_data *code, krb5_cred_enc_part **rep)
+krb5_error_code
+decode_krb5_enc_cred_part(const krb5_data *code, krb5_cred_enc_part **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_cred_enc_part);
+    setup(krb5_cred_enc_part *);
+    alloc_field(rep);
     clear_field(rep,r_address);
     clear_field(rep,s_address);
+    clear_field(rep,ticket_info);
 
     check_apptag(29);
     { begin_structure();
-        get_field((*rep)->ticket_info,0,asn1_decode_sequence_of_krb_cred_info);
-        opt_field((*rep)->nonce,1,asn1_decode_int32);
-        opt_field((*rep)->timestamp,2,asn1_decode_kerberos_time);
-        opt_field((*rep)->usec,3,asn1_decode_int32);
-        if (tagnum == 4) { alloc_field((*rep)->s_address,krb5_address); }
-        opt_field(*((*rep)->s_address),4,asn1_decode_host_address);
-        if (tagnum == 5) { alloc_field((*rep)->r_address,krb5_address); }
-        opt_field(*((*rep)->r_address),5,asn1_decode_host_address);
-        (*rep)->magic = KV5M_CRED_ENC_PART;
+        get_field(rep->ticket_info,0,asn1_decode_sequence_of_krb_cred_info);
+        opt_field(rep->nonce,1,asn1_decode_int32);
+        opt_field(rep->timestamp,2,asn1_decode_kerberos_time);
+        opt_field(rep->usec,3,asn1_decode_int32);
+        opt_field(rep->s_address,4,asn1_decode_host_address_ptr);
+        opt_field(rep->r_address,5,asn1_decode_host_address_ptr);
+        rep->magic = KV5M_CRED_ENC_PART;
         end_structure();
     }
     cleanup_manual();
 error_out:
-    if (rep && *rep) {
-        free_field(*rep,r_address);
-        free_field(*rep,s_address);
-        free(*rep);
-        *rep = NULL;
-    }
+    /* Despite the name, krb5_free_cred_enc_part is contents only. */
+    krb5_free_cred_enc_part(NULL, rep);
+    free(rep);
     return retval;
 }
 
 
-krb5_error_code decode_krb5_error(const krb5_data *code, krb5_error **rep)
+krb5_error_code
+decode_krb5_error(const krb5_data *code, krb5_error **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_error);
+    setup(krb5_error *);
+    alloc_field(rep);
     clear_field(rep,server);
     clear_field(rep,client);
+    clear_field(rep,text.data);
+    clear_field(rep,e_data.data);
 
     check_apptag(30);
     { begin_structure();
@@ -719,427 +774,466 @@ krb5_error_code decode_krb5_error(const krb5_data *code, krb5_error **rep)
             if (msg_type != KRB5_ERROR) clean_return(KRB5_BADMSGTYPE);
 #endif
         }
-        opt_field((*rep)->ctime,2,asn1_decode_kerberos_time);
-        opt_field((*rep)->cusec,3,asn1_decode_int32);
-        get_field((*rep)->stime,4,asn1_decode_kerberos_time);
-        get_field((*rep)->susec,5,asn1_decode_int32);
-        get_field((*rep)->error,6,asn1_decode_ui_4);
-        if (tagnum == 7) { alloc_field((*rep)->client,krb5_principal_data); }
-        opt_field((*rep)->client,7,asn1_decode_realm);
-        opt_field((*rep)->client,8,asn1_decode_principal_name);
-        alloc_field((*rep)->server,krb5_principal_data);
-        get_field((*rep)->server,9,asn1_decode_realm);
-        get_field((*rep)->server,10,asn1_decode_principal_name);
-        opt_lenfield((*rep)->text.length,(*rep)->text.data,11,asn1_decode_generalstring);
-        opt_lenfield((*rep)->e_data.length,(*rep)->e_data.data,12,asn1_decode_charstring);
-        (*rep)->magic = KV5M_ERROR;
+        opt_field(rep->ctime,2,asn1_decode_kerberos_time);
+        opt_field(rep->cusec,3,asn1_decode_int32);
+        get_field(rep->stime,4,asn1_decode_kerberos_time);
+        get_field(rep->susec,5,asn1_decode_int32);
+        get_field(rep->error,6,asn1_decode_ui_4);
+        if (tagnum == 7) { alloc_principal(rep->client); }
+        opt_field(rep->client,7,asn1_decode_realm);
+        opt_field(rep->client,8,asn1_decode_principal_name);
+        alloc_principal(rep->server);
+        get_field(rep->server,9,asn1_decode_realm);
+        get_field(rep->server,10,asn1_decode_principal_name);
+        opt_lenfield(rep->text.length,rep->text.data,11,asn1_decode_generalstring);
+        opt_lenfield(rep->e_data.length,rep->e_data.data,12,asn1_decode_charstring);
+        rep->magic = KV5M_ERROR;
         end_structure();
     }
     cleanup_manual();
 error_out:
-    if (rep && *rep) {
-        free_field(*rep,server);
-        free_field(*rep,client);
-        free(*rep);
-        *rep = NULL;
-    }
+    krb5_free_error(NULL, rep);
     return retval;
 }
 
-krb5_error_code decode_krb5_authdata(const krb5_data *code, krb5_authdata ***rep)
+krb5_error_code
+decode_krb5_authdata(const krb5_data *code, krb5_authdata ***repptr)
 {
-    setup_buf_only();
-    *rep = 0;
-    retval = asn1_decode_authorization_data(&buf,rep);
+    setup_buf_only(krb5_authdata **);
+    retval = asn1_decode_authorization_data(&buf,&rep);
     if (retval) clean_return(retval);
     cleanup_none();             /* we're not allocating anything here... */
 }
 
-krb5_error_code decode_krb5_pwd_sequence(const krb5_data *code, passwd_phrase_element **rep)
+krb5_error_code
+decode_krb5_pwd_sequence(const krb5_data *code, passwd_phrase_element **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep,passwd_phrase_element);
-    retval = asn1_decode_passwdsequence(&buf,*rep);
+    setup_buf_only(passwd_phrase_element *);
+    alloc_field(rep);
+    retval = asn1_decode_passwdsequence(&buf,rep);
     if (retval) clean_return(retval);
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_pwd_data(const krb5_data *code, krb5_pwd_data **rep)
+krb5_error_code
+decode_krb5_pwd_data(const krb5_data *code, krb5_pwd_data **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_pwd_data);
+    setup(krb5_pwd_data *);
+    alloc_field(rep);
+    clear_field(rep,element);
     { begin_structure();
-        get_field((*rep)->sequence_count,0,asn1_decode_int);
-        get_field((*rep)->element,1,asn1_decode_sequence_of_passwdsequence);
-        (*rep)->magic = KV5M_PWD_DATA;
+        get_field(rep->sequence_count,0,asn1_decode_int);
+        get_field(rep->element,1,asn1_decode_sequence_of_passwdsequence);
+        rep->magic = KV5M_PWD_DATA;
         end_structure (); }
-    cleanup(free);
+    cleanup_manual();
+error_out:
+    krb5_free_pwd_data(NULL, rep);
+    return retval;
 }
 
-krb5_error_code decode_krb5_padata_sequence(const krb5_data *code, krb5_pa_data ***rep)
+krb5_error_code
+decode_krb5_padata_sequence(const krb5_data *code, krb5_pa_data ***repptr)
 {
-    setup_buf_only();
-    *rep = 0;
-    retval = asn1_decode_sequence_of_pa_data(&buf,rep);
+    setup_buf_only(krb5_pa_data **);
+    retval = asn1_decode_sequence_of_pa_data(&buf,&rep);
     if (retval) clean_return(retval);
     cleanup_none();             /* we're not allocating anything here */
 }
 
-krb5_error_code decode_krb5_alt_method(const krb5_data *code, krb5_alt_method **rep)
+krb5_error_code
+decode_krb5_alt_method(const krb5_data *code, krb5_alt_method **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_alt_method);
+    setup(krb5_alt_method *);
+    alloc_field(rep);
+    clear_field(rep,data);
     { begin_structure();
-        get_field((*rep)->method,0,asn1_decode_int32);
+        get_field(rep->method,0,asn1_decode_int32);
         if (tagnum == 1) {
-            get_lenfield((*rep)->length,(*rep)->data,1,asn1_decode_octetstring);
+            get_lenfield(rep->length,rep->data,1,asn1_decode_octetstring);
         } else {
-            (*rep)->length = 0;
-            (*rep)->data = 0;
+            rep->length = 0;
+            rep->data = 0;
         }
-        (*rep)->magic = KV5M_ALT_METHOD;
+        rep->magic = KV5M_ALT_METHOD;
         end_structure();
     }
-    cleanup(free);
+    cleanup_manual();
+error_out:
+    krb5_free_alt_method(NULL, rep);
+    return retval;
 }
 
-krb5_error_code decode_krb5_etype_info(const krb5_data *code, krb5_etype_info_entry ***rep)
+krb5_error_code
+decode_krb5_etype_info(const krb5_data *code, krb5_etype_info_entry ***repptr)
 {
-    setup_buf_only();
-    *rep = 0;
-    retval = asn1_decode_etype_info(&buf,rep);
+    setup_buf_only(krb5_etype_info_entry **);
+    retval = asn1_decode_etype_info(&buf,&rep);
     if (retval) clean_return(retval);
     cleanup_none();             /* we're not allocating anything here */
 }
 
-krb5_error_code decode_krb5_etype_info2(const krb5_data *code, krb5_etype_info_entry ***rep)
+krb5_error_code
+decode_krb5_etype_info2(const krb5_data *code, krb5_etype_info_entry ***repptr)
 {
-    setup_buf_only();
-    *rep = 0;
-    retval = asn1_decode_etype_info2(&buf,rep, 0);
+    setup_buf_only(krb5_etype_info_entry **);
+    retval = asn1_decode_etype_info2(&buf,&rep, 0);
     if (retval == ASN1_BAD_ID) {
         retval = asn1buf_wrap_data(&buf,code);
         if (retval) clean_return(retval);
-        retval = asn1_decode_etype_info2(&buf, rep, 1);
+        retval = asn1_decode_etype_info2(&buf, &rep, 1);
     }
     if (retval) clean_return(retval);
     cleanup_none();             /* we're not allocating anything here */
 }
 
 
-krb5_error_code decode_krb5_enc_data(const krb5_data *code, krb5_enc_data **rep)
+krb5_error_code
+decode_krb5_enc_data(const krb5_data *code, krb5_enc_data **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep,krb5_enc_data);
+    setup_buf_only(krb5_enc_data *);
+    alloc_field(rep);
 
-    retval = asn1_decode_encrypted_data(&buf,*rep);
+    retval = asn1_decode_encrypted_data(&buf,rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_pa_enc_ts(const krb5_data *code, krb5_pa_enc_ts **rep)
+krb5_error_code
+decode_krb5_pa_enc_ts(const krb5_data *code, krb5_pa_enc_ts **repptr)
 {
-    setup();
-    alloc_field(*rep,krb5_pa_enc_ts);
+    setup(krb5_pa_enc_ts *);
+    alloc_field(rep);
     { begin_structure();
-        get_field((*rep)->patimestamp,0,asn1_decode_kerberos_time);
+        get_field(rep->patimestamp,0,asn1_decode_kerberos_time);
         if (tagnum == 1) {
-            get_field((*rep)->pausec,1,asn1_decode_int32);
+            get_field(rep->pausec,1,asn1_decode_int32);
         } else
-            (*rep)->pausec = 0;
+            rep->pausec = 0;
         end_structure (); }
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_sam_challenge(const krb5_data *code, krb5_sam_challenge **rep)
+krb5_error_code
+decode_krb5_sam_challenge(const krb5_data *code, krb5_sam_challenge **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep,krb5_sam_challenge);
+    setup_buf_only(krb5_sam_challenge *);
+    alloc_field(rep);
 
-    retval = asn1_decode_sam_challenge(&buf,*rep);
+    retval = asn1_decode_sam_challenge(&buf,rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_sam_challenge_2(const krb5_data *code, krb5_sam_challenge_2 **rep)
+krb5_error_code
+decode_krb5_sam_challenge_2(const krb5_data *code,
+                            krb5_sam_challenge_2 **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep,krb5_sam_challenge_2);
+    setup_buf_only(krb5_sam_challenge_2 *);
+    alloc_field(rep);
 
-    retval = asn1_decode_sam_challenge_2(&buf,*rep);
+    retval = asn1_decode_sam_challenge_2(&buf,rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_sam_challenge_2_body(const krb5_data *code, krb5_sam_challenge_2_body **rep)
+krb5_error_code
+decode_krb5_sam_challenge_2_body(const krb5_data *code,
+                                 krb5_sam_challenge_2_body **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_sam_challenge_2_body);
+    setup_buf_only(krb5_sam_challenge_2_body *);
+    alloc_field(rep);
 
-    retval = asn1_decode_sam_challenge_2_body(&buf, *rep);
+    retval = asn1_decode_sam_challenge_2_body(&buf, rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_enc_sam_key(const krb5_data *code, krb5_sam_key **rep)
+krb5_error_code
+decode_krb5_enc_sam_key(const krb5_data *code, krb5_sam_key **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep,krb5_sam_key);
+    setup_buf_only(krb5_sam_key *);
+    alloc_field(rep);
 
-    retval = asn1_decode_enc_sam_key(&buf,*rep);
+    retval = asn1_decode_enc_sam_key(&buf,rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_enc_sam_response_enc(const krb5_data *code, krb5_enc_sam_response_enc **rep)
+krb5_error_code
+decode_krb5_enc_sam_response_enc(const krb5_data *code,
+                                 krb5_enc_sam_response_enc **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep,krb5_enc_sam_response_enc);
+    setup_buf_only(krb5_enc_sam_response_enc *);
+    alloc_field(rep);
 
-    retval = asn1_decode_enc_sam_response_enc(&buf,*rep);
+    retval = asn1_decode_enc_sam_response_enc(&buf,rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_enc_sam_response_enc_2(const krb5_data *code, krb5_enc_sam_response_enc_2 **rep)
+krb5_error_code
+decode_krb5_enc_sam_response_enc_2(const krb5_data *code,
+                                   krb5_enc_sam_response_enc_2 **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep,krb5_enc_sam_response_enc_2);
+    setup_buf_only(krb5_enc_sam_response_enc_2 *);
+    alloc_field(rep);
 
-    retval = asn1_decode_enc_sam_response_enc_2(&buf,*rep);
+    retval = asn1_decode_enc_sam_response_enc_2(&buf,rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_sam_response(const krb5_data *code, krb5_sam_response **rep)
+krb5_error_code
+decode_krb5_sam_response(const krb5_data *code,
+                         krb5_sam_response **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep,krb5_sam_response);
+    setup_buf_only(krb5_sam_response *);
+    alloc_field(rep);
 
-    retval = asn1_decode_sam_response(&buf,*rep);
+    retval = asn1_decode_sam_response(&buf,rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_sam_response_2(const krb5_data *code, krb5_sam_response_2 **rep)
+krb5_error_code
+decode_krb5_sam_response_2(const krb5_data *code,
+                           krb5_sam_response_2 **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep,krb5_sam_response_2);
+    setup_buf_only(krb5_sam_response_2 *);
+    alloc_field(rep);
 
-    retval = asn1_decode_sam_response_2(&buf,*rep);
+    retval = asn1_decode_sam_response_2(&buf,rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_predicted_sam_response(const krb5_data *code, krb5_predicted_sam_response **rep)
+krb5_error_code
+decode_krb5_predicted_sam_response(const krb5_data *code,
+                                   krb5_predicted_sam_response **repptr)
 {
-    setup_buf_only();           /* preallocated */
-    alloc_field(*rep,krb5_predicted_sam_response);
+    setup_buf_only(krb5_predicted_sam_response *);           /* preallocated */
+    alloc_field(rep);
 
-    retval = asn1_decode_predicted_sam_response(&buf,*rep);
+    retval = asn1_decode_predicted_sam_response(&buf,rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_setpw_req(const krb5_data *code,
-                                      krb5_data **rep,
-                                      krb5_principal *principal)
+krb5_error_code
+decode_krb5_setpw_req(const krb5_data *code, krb5_data **repptr,
+                      krb5_principal *principal)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_data);
+    setup_buf_only(krb5_data *);
+    alloc_field(rep);
     *principal = NULL;
 
-    retval = asn1_decode_setpw_req(&buf, *rep, principal);
+    retval = asn1_decode_setpw_req(&buf, rep, principal);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_pa_for_user(const krb5_data *code, krb5_pa_for_user **rep)
+krb5_error_code
+decode_krb5_pa_for_user(const krb5_data *code, krb5_pa_for_user **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_pa_for_user);
+    setup_buf_only(krb5_pa_for_user *);
+    alloc_field(rep);
 
-    retval = asn1_decode_pa_for_user(&buf, *rep);
+    retval = asn1_decode_pa_for_user(&buf, rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_pa_pac_req(const krb5_data *code, krb5_pa_pac_req **rep)
+krb5_error_code
+decode_krb5_pa_pac_req(const krb5_data *code, krb5_pa_pac_req **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_pa_pac_req);
+    setup_buf_only(krb5_pa_pac_req *);
+    alloc_field(rep);
 
-    retval = asn1_decode_pa_pac_req(&buf, *rep);
+    retval = asn1_decode_pa_pac_req(&buf, rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_etype_list(const krb5_data *code, krb5_etype_list **rep)
+krb5_error_code
+decode_krb5_etype_list(const krb5_data *code, krb5_etype_list **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_etype_list);
+    setup_buf_only(krb5_etype_list *);
+    alloc_field(rep);
 
-    retval = asn1_decode_sequence_of_enctype(&buf, &(*rep)->length, &(*rep)->etypes);
+    retval = asn1_decode_sequence_of_enctype(&buf, &rep->length, &rep->etypes);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
 #ifndef DISABLE_PKINIT
-krb5_error_code decode_krb5_pa_pk_as_req(const krb5_data *code, krb5_pa_pk_as_req **rep)
+krb5_error_code
+decode_krb5_pa_pk_as_req(const krb5_data *code, krb5_pa_pk_as_req **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_pa_pk_as_req);
+    setup_buf_only(krb5_pa_pk_as_req *);
+    alloc_field(rep);
 
-    retval = asn1_decode_pa_pk_as_req(&buf, *rep);
+    retval = asn1_decode_pa_pk_as_req(&buf, rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_pa_pk_as_req_draft9(const krb5_data *code, krb5_pa_pk_as_req_draft9 **rep)
+krb5_error_code
+decode_krb5_pa_pk_as_req_draft9(const krb5_data *code,
+                                krb5_pa_pk_as_req_draft9 **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_pa_pk_as_req_draft9);
+    setup_buf_only(krb5_pa_pk_as_req_draft9 *);
+    alloc_field(rep);
 
-    retval = asn1_decode_pa_pk_as_req_draft9(&buf, *rep);
+    retval = asn1_decode_pa_pk_as_req_draft9(&buf, rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_pa_pk_as_rep(const krb5_data *code, krb5_pa_pk_as_rep **rep)
+krb5_error_code
+decode_krb5_pa_pk_as_rep(const krb5_data *code, krb5_pa_pk_as_rep **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_pa_pk_as_rep);
+    setup_buf_only(krb5_pa_pk_as_rep *);
+    alloc_field(rep);
 
-    retval = asn1_decode_pa_pk_as_rep(&buf, *rep);
+    retval = asn1_decode_pa_pk_as_rep(&buf, rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_pa_pk_as_rep_draft9(const krb5_data *code, krb5_pa_pk_as_rep_draft9 **rep)
+krb5_error_code
+decode_krb5_pa_pk_as_rep_draft9(const krb5_data *code,
+                                krb5_pa_pk_as_rep_draft9 **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_pa_pk_as_rep_draft9);
+    setup_buf_only(krb5_pa_pk_as_rep_draft9 *);
+    alloc_field(rep);
 
-    retval = asn1_decode_pa_pk_as_rep_draft9(&buf, *rep);
+    retval = asn1_decode_pa_pk_as_rep_draft9(&buf, rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_auth_pack(const krb5_data *code, krb5_auth_pack **rep)
+krb5_error_code
+decode_krb5_auth_pack(const krb5_data *code, krb5_auth_pack **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_auth_pack);
+    setup_buf_only(krb5_auth_pack *);
+    alloc_field(rep);
 
-    retval = asn1_decode_auth_pack(&buf, *rep);
+    retval = asn1_decode_auth_pack(&buf, rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_auth_pack_draft9(const krb5_data *code, krb5_auth_pack_draft9 **rep)
+krb5_error_code
+decode_krb5_auth_pack_draft9(const krb5_data *code,
+                             krb5_auth_pack_draft9 **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_auth_pack_draft9);
+    setup_buf_only(krb5_auth_pack_draft9 *);
+    alloc_field(rep);
 
-    retval = asn1_decode_auth_pack_draft9(&buf, *rep);
+    retval = asn1_decode_auth_pack_draft9(&buf, rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_kdc_dh_key_info(const krb5_data *code, krb5_kdc_dh_key_info **rep)
+krb5_error_code
+decode_krb5_kdc_dh_key_info(const krb5_data *code,
+                            krb5_kdc_dh_key_info **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_kdc_dh_key_info);
+    setup_buf_only(krb5_kdc_dh_key_info *);
+    alloc_field(rep);
 
-    retval = asn1_decode_kdc_dh_key_info(&buf, *rep);
+    retval = asn1_decode_kdc_dh_key_info(&buf, rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_principal_name(const krb5_data *code, krb5_principal_data **rep)
+krb5_error_code
+decode_krb5_principal_name(const krb5_data *code, krb5_principal_data **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_principal_data);
+    setup_buf_only(krb5_principal_data *);
+    alloc_field(rep);
 
-    retval = asn1_decode_krb5_principal_name(&buf, rep);
+    retval = asn1_decode_krb5_principal_name(&buf, &rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_reply_key_pack(const krb5_data *code, krb5_reply_key_pack **rep)
+krb5_error_code
+decode_krb5_reply_key_pack(const krb5_data *code, krb5_reply_key_pack **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_reply_key_pack);
+    setup_buf_only(krb5_reply_key_pack *);
+    alloc_field(rep);
 
-    retval = asn1_decode_reply_key_pack(&buf, *rep);
+    retval = asn1_decode_reply_key_pack(&buf, rep);
     if (retval)
         goto error_out;
 
-    cleanup_manual();
-error_out:
-    if (rep && *rep) {
-        free((*rep)->replyKey.contents);
-        free((*rep)->asChecksum.contents);
-        free(*rep);
-        *rep = NULL;
-    }
-    return retval;
+    cleanup(free);
 }
 
-krb5_error_code decode_krb5_reply_key_pack_draft9(const krb5_data *code, krb5_reply_key_pack_draft9 **rep)
+krb5_error_code
+decode_krb5_reply_key_pack_draft9(const krb5_data *code,
+                                  krb5_reply_key_pack_draft9 **repptr)
 {
-    setup_buf_only();
-    alloc_field(*rep, krb5_reply_key_pack_draft9);
+    setup_buf_only(krb5_reply_key_pack_draft9 *);
+    alloc_field(rep);
 
-    retval = asn1_decode_reply_key_pack_draft9(&buf, *rep);
+    retval = asn1_decode_reply_key_pack_draft9(&buf, rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_typed_data(const krb5_data *code, krb5_typed_data ***rep)
+krb5_error_code
+decode_krb5_typed_data(const krb5_data *code, krb5_typed_data ***repptr)
 {
-    setup_buf_only();
-    retval = asn1_decode_sequence_of_typed_data(&buf, rep);
+    setup_buf_only(krb5_typed_data **);
+    retval = asn1_decode_sequence_of_typed_data(&buf, &rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_td_trusted_certifiers(const krb5_data *code, krb5_external_principal_identifier ***rep)
+krb5_error_code
+decode_krb5_td_trusted_certifiers(const krb5_data *code,
+                                  krb5_external_principal_identifier ***repptr)
 {
-    setup_buf_only();
-    retval = asn1_decode_sequence_of_external_principal_identifier(&buf, rep);
+    setup_buf_only(krb5_external_principal_identifier **);
+    retval = asn1_decode_sequence_of_external_principal_identifier(&buf, &rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_td_dh_parameters(const krb5_data *code, krb5_algorithm_identifier ***rep)
+krb5_error_code
+decode_krb5_td_dh_parameters(const krb5_data *code,
+                             krb5_algorithm_identifier ***repptr)
 {
-    setup_buf_only();
-    retval = asn1_decode_sequence_of_algorithm_identifier(&buf, rep);
+    setup_buf_only(krb5_algorithm_identifier **);
+    retval = asn1_decode_sequence_of_algorithm_identifier(&buf, &rep);
     if (retval) clean_return(retval);
 
     cleanup(free);
index a6fa305e6236b9d847b4ccef15e683f87c4c9fec..a8ac06a54b680945d7b2790597d332343c09d4d3 100644 (file)
@@ -44,6 +44,9 @@
   asn1_error_code retval;\
   unsigned int length, sum = 0;\
   asn1buf *buf=NULL;\
+  krb5_data *tmpcode;\
+\
+  *code = NULL;\
 \
   if (rep == NULL) return ASN1_MISSING_FIELD;\
 \
 
 /* produce the final output and clean up the workspace */
 #define krb5_cleanup()\
-  retval = asn12krb5_buf(buf,code);\
-  if (retval) {\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  retval = asn1buf_destroy(&buf);\
-  if (retval) {\
-    return retval; }\
-\
+  retval = asn12krb5_buf(buf,&tmpcode);\
+error:\
+  asn1buf_destroy(&buf);\
+  if (retval)\
+    return retval;\
+  *code = tmpcode;\
   return 0
 
 krb5_error_code encode_krb5_pa_pk_as_req(const krb5_pa_pk_as_req *rep, krb5_data **code)
 {
     krb5_setup();
     retval = asn1_encode_pa_pk_as_req(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
@@ -75,7 +76,7 @@ krb5_error_code encode_krb5_pa_pk_as_req_draft9(const krb5_pa_pk_as_req_draft9 *
 {
     krb5_setup();
     retval = asn1_encode_pa_pk_as_req_draft9(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
@@ -84,7 +85,7 @@ krb5_error_code encode_krb5_pa_pk_as_rep(const krb5_pa_pk_as_rep *rep, krb5_data
 {
     krb5_setup();
     retval = asn1_encode_pa_pk_as_rep(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
@@ -93,7 +94,7 @@ krb5_error_code encode_krb5_pa_pk_as_rep_draft9(const krb5_pa_pk_as_rep_draft9 *
 {
     krb5_setup();
     retval = asn1_encode_pa_pk_as_rep_draft9(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
@@ -102,7 +103,7 @@ krb5_error_code encode_krb5_auth_pack(const krb5_auth_pack *rep, krb5_data **cod
 {
     krb5_setup();
     retval = asn1_encode_auth_pack(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
@@ -111,7 +112,7 @@ krb5_error_code encode_krb5_auth_pack_draft9(const krb5_auth_pack_draft9 *rep, k
 {
     krb5_setup();
     retval = asn1_encode_auth_pack_draft9(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
@@ -120,7 +121,7 @@ krb5_error_code encode_krb5_kdc_dh_key_info(const krb5_kdc_dh_key_info *rep, krb
 {
     krb5_setup();
     retval = asn1_encode_kdc_dh_key_info(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
@@ -129,7 +130,7 @@ krb5_error_code encode_krb5_reply_key_pack(const krb5_reply_key_pack *rep, krb5_
 {
     krb5_setup();
     retval = asn1_encode_reply_key_pack(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
@@ -138,7 +139,7 @@ krb5_error_code encode_krb5_reply_key_pack_draft9(const krb5_reply_key_pack_draf
 {
     krb5_setup();
     retval = asn1_encode_reply_key_pack_draft9(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
@@ -147,7 +148,7 @@ krb5_error_code encode_krb5_td_trusted_certifiers(const krb5_external_principal_
 {
     krb5_setup();
     retval = asn1_encode_td_trusted_certifiers(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
@@ -156,7 +157,7 @@ krb5_error_code encode_krb5_typed_data(const krb5_typed_data **rep, krb5_data **
 {
     krb5_setup();
     retval = asn1_encode_sequence_of_typed_data(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
@@ -165,7 +166,7 @@ krb5_error_code encode_krb5_td_dh_parameters(const krb5_algorithm_identifier **r
 {
     krb5_setup();
     retval = asn1_encode_sequence_of_algorithm_identifier(buf,rep,&length);
-    if (retval) return retval;
+    if (retval) goto error;
     sum += length;
     krb5_cleanup();
 }
index c7c1c602c379b74d64a412b38cb98184f25c4772..e0e71746d6de94ff352bbb231ec7fb14a1baba01 100644 (file)
@@ -79,6 +79,15 @@ krb5_free_addresses(krb5_context context, krb5_address **val)
 }
 
 
+void KRB5_CALLCONV
+krb5_free_alt_method(krb5_context context,
+                    krb5_alt_method *alt)
+{
+    if (alt) {
+       free(alt->data);
+       free(alt);
+    }
+}
 void KRB5_CALLCONV
 krb5_free_ap_rep(krb5_context context, register krb5_ap_rep *val)
 {
@@ -254,6 +263,15 @@ krb5_free_data_contents(krb5_context context, krb5_data *val)
     }
 }
 
+void KRB5_CALLCONV
+krb5_free_enc_data(krb5_context context, krb5_enc_data *val)
+{
+    if (val == NULL)
+       return;
+    krb5_free_data_contents(context, &val->ciphertext);
+    free(val);
+}
+
 void krb5_free_etype_info(krb5_context context, krb5_etype_info info)
 {
     int i;
@@ -425,6 +443,22 @@ krb5_free_pwd_data(krb5_context context, krb5_pwd_data *val)
 }
 
 
+void KRB5_CALLCONV
+krb5_free_passwd_phrase_element(krb5_context context,
+                               passwd_phrase_element *val)
+{
+    register passwd_phrase_element **temp;
+
+    if (val == NULL)
+       return;
+    krb5_free_data(context, val->passwd);
+    val->passwd = NULL;
+    krb5_free_data(context, val->phrase);
+    val->phrase = NULL;
+    free(val);
+}
+
+
 void KRB5_CALLCONV
 krb5_free_pwd_sequences(krb5_context context, passwd_phrase_element **val)
 {
@@ -432,13 +466,8 @@ krb5_free_pwd_sequences(krb5_context context, passwd_phrase_element **val)
 
     if (val == NULL)
        return;
-    for (temp = val; *temp; temp++) {
-       krb5_free_data(context, (*temp)->passwd);
-       (*temp)->passwd = 0;
-       krb5_free_data(context, (*temp)->phrase);
-       (*temp)->phrase = 0;
-       free(*temp);
-    }
+    for (temp = val; *temp; temp++)
+       krb5_free_passwd_phrase_element(context, *temp);
     free(val);
 }
 
index f04e8b5e6fb1537c02e7b925f0ce81acf0b594f3..7112411a9bc84032f84391d350a9c8d91bbd132f 100644 (file)
@@ -13,10 +13,12 @@ decode_krb5_enc_data
 decode_krb5_enc_kdc_rep_part
 decode_krb5_enc_priv_part
 decode_krb5_enc_sam_response_enc
+decode_krb5_enc_sam_response_enc_2
 decode_krb5_enc_tkt_part
 decode_krb5_encryption_key
 decode_krb5_error
 decode_krb5_etype_info
+decode_krb5_etype_info2
 decode_krb5_kdc_req_body
 decode_krb5_pa_enc_ts
 decode_krb5_pa_for_user
@@ -29,6 +31,7 @@ decode_krb5_pwd_sequence
 decode_krb5_safe
 decode_krb5_sam_challenge
 decode_krb5_sam_response
+decode_krb5_sam_response_2
 decode_krb5_setpw_req
 decode_krb5_tgs_rep
 decode_krb5_tgs_req
@@ -47,6 +50,7 @@ encode_krb5_enc_data
 encode_krb5_enc_kdc_rep_part
 encode_krb5_enc_priv_part
 encode_krb5_enc_sam_response_enc
+encode_krb5_enc_sam_response_enc_2
 encode_krb5_enc_tkt_part
 encode_krb5_encryption_key
 encode_krb5_error
@@ -66,6 +70,7 @@ encode_krb5_safe
 encode_krb5_sam_challenge
 encode_krb5_sam_key
 encode_krb5_sam_response
+encode_krb5_sam_response_2
 encode_krb5_tgs_rep
 encode_krb5_tgs_req
 encode_krb5_ticket
@@ -192,6 +197,7 @@ krb5_fcc_ops
 krb5_find_serializer
 krb5_free_address
 krb5_free_addresses
+krb5_free_alt_method
 krb5_free_ap_rep
 krb5_free_ap_rep_enc_part
 krb5_free_ap_req
@@ -209,6 +215,7 @@ krb5_free_creds
 krb5_free_data
 krb5_free_data_contents
 krb5_free_default_realm
+krb5_free_enc_data
 krb5_free_enc_kdc_rep_part
 krb5_free_enc_sam_response_enc
 krb5_free_enc_sam_response_enc_2
@@ -233,6 +240,7 @@ krb5_free_pa_pac_req
 krb5_free_pa_for_user
 krb5_free_pa_server_referral_data
 krb5_free_pa_svr_referral_data
+krb5_free_passwd_phrase_element
 krb5_free_predicted_sam_response
 krb5_free_predicted_sam_response_contents
 krb5_free_principal