Asn.1 decode related file rearrangement. It was made based on the following criteria:
authorZhanna Tsitkov <tsitkova@mit.edu>
Tue, 11 Jan 2011 20:00:52 +0000 (20:00 +0000)
committerZhanna Tsitkov <tsitkova@mit.edu>
Tue, 11 Jan 2011 20:00:52 +0000 (20:00 +0000)
1. based on functionality (for example, kdc-only code)
2. Well defined clusters of functions (fast, sam).

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24593 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/asn.1/Makefile.in
src/lib/krb5/asn.1/asn1_k_decode.c
src/lib/krb5/asn.1/asn1_k_decode_fast.c [new file with mode: 0644]
src/lib/krb5/asn.1/asn1_k_decode_kdc.c [new file with mode: 0644]
src/lib/krb5/asn.1/asn1_k_decode_macros.h [new file with mode: 0644]
src/lib/krb5/asn.1/asn1_k_decode_sam.c [new file with mode: 0644]
src/lib/krb5/asn.1/deps
src/lib/krb5/asn.1/krb5_decode.c
src/lib/krb5/asn.1/krb5_decode_kdc.c [new file with mode: 0644]
src/lib/krb5/asn.1/krb5_decode_macros.h [new file with mode: 0644]

index ec8455ca64aa9c7e1cd1696c76e56b5df8af4b46..43a4bdd7dd0f665d8205cf07ad4e03380f431229 100644 (file)
@@ -11,11 +11,15 @@ EHDRDIR=$(BUILDTOP)/include/krb5/asn.1
 STLIBOBJS= \
        asn1_decode.o\
        asn1_k_decode.o\
+       asn1_k_decode_fast.o\
+       asn1_k_decode_kdc.o\
+       asn1_k_decode_sam.o\
        asn1_encode.o\
        asn1_get.o\
        asn1_make.o\
        asn1buf.o\
        krb5_decode.o\
+       krb5_decode_kdc.o\
        krb5_encode.o\
        asn1_k_encode.o\
        ldap_key_seq.o\
@@ -24,11 +28,15 @@ STLIBOBJS= \
 SRCS= \
        $(srcdir)/asn1_decode.c\
        $(srcdir)/asn1_k_decode.c\
+       $(srcdir)/asn1_k_decode_fast.c\
+       $(srcdir)/asn1_k_decode_kdc.c\
+       $(srcdir)/asn1_k_decode_sam.c\
        $(srcdir)/asn1_encode.c\
        $(srcdir)/asn1_get.c\
        $(srcdir)/asn1_make.c\
        $(srcdir)/asn1buf.c\
        $(srcdir)/krb5_decode.c\
+       $(srcdir)/krb5_decode_kdc.c\
        $(srcdir)/krb5_encode.c\
        $(srcdir)/asn1_k_encode.c\
        $(srcdir)/ldap_key_seq.c\
@@ -37,11 +45,15 @@ SRCS= \
 OBJS= \
        $(OUTPRE)asn1_decode.$(OBJEXT)\
        $(OUTPRE)asn1_k_decode.$(OBJEXT)\
+       $(OUTPRE)asn1_k_decode_fast.$(OBJEXT)\
+       $(OUTPRE)asn1_k_decode_kdc.$(OBJEXT)\
+       $(OUTPRE)asn1_k_decode_sam.$(OBJEXT)\
        $(OUTPRE)asn1_encode.$(OBJEXT)\
        $(OUTPRE)asn1_get.$(OBJEXT)\
        $(OUTPRE)asn1_make.$(OBJEXT)\
        $(OUTPRE)asn1buf.$(OBJEXT)\
        $(OUTPRE)krb5_decode.$(OBJEXT)\
+       $(OUTPRE)krb5_decode_kdc.$(OBJEXT)\
        $(OUTPRE)krb5_encode.$(OBJEXT)\
        $(OUTPRE)asn1_k_encode.$(OBJEXT)\
        $(OUTPRE)ldap_key_seq.$(OBJEXT)\
index c2dd5f6d44943e5b892feb5ea5190d9b56a22b0b..365d18aaf837ac583ca6c7b30ea3b18d075acfaf 100644 (file)
  */
 
 #include "asn1_k_decode.h"
+#include "asn1_k_decode_macros.h"
 #include "asn1_decode.h"
 #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;                     \
-    asn1_class asn1class;                       \
-    asn1_construction construction;             \
-    asn1_tagnum tagnum;                         \
-    unsigned int length, taglen
-
-#define unused_var(x) if (0) { x = 0; x = x - x; }
-
-/* This is used for prefetch of next tag in sequence. */
-#define next_tag()                                                      \
-    { taginfo t2;                                                       \
-        retval = asn1_get_tag_2(&subbuf, &t2);                          \
-        if (retval) clean_return(retval);                               \
-        /* Copy out to match previous functionality, until better integrated.  */ \
-        asn1class = t2.asn1class;                                       \
-        construction = t2.construction;                                 \
-        tagnum = t2.tagnum;                                             \
-        taglen = t2.length;                                             \
-        indef = t2.indef;                                               \
-    }
-
-static asn1_error_code
-asn1_get_eoc_tag (asn1buf *buf)
-{
-    asn1_error_code retval;
-    taginfo t;
-
-    retval = asn1_get_tag_2(buf, &t);
-    if (retval)
-        return retval;
-    if (t.asn1class != UNIVERSAL || t.tagnum || t.indef)
-        return ASN1_MISSING_EOC;
-    return 0;
-}
-
-/* Force check for EOC tag. */
-#define get_eoc()                               \
-    {                                           \
-        retval = asn1_get_eoc_tag(&subbuf);     \
-        if (retval) clean_return(retval);       \
-    }
-
-#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) clean_return(retval);                               \
-        if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED || \
-            t1.tagnum != (tagexpect)) clean_return(ASN1_BAD_ID);        \
-        /* Copy out to match previous functionality, until better integrated.  */ \
-        asn1class = t1.asn1class;                                       \
-        construction = t1.construction;                                 \
-        tagnum = t1.tagnum;                                             \
-        applen = t1.length;                                             \
-    }
-
-/**** normal fields ****/
-
-/*
- * get_field_body
- *
- * Get bare field.  This also prefetches the next tag.  The call to
- * get_eoc() assumes that any values fetched by this macro are
- * enclosed in a context-specific tag.
- */
-#define get_field_body(var, decoder)            \
-    retval = decoder(&subbuf, &(var));          \
-    if (retval) clean_return(retval);           \
-    if (!taglen && indef) { get_eoc(); }        \
-    next_tag()
-
-/*
- * error_if_bad_tag
- *
- * Checks that the next tag is the expected one; returns with an error
- * if not.
- */
-#define error_if_bad_tag(tagexpect)                                     \
-    if (tagnum != (tagexpect)) { clean_return((tagnum < (tagexpect)) ? ASN1_MISPLACED_FIELD : ASN1_MISSING_FIELD); }
-
-/*
- * get_field
- *
- * Get field having an expected context specific tag.  This assumes
- * that context-specific tags are monotonically increasing in its
- * verification of tag numbers.
- */
-#define get_field(var, tagexpect, decoder)                              \
-    error_if_bad_tag(tagexpect);                                        \
-    if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)  \
-        && (tagnum || taglen || asn1class != UNIVERSAL))                \
-        clean_return(ASN1_BAD_ID);                                      \
-    get_field_body(var,decoder)
-
-/*
- * opt_field
- *
- * Get an optional field with an expected context specific tag.
- * Assumes that OPTVAL will have the default value, thus failing to
- * distinguish between absent optional values and present optional
- * values that happen to have the value of OPTVAL.
- */
-#define opt_field(var, tagexpect, decoder, optvalue)                    \
-    if (asn1buf_remains(&subbuf, seqindef)) {                           \
-        if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
-            && (tagnum || taglen || asn1class != UNIVERSAL))            \
-            clean_return(ASN1_BAD_ID);                                  \
-        if (tagnum == (tagexpect)) {                                    \
-            get_field_body(var, decoder);                               \
-        } else var = optvalue;                                          \
-    }
-
-/**** fields w/ length ****/
-
-/* similar to get_field_body */
-#define get_lenfield_body(len, var, decoder)    \
-    retval = decoder(&subbuf, &(len), &(var));  \
-    if (retval) clean_return(retval);           \
-    if (!taglen && indef) { get_eoc(); }        \
-    next_tag()
-
-/* similar to get_field_body */
-#define get_lenfield(len, var, tagexpect, decoder)                      \
-    error_if_bad_tag(tagexpect);                                        \
-    if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)  \
-        && (tagnum || taglen || asn1class != UNIVERSAL))                \
-        clean_return(ASN1_BAD_ID);                                      \
-    get_lenfield_body(len, var, decoder)
-
-/* similar to opt_field */
-#define opt_lenfield(len, var, tagexpect, decoder)      \
-    if (tagnum == (tagexpect)) {                        \
-        get_lenfield_body(len, var, decoder);           \
-    } else { len = 0; var = 0; }
-
-/*
- * Deal with implicitly tagged fields
- */
-#define get_implicit_octet_string(len, var, tagexpect)                  \
-    if (tagnum != (tagexpect)) clean_return(ASN1_MISSING_FIELD);        \
-    if (asn1class != CONTEXT_SPECIFIC || construction != PRIMITIVE)     \
-        clean_return(ASN1_BAD_ID);                                      \
-    retval = asn1buf_remove_octetstring(&subbuf, taglen, &(var));       \
-    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) \
-            clean_return(ASN1_BAD_ID);                                  \
-        retval = asn1buf_remove_octetstring(&subbuf, taglen, &(var));   \
-        if (retval) clean_return(retval);                               \
-        (len) = taglen;                                                 \
-        next_tag();                                                     \
-    } else { (len) = 0; (var) = NULL; }
-
-/*
- * begin_structure
- *
- * Declares some variables for decoding SEQUENCE types.  This is meant
- * to be called in an inner block that ends with a call to
- * end_structure().
- */
-#define begin_structure()                                       \
-    asn1buf subbuf;                                             \
-    int seqindef;                                               \
-    int indef;                                                  \
-    retval = asn1_get_sequence(buf, &length, &seqindef);        \
-    if (retval) clean_return(retval);                           \
-    retval = asn1buf_imbed(&subbuf, buf, length, seqindef);     \
-    if (retval) clean_return(retval);                           \
-    next_tag()
-
-/*
- * This is used for structures which have no tagging.
- * It is the same as begin_structure() except next_tag()
- * is not called.
- */
-#define begin_structure_no_tag()                                \
-    asn1buf subbuf;                                             \
-    int seqindef;                                               \
-    int indef;                                                  \
-    retval = asn1_get_sequence(buf, &length, &seqindef);        \
-    if (retval) clean_return(retval);                           \
-    retval = asn1buf_imbed(&subbuf, buf, length, seqindef);     \
-    if (retval) clean_return(retval)
-
-/* skip trailing garbage */
-#define end_structure()                                         \
-    retval = asn1buf_sync(buf, &subbuf, asn1class, tagnum,      \
-                          length, indef, seqindef);             \
-    if (retval) clean_return(retval)
-
-/*
- * begin_choice
- *
- * Declares some variables for decoding CHOICE types.  This is meant
- * to be called in an inner block that ends with a call to
- * end_choice().
- */
-#define begin_choice()                                          \
-    asn1buf subbuf;                                             \
-    int seqindef;                                               \
-    int indef;                                                  \
-    taginfo t;                                                  \
-    retval = asn1_get_tag_2(buf, &t);                           \
-    if (retval) clean_return(retval);                           \
-    tagnum = t.tagnum;                                          \
-    taglen = t.length;                                          \
-    indef = t.indef;                                            \
-    length = t.length;                                          \
-    seqindef = t.indef;                                         \
-    asn1class = t.asn1class;                                    \
-    construction = t.construction;                              \
-    retval = asn1buf_imbed(&subbuf, buf, length, seqindef);     \
-    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) clean_return(retval)
-
-/*
- * sequence_of
- *
- * Declares some variables for decoding SEQUENCE OF types.  This is
- * meant to be called in an inner block that ends with a call to
- * end_sequence_of().
- */
-#define sequence_of(buf)                        \
-    unsigned int length, taglen;                \
-    asn1_class asn1class;                       \
-    asn1_construction construction;             \
-    asn1_tagnum tagnum;                         \
-    int indef;                                  \
-    sequence_of_common(buf)
-
-/*
- * sequence_of_no_tagvars
- *
- * This is meant for use inside decoder functions that have an outer
- * sequence structure and thus declares variables of different names
- * than does sequence_of() to avoid shadowing.
- */
-#define sequence_of_no_tagvars(buf)             \
-    sequence_of_common(buf)
-
-/*
- * sequence_of_common
- *
- * Fetches the outer SEQUENCE OF length info into {length,seqofindef}
- * and imbeds an inner buffer seqbuf.  Unlike begin_structure(), it
- * does not prefetch the next tag.
- */
-#define sequence_of_common(buf)                                 \
-    asn1buf seqbuf;                                             \
-    int seqofindef;                                             \
-    retval = asn1_get_sequence(buf, &length, &seqofindef);      \
-    if (retval) clean_return(retval);                           \
-    retval = asn1buf_imbed(&seqbuf, buf, length, seqofindef);   \
-    if (retval) clean_return(retval)
-
-/*
- * end_sequence_of
- *
- * Attempts to fetch an EOC tag, if any, and to sync over trailing
- * garbage, if any.
- */
-#define end_sequence_of(buf)                                            \
-    {                                                                   \
-        taginfo t4;                                                     \
-        retval = asn1_get_tag_2(&seqbuf, &t4);                          \
-        if (retval) clean_return(retval);                               \
-        /* Copy out to match previous functionality, until better integrated.  */ \
-        asn1class = t4.asn1class;                                       \
-        construction = t4.construction;                                 \
-        tagnum = t4.tagnum;                                             \
-        taglen = t4.length;                                             \
-        indef = t4.indef;                                               \
-    }                                                                   \
-        retval = asn1buf_sync(buf, &seqbuf, asn1class, tagnum,          \
-                              length, indef, seqofindef);               \
-        if (retval) clean_return(retval);
-
-/*
- * end_sequence_of_no_tagvars
- *
- * Like end_sequence_of(), but uses the different (non-shadowing)
- * variable names.
- */
-static asn1_error_code
-end_sequence_of_no_tagvars_helper(asn1buf *buf, asn1buf *seqbufp,
-                                  int seqofindef)
-{
-    taginfo t;
-    asn1_error_code retval;
-
-    retval = asn1_get_tag_2(seqbufp, &t);
-    if (retval)
-        return retval;
-    retval = asn1buf_sync(buf, seqbufp, t.asn1class, t.tagnum,
-                          t.length, t.indef, seqofindef);
-    return retval;
-}
-#define end_sequence_of_no_tagvars(buf)                                 \
-    retval = end_sequence_of_no_tagvars_helper(buf, &seqbuf, seqofindef); \
-    if (retval) clean_return(retval)
-
-/*
- * 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;
+integer_convert(asn1_decode_int,int)
+integer_convert(asn1_decode_int32,krb5_int32)
+integer_convert(asn1_decode_kvno,krb5_kvno)
+integer_convert(asn1_decode_enctype,krb5_enctype)
+integer_convert(asn1_decode_cksumtype,krb5_cksumtype)
+integer_convert(asn1_decode_octet,krb5_octet)
+integer_convert(asn1_decode_addrtype,krb5_addrtype)
+integer_convert(asn1_decode_authdatatype,krb5_authdatatype)
+unsigned_integer_convert(asn1_decode_ui_2,krb5_ui_2)
+unsigned_integer_convert(asn1_decode_ui_4,krb5_ui_4)
 
 /* scalars */
 asn1_error_code
@@ -405,37 +57,6 @@ asn1_decode_kerberos_time(asn1buf *buf, krb5_timestamp *val)
     return 0;
 }
 
-#define integer_convert(fname,ktype)                    \
-    asn1_error_code fname(asn1buf * buf, ktype * val)   \
-    {                                                   \
-        asn1_error_code retval;                         \
-        long n;                                         \
-        retval = asn1_decode_integer(buf,&n);           \
-        if (retval) return retval;                      \
-        *val = (ktype)n;                                \
-        return 0;                                       \
-    }
-#define unsigned_integer_convert(fname,ktype)           \
-    asn1_error_code fname(asn1buf * buf, ktype * val)   \
-    {                                                   \
-        asn1_error_code retval;                         \
-        unsigned long n;                                \
-        retval = asn1_decode_unsigned_integer(buf,&n);  \
-        if (retval) return retval;                      \
-        *val = (ktype)n;                                \
-        return 0;                                       \
-    }
-integer_convert(asn1_decode_int,int)
-integer_convert(asn1_decode_int32,krb5_int32)
-integer_convert(asn1_decode_kvno,krb5_kvno)
-integer_convert(asn1_decode_enctype,krb5_enctype)
-integer_convert(asn1_decode_cksumtype,krb5_cksumtype)
-integer_convert(asn1_decode_octet,krb5_octet)
-integer_convert(asn1_decode_addrtype,krb5_addrtype)
-integer_convert(asn1_decode_authdatatype,krb5_authdatatype)
-unsigned_integer_convert(asn1_decode_ui_2,krb5_ui_2)
-unsigned_integer_convert(asn1_decode_ui_4,krb5_ui_4)
-
 asn1_error_code
 asn1_decode_seqnum(asn1buf *buf, krb5_ui_4 *val)
 {
@@ -731,99 +352,6 @@ 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) 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;
-    }
-    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_principal(val->client); }
-        opt_field(val->client,1,asn1_decode_principal_name,NULL);
-        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) clean_return(retval); }
-
-        /* If opt_field server is missing, memory reference to server is
-           lost and results in memory leak */
-        psave = val->server;
-        opt_field(val->server,3,asn1_decode_principal_name,NULL);
-        if (val->server == NULL) {
-            if (psave->realm.data) {
-                free(psave->realm.data);
-                psave->realm.data = NULL;
-                psave->realm.length=0;
-            }
-            free(psave);
-        }
-        opt_field(val->from,4,asn1_decode_kerberos_time,0);
-        get_field(val->till,5,asn1_decode_kerberos_time);
-        opt_field(val->rtime,6,asn1_decode_kerberos_time,0);
-        get_field(val->nonce,7,asn1_decode_int32);
-        get_lenfield(val->nktypes,val->ktype,8,asn1_decode_sequence_of_enctype);
-        opt_field(val->addresses,9,asn1_decode_host_addresses,0);
-        if (tagnum == 10) {
-            get_field(val->authorization_data,10,asn1_decode_encrypted_data); }
-        else {
-            val->authorization_data.magic = KV5M_ENC_DATA;
-            val->authorization_data.enctype = 0;
-            val->authorization_data.kvno = 0;
-            val->authorization_data.ciphertext.data = NULL;
-            val->authorization_data.ciphertext.length = 0;
-        }
-        opt_field(val->second_ticket,11,asn1_decode_sequence_of_ticket,NULL);
-        end_structure();
-        val->magic = KV5M_KDC_REQ;
-    }
-    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)
 {
@@ -1428,251 +956,6 @@ asn1_decode_sequence_of_passwdsequence(asn1buf *buf,
     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)
-{
-    return asn1_decode_krb5_flags(buf,val);
-}
-
-#define opt_string(val,n,fn) opt_lenfield((val).length,(val).data,n,fn)
-#define opt_cksum(var,tagexpect,decoder)        \
-    if (tagnum == (tagexpect)) {                \
-        get_field_body(var,decoder); }          \
-    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);
-        opt_string(val->sam_type_name,2,asn1_decode_charstring);
-        opt_string(val->sam_track_id,3,asn1_decode_charstring);
-        opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
-        opt_string(val->sam_challenge,5,asn1_decode_charstring);
-        opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
-        opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
-        opt_field(val->sam_nonce,8,asn1_decode_int32,0);
-        opt_cksum(val->sam_cksum,9,asn1_decode_checksum);
-        end_structure();
-        val->magic = KV5M_SAM_CHALLENGE;
-    }
-    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) clean_return(ASN1_MISSING_FIELD);
-        if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
-            clean_return(ASN1_BAD_ID);
-        save = subbuf.next;
-        { sequence_of_no_tagvars(&subbuf);
-            end_sequence_of_no_tagvars(&subbuf);
-        }
-        end = subbuf.next;
-        alloclen = end - save;
-        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();
-    }
-    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);
-        opt_string(val->sam_type_name,2,asn1_decode_charstring);
-        opt_string(val->sam_track_id,3,asn1_decode_charstring);
-        opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
-        opt_string(val->sam_challenge,5,asn1_decode_charstring);
-        opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
-        opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
-        get_field(val->sam_nonce,8,asn1_decode_int32);
-        get_field(val->sam_etype, 9, asn1_decode_int32);
-        end_structure();
-        val->magic = KV5M_SAM_CHALLENGE;
-    }
-    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();
-        get_field(val->sam_key,0,asn1_decode_encryption_key);
-        end_structure();
-        val->magic = KV5M_SAM_KEY;
-    }
-    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);
-        opt_field(val->sam_usec,2,asn1_decode_int32,0);
-        opt_string(val->sam_sad,3,asn1_decode_charstring);
-        end_structure();
-        val->magic = KV5M_ENC_SAM_RESPONSE_ENC;
-    }
-    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;
-    }
-    return 0;
-error_out:
-    krb5_free_enc_sam_response_enc_2_contents(NULL, val);
-    return retval;
-}
-
-#define opt_encfield(fld,tag,fn)                \
-    if (tagnum == tag) {                        \
-        get_field(fld,tag,fn); }                \
-    else {                                      \
-        fld.magic = 0;                          \
-        fld.enctype = 0;                        \
-        fld.kvno = 0;                           \
-        fld.ciphertext.data = NULL;             \
-        fld.ciphertext.length = 0;              \
-    }
-
-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);
-        opt_string(val->sam_track_id,2,asn1_decode_charstring);
-        opt_encfield(val->sam_enc_key,3,asn1_decode_encrypted_data);
-        get_field(val->sam_enc_nonce_or_ts,4,asn1_decode_encrypted_data);
-        opt_field(val->sam_nonce,5,asn1_decode_int32,0);
-        opt_field(val->sam_patimestamp,6,asn1_decode_kerberos_time,0);
-        end_structure();
-        val->magic = KV5M_SAM_RESPONSE;
-    }
-    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);
-        opt_string(val->sam_track_id,2,asn1_decode_charstring);
-        get_field(val->sam_enc_nonce_or_sad,3,asn1_decode_encrypted_data);
-        get_field(val->sam_nonce,4,asn1_decode_int32);
-        end_structure();
-        val->magic = KV5M_SAM_RESPONSE;
-    }
-    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_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;
-    }
-    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)
@@ -1779,56 +1062,6 @@ error_out:
     return retval;
 }
 
-asn1_error_code
-asn1_decode_fast_armor(asn1buf *buf, krb5_fast_armor *val)
-{
-    setup();
-    val->armor_value.data = NULL;
-    {begin_structure();
-        get_field(val->armor_type, 0, asn1_decode_int32);
-        get_lenfield(val->armor_value.length, val->armor_value.data,
-                     1, asn1_decode_charstring);
-        end_structure();
-    }
-    return 0;
-error_out:
-    krb5_free_data_contents( NULL, &val->armor_value);
-    return retval;
-}
-
-asn1_error_code
-asn1_decode_fast_armor_ptr(asn1buf *buf, krb5_fast_armor **valptr)
-{
-    decode_ptr(krb5_fast_armor *, asn1_decode_fast_armor);
-}
-
-asn1_error_code
-asn1_decode_fast_finished(asn1buf *buf, krb5_fast_finished *val)
-{
-    setup();
-    val->client = NULL;
-    val->ticket_checksum.contents = NULL;
-    {begin_structure();
-        get_field(val->timestamp, 0, asn1_decode_kerberos_time);
-        get_field(val->usec, 1, asn1_decode_int32);
-        alloc_field(val->client);
-        get_field(val->client, 2, asn1_decode_realm);
-        get_field(val->client, 3, asn1_decode_principal_name);
-        get_field(val->ticket_checksum, 4, asn1_decode_checksum);
-        end_structure();
-    }
-    return 0;
-error_out:
-    krb5_free_principal(NULL, val->client);
-    krb5_free_checksum_contents( NULL, &val->ticket_checksum);
-    return retval;
-}
-asn1_error_code
-asn1_decode_fast_finished_ptr(asn1buf *buf, krb5_fast_finished **valptr)
-{
-    decode_ptr( krb5_fast_finished *, asn1_decode_fast_finished);
-}
-
 asn1_error_code
 asn1_decode_ad_kdcissued(asn1buf *buf, krb5_ad_kdcissued *val)
 {
@@ -1999,31 +1232,6 @@ asn1_decode_sequence_of_external_principal_identifier(
                       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);
-        opt_field(val->trustedCertifiers, 1, asn1_decode_sequence_of_external_principal_identifier, NULL);
-        opt_implicit_octet_string(val->kdcPkId.length, val->kdcPkId.data, 2);
-        end_structure();
-    }
-    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)
@@ -2115,7 +1323,7 @@ error_out:
     val->choice = choice_trusted_cas_UNKNOWN;
     return retval;
 }
-#endif
+#endif /* if 0 */
 
 asn1_error_code
 asn1_decode_trusted_ca_ptr(asn1buf *buf, krb5_trusted_ca **valptr)
@@ -2140,39 +1348,6 @@ asn1_decode_sequence_of_trusted_ca(asn1buf *buf, krb5_trusted_ca ***val)
                       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);
-        opt_lenfield(val->kdcCert.length, val->kdcCert.data, 2, asn1_decode_octetstring);
-        opt_lenfield(val->encryptionCert.length, val->encryptionCert.data, 2, asn1_decode_octetstring);
-        end_structure();
-    }
-    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)
 {
@@ -2442,113 +1617,6 @@ error_out:
     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);
-            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))
-                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;
-        }
-        /* can't call opt_field because it does decoder(&subbuf, &(val)); */
-        if (asn1buf_remains(&subbuf, seqindef)) {
-            if (tagnum == 2) {
-                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;
-        }
-        opt_lenfield(val->clientDHNonce.length, val->clientDHNonce.data, 3, asn1_decode_octetstring);
-        end_structure();
-    }
-    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);
-            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))
-                    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;
-            }
-        }
-        end_structure();
-    }
-    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)
 {
diff --git a/src/lib/krb5/asn.1/asn1_k_decode_fast.c b/src/lib/krb5/asn.1/asn1_k_decode_fast.c
new file mode 100644 (file)
index 0000000..8007371
--- /dev/null
@@ -0,0 +1,80 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/asn1_k_decode_fast.c
+ *
+ * Copyright 1994, 2007, 2008, 2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "asn1_k_decode_macros.h"
+
+asn1_error_code
+asn1_decode_fast_armor(asn1buf *buf, krb5_fast_armor *val)
+{
+    setup();
+    val->armor_value.data = NULL;
+    {begin_structure();
+        get_field(val->armor_type, 0, asn1_decode_int32);
+        get_lenfield(val->armor_value.length, val->armor_value.data,
+                     1, asn1_decode_charstring);
+        end_structure();
+    }
+    return 0;
+error_out:
+    krb5_free_data_contents( NULL, &val->armor_value);
+    return retval;
+}
+
+asn1_error_code
+asn1_decode_fast_armor_ptr(asn1buf *buf, krb5_fast_armor **valptr)
+{
+    decode_ptr(krb5_fast_armor *, asn1_decode_fast_armor);
+}
+
+asn1_error_code
+asn1_decode_fast_finished(asn1buf *buf, krb5_fast_finished *val)
+{
+    setup();
+    val->client = NULL;
+    val->ticket_checksum.contents = NULL;
+    {begin_structure();
+        get_field(val->timestamp, 0, asn1_decode_kerberos_time);
+        get_field(val->usec, 1, asn1_decode_int32);
+        alloc_field(val->client);
+        get_field(val->client, 2, asn1_decode_realm);
+        get_field(val->client, 3, asn1_decode_principal_name);
+        get_field(val->ticket_checksum, 4, asn1_decode_checksum);
+        end_structure();
+    }
+    return 0;
+error_out:
+    krb5_free_principal(NULL, val->client);
+    krb5_free_checksum_contents( NULL, &val->ticket_checksum);
+    return retval;
+}
+
+asn1_error_code
+asn1_decode_fast_finished_ptr(asn1buf *buf, krb5_fast_finished **valptr)
+{
+    decode_ptr( krb5_fast_finished *, asn1_decode_fast_finished);
+}
+
diff --git a/src/lib/krb5/asn.1/asn1_k_decode_kdc.c b/src/lib/krb5/asn.1/asn1_k_decode_kdc.c
new file mode 100644 (file)
index 0000000..d8499bb
--- /dev/null
@@ -0,0 +1,309 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/asn1_k_decode_kdc.c
+ *
+ * Copyright 1994, 2007, 2008, 2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "asn1_k_decode_macros.h"
+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) 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;
+    }
+    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_principal(val->client); }
+        opt_field(val->client,1,asn1_decode_principal_name,NULL);
+        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) clean_return(retval); }
+
+        /* If opt_field server is missing, memory reference to server is
+         * lost and results in memory leak
+         */
+        psave = val->server;
+        opt_field(val->server,3,asn1_decode_principal_name,NULL);
+        if (val->server == NULL) {
+            if (psave->realm.data) {
+                free(psave->realm.data);
+                psave->realm.data = NULL;
+                psave->realm.length=0;
+            }
+            free(psave);
+        }
+        opt_field(val->from,4,asn1_decode_kerberos_time,0);
+        get_field(val->till,5,asn1_decode_kerberos_time);
+        opt_field(val->rtime,6,asn1_decode_kerberos_time,0);
+        get_field(val->nonce,7,asn1_decode_int32);
+        get_lenfield(val->nktypes,val->ktype,8,asn1_decode_sequence_of_enctype);
+        opt_field(val->addresses,9,asn1_decode_host_addresses,0);
+        if (tagnum == 10) {
+            get_field(val->authorization_data,10,asn1_decode_encrypted_data); }
+        else {
+            val->authorization_data.magic = KV5M_ENC_DATA;
+            val->authorization_data.enctype = 0;
+            val->authorization_data.kvno = 0;
+            val->authorization_data.ciphertext.data = NULL;
+            val->authorization_data.ciphertext.length = 0;
+        }
+        opt_field(val->second_ticket,11,asn1_decode_sequence_of_ticket,NULL);
+        end_structure();
+        val->magic = KV5M_KDC_REQ;
+    }
+    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;
+}
+
+#ifndef DISABLE_PKINIT
+/* PKINIT */
+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);
+        opt_field(val->trustedCertifiers, 1, asn1_decode_sequence_of_external_principal_identifier, NULL);
+        opt_implicit_octet_string(val->kdcPkId.length, val->kdcPkId.data, 2);
+        end_structure();
+    }
+    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;
+}
+
+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_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);
+        opt_lenfield(val->kdcCert.length, val->kdcCert.data, 2, asn1_decode_octetstring);
+        opt_lenfield(val->encryptionCert.length, val->encryptionCert.data, 2, asn1_decode_octetstring);
+        end_structure();
+    }
+    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;
+}
+
+static void
+free_algorithm_identifier(krb5_algorithm_identifier *val)
+{
+    free(val->algorithm.data);
+    free(val->parameters.data);
+    free(val);
+}
+
+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);
+            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))
+                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;
+        }
+        /* can't call opt_field because it does decoder(&subbuf, &(val)); */
+        if (asn1buf_remains(&subbuf, seqindef)) {
+            if (tagnum == 2) {
+                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;
+        }
+        opt_lenfield(val->clientDHNonce.length, val->clientDHNonce.data, 3, asn1_decode_octetstring);
+        end_structure();
+    }
+    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(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);
+            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))
+                    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;
+            }
+        }
+        end_structure();
+    }
+    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;
+}
+
+#endif /* DISABLE_PKINIT */
diff --git a/src/lib/krb5/asn.1/asn1_k_decode_macros.h b/src/lib/krb5/asn.1/asn1_k_decode_macros.h
new file mode 100644 (file)
index 0000000..24580af
--- /dev/null
@@ -0,0 +1,415 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/asn1_k_decode_macros.h
+ *
+ * Copyright 1994, 2007, 2008, 2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef ASN1_DECODE_KRB5_MACROS_H
+#define ASN1_DECODE_KRB5_MACROS_H
+
+#include "asn1_k_decode.h"
+#include "asn1_decode.h"
+#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;                     \
+    asn1_class asn1class;                       \
+    asn1_construction construction;             \
+    asn1_tagnum tagnum;                         \
+    unsigned int length, taglen
+
+#define unused_var(x) if (0) { x = 0; x = x - x; }
+
+/* This is used for prefetch of next tag in sequence. */
+#define next_tag()                                                      \
+    { taginfo t2;                                                       \
+        retval = asn1_get_tag_2(&subbuf, &t2);                          \
+        if (retval) clean_return(retval);                               \
+        /* Copy out to match previous functionality, until better integrated.  */ \
+        asn1class = t2.asn1class;                                       \
+        construction = t2.construction;                                 \
+        tagnum = t2.tagnum;                                             \
+        taglen = t2.length;                                             \
+        indef = t2.indef;                                               \
+    }
+
+static asn1_error_code
+asn1_get_eoc_tag (asn1buf *buf)
+{
+    asn1_error_code retval;
+    taginfo t;
+
+    retval = asn1_get_tag_2(buf, &t);
+    if (retval)
+        return retval;
+    if (t.asn1class != UNIVERSAL || t.tagnum || t.indef)
+        return ASN1_MISSING_EOC;
+    return 0;
+}
+
+/* Force check for EOC tag. */
+#define get_eoc()                               \
+    {                                           \
+        retval = asn1_get_eoc_tag(&subbuf);     \
+        if (retval) clean_return(retval);       \
+    }
+
+#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) clean_return(retval);                               \
+        if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED || \
+            t1.tagnum != (tagexpect)) clean_return(ASN1_BAD_ID);        \
+        /* Copy out to match previous functionality, until better integrated.  */ \
+        asn1class = t1.asn1class;                                       \
+        construction = t1.construction;                                 \
+        tagnum = t1.tagnum;                                             \
+        applen = t1.length;                                             \
+    }
+
+/**** normal fields ****/
+
+/*
+ * get_field_body
+ *
+ * Get bare field.  This also prefetches the next tag.  The call to
+ * get_eoc() assumes that any values fetched by this macro are
+ * enclosed in a context-specific tag.
+ */
+#define get_field_body(var, decoder)            \
+    retval = decoder(&subbuf, &(var));          \
+    if (retval) clean_return(retval);           \
+    if (!taglen && indef) { get_eoc(); }        \
+    next_tag()
+
+/*
+ * error_if_bad_tag
+ *
+ * Checks that the next tag is the expected one; returns with an error
+ * if not.
+ */
+#define error_if_bad_tag(tagexpect)                                     \
+    if (tagnum != (tagexpect)) { clean_return((tagnum < (tagexpect)) ? ASN1_MISPLACED_FIELD : ASN1_MISSING_FIELD); }
+
+/*
+ * get_field
+ *
+ * Get field having an expected context specific tag.  This assumes
+ * that context-specific tags are monotonically increasing in its
+ * verification of tag numbers.
+ */
+#define get_field(var, tagexpect, decoder)                              \
+    error_if_bad_tag(tagexpect);                                        \
+    if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)  \
+        && (tagnum || taglen || asn1class != UNIVERSAL))                \
+        clean_return(ASN1_BAD_ID);                                      \
+    get_field_body(var,decoder)
+
+/*
+ * opt_field
+ *
+ * Get an optional field with an expected context specific tag.
+ * Assumes that OPTVAL will have the default value, thus failing to
+ * distinguish between absent optional values and present optional
+ * values that happen to have the value of OPTVAL.
+ */
+#define opt_field(var, tagexpect, decoder, optvalue)                    \
+    if (asn1buf_remains(&subbuf, seqindef)) {                           \
+        if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+            && (tagnum || taglen || asn1class != UNIVERSAL))            \
+            clean_return(ASN1_BAD_ID);                                  \
+        if (tagnum == (tagexpect)) {                                    \
+            get_field_body(var, decoder);                               \
+        } else var = optvalue;                                          \
+    }
+
+/**** fields w/ length ****/
+
+/* similar to get_field_body */
+#define get_lenfield_body(len, var, decoder)    \
+    retval = decoder(&subbuf, &(len), &(var));  \
+    if (retval) clean_return(retval);           \
+    if (!taglen && indef) { get_eoc(); }        \
+    next_tag()
+
+/* similar to get_field_body */
+#define get_lenfield(len, var, tagexpect, decoder)                      \
+    error_if_bad_tag(tagexpect);                                        \
+    if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)  \
+        && (tagnum || taglen || asn1class != UNIVERSAL))                \
+        clean_return(ASN1_BAD_ID);                                      \
+    get_lenfield_body(len, var, decoder)
+
+/* similar to opt_field */
+#define opt_lenfield(len, var, tagexpect, decoder)      \
+    if (tagnum == (tagexpect)) {                        \
+        get_lenfield_body(len, var, decoder);           \
+    } else { len = 0; var = 0; }
+
+/*
+ * Deal with implicitly tagged fields
+ */
+#define get_implicit_octet_string(len, var, tagexpect)                  \
+    if (tagnum != (tagexpect)) clean_return(ASN1_MISSING_FIELD);        \
+    if (asn1class != CONTEXT_SPECIFIC || construction != PRIMITIVE)     \
+        clean_return(ASN1_BAD_ID);                                      \
+    retval = asn1buf_remove_octetstring(&subbuf, taglen, &(var));       \
+    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) \
+            clean_return(ASN1_BAD_ID);                                  \
+        retval = asn1buf_remove_octetstring(&subbuf, taglen, &(var));   \
+        if (retval) clean_return(retval);                               \
+        (len) = taglen;                                                 \
+        next_tag();                                                     \
+    } else { (len) = 0; (var) = NULL; }
+
+/*
+ * begin_structure
+ *
+ * Declares some variables for decoding SEQUENCE types.  This is meant
+ * to be called in an inner block that ends with a call to
+ * end_structure().
+ */
+#define begin_structure()                                       \
+    asn1buf subbuf;                                             \
+    int seqindef;                                               \
+    int indef;                                                  \
+    retval = asn1_get_sequence(buf, &length, &seqindef);        \
+    if (retval) clean_return(retval);                           \
+    retval = asn1buf_imbed(&subbuf, buf, length, seqindef);     \
+    if (retval) clean_return(retval);                           \
+    next_tag()
+
+/*
+ * This is used for structures which have no tagging.
+ * It is the same as begin_structure() except next_tag()
+ * is not called.
+ */
+#define begin_structure_no_tag()                                \
+    asn1buf subbuf;                                             \
+    int seqindef;                                               \
+    int indef;                                                  \
+    retval = asn1_get_sequence(buf, &length, &seqindef);        \
+    if (retval) clean_return(retval);                           \
+    retval = asn1buf_imbed(&subbuf, buf, length, seqindef);     \
+    if (retval) clean_return(retval)
+
+/* skip trailing garbage */
+#define end_structure()                                         \
+    retval = asn1buf_sync(buf, &subbuf, asn1class, tagnum,      \
+                          length, indef, seqindef);             \
+    if (retval) clean_return(retval)
+
+/*
+ * begin_choice
+ *
+ * Declares some variables for decoding CHOICE types.  This is meant
+ * to be called in an inner block that ends with a call to
+ * end_choice().
+ */
+#define begin_choice()                                          \
+    asn1buf subbuf;                                             \
+    int seqindef;                                               \
+    int indef;                                                  \
+    taginfo t;                                                  \
+    retval = asn1_get_tag_2(buf, &t);                           \
+    if (retval) clean_return(retval);                           \
+    tagnum = t.tagnum;                                          \
+    taglen = t.length;                                          \
+    indef = t.indef;                                            \
+    length = t.length;                                          \
+    seqindef = t.indef;                                         \
+    asn1class = t.asn1class;                                    \
+    construction = t.construction;                              \
+    retval = asn1buf_imbed(&subbuf, buf, length, seqindef);     \
+    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) clean_return(retval)
+
+/*
+ * sequence_of
+ *
+ * Declares some variables for decoding SEQUENCE OF types.  This is
+ * meant to be called in an inner block that ends with a call to
+ * end_sequence_of().
+ */
+#define sequence_of(buf)                        \
+    unsigned int length, taglen;                \
+    asn1_class asn1class;                       \
+    asn1_construction construction;             \
+    asn1_tagnum tagnum;                         \
+    int indef;                                  \
+    sequence_of_common(buf)
+
+/*
+ * sequence_of_no_tagvars
+ *
+ * This is meant for use inside decoder functions that have an outer
+ * sequence structure and thus declares variables of different names
+ * than does sequence_of() to avoid shadowing.
+ */
+#define sequence_of_no_tagvars(buf)             \
+    sequence_of_common(buf)
+
+/*
+ * sequence_of_common
+ *
+ * Fetches the outer SEQUENCE OF length info into {length,seqofindef}
+ * and imbeds an inner buffer seqbuf.  Unlike begin_structure(), it
+ * does not prefetch the next tag.
+ */
+#define sequence_of_common(buf)                                 \
+    asn1buf seqbuf;                                             \
+    int seqofindef;                                             \
+    retval = asn1_get_sequence(buf, &length, &seqofindef);      \
+    if (retval) clean_return(retval);                           \
+    retval = asn1buf_imbed(&seqbuf, buf, length, seqofindef);   \
+    if (retval) clean_return(retval)
+
+/*
+ * end_sequence_of
+ *
+ * Attempts to fetch an EOC tag, if any, and to sync over trailing
+ * garbage, if any.
+ */
+#define end_sequence_of(buf)                                            \
+    {                                                                   \
+        taginfo t4;                                                     \
+        retval = asn1_get_tag_2(&seqbuf, &t4);                          \
+        if (retval) clean_return(retval);                               \
+        /* Copy out to match previous functionality, until better integrated.  */ \
+        asn1class = t4.asn1class;                                       \
+        construction = t4.construction;                                 \
+        tagnum = t4.tagnum;                                             \
+        taglen = t4.length;                                             \
+        indef = t4.indef;                                               \
+    }                                                                   \
+        retval = asn1buf_sync(buf, &seqbuf, asn1class, tagnum,          \
+                              length, indef, seqofindef);               \
+        if (retval) clean_return(retval);
+
+/*
+ * end_sequence_of_no_tagvars
+ *
+ * Like end_sequence_of(), but uses the different (non-shadowing)
+ * variable names.
+ */
+static asn1_error_code
+end_sequence_of_no_tagvars_helper(asn1buf *buf, asn1buf *seqbufp,
+                                  int seqofindef)
+{
+    taginfo t;
+    asn1_error_code retval;
+
+    retval = asn1_get_tag_2(seqbufp, &t);
+    if (retval)
+        return retval;
+    retval = asn1buf_sync(buf, seqbufp, t.asn1class, t.tagnum,
+                          t.length, t.indef, seqofindef);
+    return retval;
+}
+#define end_sequence_of_no_tagvars(buf)                                 \
+    retval = end_sequence_of_no_tagvars_helper(buf, &seqbuf, seqofindef); \
+    if (retval) clean_return(retval)
+
+/*
+ * 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;
+#define integer_convert(fname,ktype)                    \
+    asn1_error_code fname(asn1buf * buf, ktype * val)   \
+    {                                                   \
+        asn1_error_code retval;                         \
+        long n;                                         \
+        retval = asn1_decode_integer(buf,&n);           \
+        if (retval) return retval;                      \
+        *val = (ktype)n;                                \
+        return 0;                                       \
+    }
+#define unsigned_integer_convert(fname,ktype)           \
+    asn1_error_code fname(asn1buf * buf, ktype * val)   \
+    {                                                   \
+        asn1_error_code retval;                         \
+        unsigned long n;                                \
+        retval = asn1_decode_unsigned_integer(buf,&n);  \
+        if (retval) return retval;                      \
+        *val = (ktype)n;                                \
+        return 0;                                       \
+    }
+#endif
diff --git a/src/lib/krb5/asn.1/asn1_k_decode_sam.c b/src/lib/krb5/asn.1/asn1_k_decode_sam.c
new file mode 100644 (file)
index 0000000..083e543
--- /dev/null
@@ -0,0 +1,274 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/asn1_k_decode_sam.c
+ *
+ * Copyright 1994, 2007, 2008, 2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "asn1_k_decode_macros.h"
+
+asn1_error_code
+asn1_decode_sam_flags(asn1buf *buf, krb5_flags *val)
+{
+    return asn1_decode_krb5_flags(buf,val);
+}
+
+#define opt_string(val,n,fn) opt_lenfield((val).length,(val).data,n,fn)
+#define opt_cksum(var,tagexpect,decoder)        \
+    if (tagnum == (tagexpect)) {                \
+        get_field_body(var,decoder); }          \
+    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);
+        opt_string(val->sam_type_name,2,asn1_decode_charstring);
+        opt_string(val->sam_track_id,3,asn1_decode_charstring);
+        opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
+        opt_string(val->sam_challenge,5,asn1_decode_charstring);
+        opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
+        opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
+        opt_field(val->sam_nonce,8,asn1_decode_int32,0);
+        opt_cksum(val->sam_cksum,9,asn1_decode_checksum);
+        end_structure();
+        val->magic = KV5M_SAM_CHALLENGE;
+    }
+    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) clean_return(ASN1_MISSING_FIELD);
+        if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
+            clean_return(ASN1_BAD_ID);
+        save = subbuf.next;
+        { sequence_of_no_tagvars(&subbuf);
+            end_sequence_of_no_tagvars(&subbuf);
+        }
+        end = subbuf.next;
+        alloclen = end - save;
+        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();
+    }
+    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);
+        opt_string(val->sam_type_name,2,asn1_decode_charstring);
+        opt_string(val->sam_track_id,3,asn1_decode_charstring);
+        opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
+        opt_string(val->sam_challenge,5,asn1_decode_charstring);
+        opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
+        opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
+        get_field(val->sam_nonce,8,asn1_decode_int32);
+        get_field(val->sam_etype, 9, asn1_decode_int32);
+        end_structure();
+        val->magic = KV5M_SAM_CHALLENGE;
+    }
+    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();
+        get_field(val->sam_key,0,asn1_decode_encryption_key);
+        end_structure();
+        val->magic = KV5M_SAM_KEY;
+    }
+    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);
+        opt_field(val->sam_usec,2,asn1_decode_int32,0);
+        opt_string(val->sam_sad,3,asn1_decode_charstring);
+        end_structure();
+        val->magic = KV5M_ENC_SAM_RESPONSE_ENC;
+    }
+    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;
+    }
+    return 0;
+error_out:
+    krb5_free_enc_sam_response_enc_2_contents(NULL, val);
+    return retval;
+}
+
+#define opt_encfield(fld,tag,fn)                \
+    if (tagnum == tag) {                        \
+        get_field(fld,tag,fn); }                \
+    else {                                      \
+        fld.magic = 0;                          \
+        fld.enctype = 0;                        \
+        fld.kvno = 0;                           \
+        fld.ciphertext.data = NULL;             \
+        fld.ciphertext.length = 0;              \
+    }
+
+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);
+        opt_string(val->sam_track_id,2,asn1_decode_charstring);
+        opt_encfield(val->sam_enc_key,3,asn1_decode_encrypted_data);
+        get_field(val->sam_enc_nonce_or_ts,4,asn1_decode_encrypted_data);
+        opt_field(val->sam_nonce,5,asn1_decode_int32,0);
+        opt_field(val->sam_patimestamp,6,asn1_decode_kerberos_time,0);
+        end_structure();
+        val->magic = KV5M_SAM_RESPONSE;
+    }
+    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);
+        opt_string(val->sam_track_id,2,asn1_decode_charstring);
+        get_field(val->sam_enc_nonce_or_sad,3,asn1_decode_encrypted_data);
+        get_field(val->sam_nonce,4,asn1_decode_int32);
+        end_structure();
+        val->magic = KV5M_SAM_RESPONSE;
+    }
+    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_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;
+    }
+    return 0;
+error_out:
+    krb5_free_predicted_sam_response_contents(NULL, val);
+    return retval;
+}
+
index d000c39e51df667409caa03f5074dca2305b77a2..8b90f77960f93e9da2d29b1993fee003934077a7 100644 (file)
@@ -26,6 +26,45 @@ asn1_k_decode.so asn1_k_decode.po $(OUTPRE)asn1_k_decode.$(OBJEXT): \
   $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
   asn1_decode.h asn1_get.h asn1_k_decode.c asn1_k_decode.h \
   asn1_misc.h asn1buf.h krbasn1.h
+asn1_k_decode_fast.so asn1_k_decode_fast.po $(OUTPRE)asn1_k_decode_fast.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
+  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \
+  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+  asn1_decode.h asn1_get.h asn1_k_decode_fast.c asn1_k_decode.h \
+  asn1_misc.h asn1buf.h krbasn1.h
+asn1_k_decode_kdc.so asn1_k_decode_kdc.po $(OUTPRE)asn1_k_decode_kdc.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
+  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \
+  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+  asn1_decode.h asn1_get.h asn1_k_decode_kdc.c asn1_k_decode.h \
+  asn1_misc.h asn1buf.h krbasn1.h
+asn1_k_decode_sam.so asn1_k_decode_sam.po $(OUTPRE)asn1_k_decode_sam.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
+  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \
+  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+  asn1_decode.h asn1_get.h asn1_k_decode_sam.c asn1_k_decode.h \
+  asn1_misc.h asn1buf.h krbasn1.h
 asn1_encode.so asn1_encode.po $(OUTPRE)asn1_encode.$(OBJEXT): \
   $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
   $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
index af5c659286e248cc8c104bf1602bd55a01fc9e2e..0fa8e04341bb08408de3968a9b29d435ba050ba2 100644 (file)
 #include "asn1_k_decode.h"
 #include "asn1_decode.h"
 #include "asn1_get.h"
-
-/* setup *********************************************************/
-/* 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(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(type)                   \
-    asn1_class asn1class;                       \
-    asn1_construction construction;             \
-    setup_buf_only(type)
-
-#define setup_no_length(type)                   \
-    asn1_tagnum tagnum;                         \
-    setup_no_tagnum(type)
-
-#define setup(type)                             \
-    unsigned int 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)                        \
-    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)                                         \
-    {                                                                   \
-        taginfo t1;                                                     \
-        retval = asn1_get_tag_2(&buf, &t1);                             \
-        if (retval) clean_return (retval);                              \
-        if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED) \
-            clean_return(ASN1_BAD_ID);                                  \
-        if (t1.tagnum != (tagexpect)) clean_return(KRB5_BADMSGTYPE);    \
-        asn1class = t1.asn1class;                                       \
-        construction = t1.construction;                                 \
-        tagnum = t1.tagnum;                                             \
-    }
-
-
-
-/* process a structure *******************************************/
-
-/* decode an explicit tag and place the number in tagnum */
-#define next_tag_from_buf(buf)                  \
-    { taginfo t2;                               \
-        retval = asn1_get_tag_2(&(buf), &t2);   \
-        if (retval) clean_return(retval);       \
-        asn1class = t2.asn1class;               \
-        construction = t2.construction;         \
-        tagnum = t2.tagnum;                     \
-        indef = t2.indef;                       \
-        taglen = t2.length;                     \
-    }
-#define next_tag() next_tag_from_buf(subbuf)
-
-
-static asn1_error_code
-asn1_get_eoc_tag (asn1buf *buf)
-{
-    asn1_error_code retval;
-    taginfo t;
-
-    retval = asn1_get_tag_2(buf, &t);
-    if (retval)
-        return retval;
-    if (t.asn1class != UNIVERSAL || t.tagnum || t.indef)
-        return ASN1_MISSING_EOC;
-    return 0;
-}
-
-#define get_eoc()                               \
-    {                                           \
-        retval = asn1_get_eoc_tag(&subbuf);     \
-        if (retval) clean_return(retval);       \
-    }
-
-/* decode sequence header and initialize tagnum with the first field */
-#define begin_structure()                                       \
-    unsigned int taglen;                                        \
-    asn1buf subbuf;                                             \
-    int seqindef;                                               \
-    int indef;                                                  \
-    retval = asn1_get_sequence(&buf,&length,&seqindef);         \
-    if (retval) clean_return(retval);                           \
-    retval = asn1buf_imbed(&subbuf,&buf,length,seqindef);       \
-    if (retval) clean_return(retval);                           \
-    next_tag()
-
-#define end_structure()                                         \
-    retval = asn1buf_sync(&buf,&subbuf,asn1class,               \
-                          tagnum,length,indef,seqindef);        \
-    if (retval) clean_return(retval)
-
-/* process fields *******************************************/
-/* normal fields ************************/
-#define get_field_body(var,decoder)             \
-    retval = decoder(&subbuf,&(var));           \
-    if (retval) clean_return(retval);           \
-    if (indef) { get_eoc(); }                   \
-    next_tag()
-
-/*
- * error_if_bad_tag
- *
- * Checks that the next tag is the expected one; returns with an error
- * if not.
- */
-#define error_if_bad_tag(tagexpect)                                     \
-    if (tagnum != (tagexpect)) { clean_return ((tagnum < (tagexpect)) ? ASN1_MISPLACED_FIELD : ASN1_MISSING_FIELD); }
-
-/*
- * decode a field (<[UNIVERSAL id]> <length> <contents>)
- *  check that the id number == tagexpect then
- *  decode into var
- *  get the next tag
- */
-#define get_field(var,tagexpect,decoder)                                \
-    error_if_bad_tag(tagexpect);                                        \
-    if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)   \
-        clean_return(ASN1_BAD_ID);                                      \
-    get_field_body(var,decoder)
-
-/* decode (or skip, if not present) an optional field */
-#define opt_field(var,tagexpect,decoder)                                \
-    if (asn1buf_remains(&subbuf, seqindef)) {                           \
-        if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
-            clean_return(ASN1_BAD_ID);                                  \
-        if (tagnum == (tagexpect)) {                                    \
-            get_field_body(var,decoder);                                \
-        }                                                               \
-    }
-
-/* field w/ accompanying length *********/
-#define get_lenfield_body(len,var,decoder)      \
-    retval = decoder(&subbuf,&(len),&(var));    \
-    if (retval) clean_return(retval);           \
-    if (indef) { get_eoc(); }                   \
-    next_tag()
-
-/* decode a field w/ its length (for string types) */
-#define get_lenfield(len,var,tagexpect,decoder)                         \
-    error_if_bad_tag(tagexpect);                                        \
-    if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)   \
-        clean_return(ASN1_BAD_ID);                                      \
-    get_lenfield_body(len,var,decoder)
-
-/* decode an optional field w/ length */
-#define opt_lenfield(len,var,tagexpect,decoder)                         \
-    if (asn1buf_remains(&subbuf, seqindef)) {                           \
-        if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
-            clean_return(ASN1_BAD_ID);                                  \
-        if (tagnum == (tagexpect)) {                                    \
-            get_lenfield_body(len,var,decoder);                         \
-        }                                                               \
-    }
-
-
-/* clean up ******************************************************/
-/* 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)                                        \
-    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
+#include "krb5_decode_macros.h"
 
 #ifndef LEAN_CLIENT
 krb5_error_code
@@ -511,74 +309,6 @@ error_out:
     return retval;
 }
 
-krb5_error_code
-decode_krb5_as_req(const krb5_data *code, krb5_kdc_req **repptr)
-{
-    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);
-    clear_field(rep, kdc_state);
-
-    check_apptag(10);
-    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);
-#endif
-
-    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 **repptr)
-{
-    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);
-    clear_field(rep, kdc_state);
-
-    check_apptag(12);
-    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);
-#endif
-
-    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 **repptr)
-{
-    setup_buf_only(krb5_kdc_req *);
-    alloc_field(rep);
-
-    retval = asn1_decode_kdc_req_body(&buf,rep);
-    if (retval) clean_return(retval);
-
-    cleanup(free);
-}
-
 /*
  * decode_krb5_safe_with_body
  *
@@ -1110,53 +840,8 @@ decode_krb5_etype_list(const krb5_data *code, krb5_etype_list **repptr)
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_pa_fx_fast_request
-(const krb5_data *code, krb5_fast_armored_req **repptr)
-{
-    setup(krb5_fast_armored_req *);
-    alloc_field(rep);
-    clear_field(rep, armor);
-    {
-        int indef;
-        unsigned int taglen;
-        next_tag_from_buf(buf);
-        if (tagnum != 0)
-            clean_return(ASN1_BAD_ID);
-    }
-    {begin_structure();
-        opt_field(rep->armor, 0, asn1_decode_fast_armor_ptr);
-        get_field(rep->req_checksum, 1, asn1_decode_checksum);
-        get_field(rep->enc_part, 2, asn1_decode_encrypted_data);
-        end_structure();}
-    rep->magic = KV5M_FAST_ARMORED_REQ;
-    cleanup(free);
-}
-
-krb5_error_code decode_krb5_fast_req
-(const krb5_data *code, krb5_fast_req **repptr)
-{
-    setup(krb5_fast_req *);
-    alloc_field(rep);
-    alloc_field(rep->req_body);
-    clear_field(rep, req_body->padata);
-    {begin_structure();
-        get_field(rep->fast_options, 0, asn1_decode_krb5_flags);
-        opt_field(rep->req_body->padata, 1, asn1_decode_sequence_of_pa_data);
-        get_field(*(rep->req_body), 2, asn1_decode_kdc_req_body);
-        end_structure(); }
-    rep->magic  = KV5M_FAST_REQ;
-    cleanup_manual();
-error_out:
-    if (rep) {
-        if (rep->req_body)
-            krb5_free_kdc_req(0, rep->req_body);
-        free(rep);
-    }
-    return retval;
-}
-
-krb5_error_code decode_krb5_fast_response
-(const krb5_data *code, krb5_fast_response **repptr)
+krb5_error_code
+decode_krb5_fast_response(const krb5_data *code, krb5_fast_response **repptr)
 {
     setup(krb5_fast_response *);
 
@@ -1174,8 +859,8 @@ krb5_error_code decode_krb5_fast_response
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_pa_fx_fast_reply
-(const krb5_data *code, krb5_enc_data **repptr)
+krb5_error_code
+decode_krb5_pa_fx_fast_reply(const krb5_data *code, krb5_enc_data **repptr)
 {
     setup(krb5_enc_data *);
     alloc_field(rep);
@@ -1218,8 +903,8 @@ decode_krb5_ad_signedpath(const krb5_data *code, krb5_ad_signedpath **repptr)
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_iakerb_header
-(const krb5_data *code, krb5_iakerb_header **repptr)
+krb5_error_code
+decode_krb5_iakerb_header(const krb5_data *code, krb5_iakerb_header **repptr)
 {
     setup_buf_only(krb5_iakerb_header *);
     alloc_field(rep);
@@ -1230,8 +915,8 @@ krb5_error_code decode_krb5_iakerb_header
     cleanup(free);
 }
 
-krb5_error_code decode_krb5_iakerb_finished
-(const krb5_data *code, krb5_iakerb_finished **repptr)
+krb5_error_code
+decode_krb5_iakerb_finished(const krb5_data *code, krb5_iakerb_finished **repptr)
 {
     setup_buf_only(krb5_iakerb_finished *);
     alloc_field(rep);
@@ -1267,30 +952,6 @@ krb5int_get_authdata_containee_types(krb5_context context,
 }
 
 #ifndef DISABLE_PKINIT
-krb5_error_code
-decode_krb5_pa_pk_as_req(const krb5_data *code, krb5_pa_pk_as_req **repptr)
-{
-    setup_buf_only(krb5_pa_pk_as_req *);
-    alloc_field(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 **repptr)
-{
-    setup_buf_only(krb5_pa_pk_as_req_draft9 *);
-    alloc_field(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 **repptr)
diff --git a/src/lib/krb5/asn.1/krb5_decode_kdc.c b/src/lib/krb5/asn.1/krb5_decode_kdc.c
new file mode 100644 (file)
index 0000000..e888d71
--- /dev/null
@@ -0,0 +1,171 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/krb5_decode_kdc.c
+ *
+ * Copyright 1994, 2008. 2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "krbasn1.h"
+#include "krb5_decode_macros.h"
+
+krb5_error_code
+decode_krb5_as_req(const krb5_data *code, krb5_kdc_req **repptr)
+{
+    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);
+    clear_field(rep, kdc_state);
+
+    check_apptag(10);
+    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);
+#endif
+
+    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 **repptr)
+{
+    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);
+    clear_field(rep, kdc_state);
+
+    check_apptag(12);
+    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);
+#endif
+
+    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 **repptr)
+{
+    setup_buf_only(krb5_kdc_req *);
+    alloc_field(rep);
+
+    retval = asn1_decode_kdc_req_body(&buf,rep);
+    if (retval) clean_return(retval);
+
+    cleanup(free);
+}
+  
+krb5_error_code
+decode_krb5_fast_req(const krb5_data *code, krb5_fast_req **repptr)
+{
+    setup(krb5_fast_req *);
+    alloc_field(rep);
+    alloc_field(rep->req_body);
+    clear_field(rep, req_body->padata);
+    {begin_structure();
+        get_field(rep->fast_options, 0, asn1_decode_krb5_flags);
+        opt_field(rep->req_body->padata, 1, asn1_decode_sequence_of_pa_data);
+        get_field(*(rep->req_body), 2, asn1_decode_kdc_req_body);
+        end_structure(); }
+    rep->magic  = KV5M_FAST_REQ;
+    cleanup_manual();
+error_out:
+    if (rep) {
+        if (rep->req_body)
+            krb5_free_kdc_req(0, rep->req_body);
+        free(rep);
+    }
+    return retval;
+}
+
+krb5_error_code
+decode_krb5_pa_fx_fast_request(const krb5_data *code, krb5_fast_armored_req **repptr)
+{
+    setup(krb5_fast_armored_req *);
+    alloc_field(rep);
+    clear_field(rep, armor);
+    {
+        int indef;
+        unsigned int taglen;
+        next_tag_from_buf(buf);
+        if (tagnum != 0)
+            clean_return(ASN1_BAD_ID);
+    }
+    {begin_structure();
+        opt_field(rep->armor, 0, asn1_decode_fast_armor_ptr);
+        get_field(rep->req_checksum, 1, asn1_decode_checksum);
+        get_field(rep->enc_part, 2, asn1_decode_encrypted_data);
+        end_structure();}
+    rep->magic = KV5M_FAST_ARMORED_REQ;
+    cleanup(free);
+}
+
+#ifndef DISABLE_PKINIT
+krb5_error_code
+decode_krb5_pa_pk_as_req(const krb5_data *code, krb5_pa_pk_as_req **repptr)
+{
+    setup_buf_only(krb5_pa_pk_as_req *);
+    alloc_field(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 **repptr)
+{
+    setup_buf_only(krb5_pa_pk_as_req_draft9 *);
+    alloc_field(rep);
+
+    retval = asn1_decode_pa_pk_as_req_draft9(&buf, rep);
+    if (retval) clean_return(retval);
+
+    cleanup(free);
+}
+#endif /* DISABLE_PKINIT */
+
diff --git a/src/lib/krb5/asn.1/krb5_decode_macros.h b/src/lib/krb5/asn.1/krb5_decode_macros.h
new file mode 100644 (file)
index 0000000..a77e74b
--- /dev/null
@@ -0,0 +1,239 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/krb5_decode_macros.h
+ *
+ * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KRB5_DECODE_MACROS_H
+#define KRB5_DECODE_MACROS_H
+
+#include "asn1_k_decode.h"
+#include "asn1_decode.h"
+#include "asn1_get.h"
+#include "asn1_misc.h"
+
+/* setup *********************************************************/
+/* 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(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(type)                   \
+    asn1_class asn1class;                       \
+    asn1_construction construction;             \
+    setup_buf_only(type)
+
+#define setup_no_length(type)                   \
+    asn1_tagnum tagnum;                         \
+    setup_no_tagnum(type)
+
+#define setup(type)                             \
+    unsigned int 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)                        \
+    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)                                         \
+    {                                                                   \
+        taginfo t1;                                                     \
+        retval = asn1_get_tag_2(&buf, &t1);                             \
+        if (retval) clean_return (retval);                              \
+        if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED) \
+            clean_return(ASN1_BAD_ID);                                  \
+        if (t1.tagnum != (tagexpect)) clean_return(KRB5_BADMSGTYPE);    \
+        asn1class = t1.asn1class;                                       \
+        construction = t1.construction;                                 \
+        tagnum = t1.tagnum;                                             \
+    }
+
+
+
+/* process a structure *******************************************/
+
+/* decode an explicit tag and place the number in tagnum */
+#define next_tag_from_buf(buf)                  \
+    { taginfo t2;                               \
+        retval = asn1_get_tag_2(&(buf), &t2);   \
+        if (retval) clean_return(retval);       \
+        asn1class = t2.asn1class;               \
+        construction = t2.construction;         \
+        tagnum = t2.tagnum;                     \
+        indef = t2.indef;                       \
+        taglen = t2.length;                     \
+    }
+#define next_tag() next_tag_from_buf(subbuf)
+
+
+static asn1_error_code
+asn1_get_eoc_tag (asn1buf *buf)
+{
+    asn1_error_code retval;
+    taginfo t;
+
+    retval = asn1_get_tag_2(buf, &t);
+    if (retval)
+        return retval;
+    if (t.asn1class != UNIVERSAL || t.tagnum || t.indef)
+        return ASN1_MISSING_EOC;
+    return 0;
+}
+
+#define get_eoc()                               \
+    {                                           \
+        retval = asn1_get_eoc_tag(&subbuf);     \
+        if (retval) clean_return(retval);       \
+    }
+
+/* decode sequence header and initialize tagnum with the first field */
+#define begin_structure()                                       \
+    unsigned int taglen;                                        \
+    asn1buf subbuf;                                             \
+    int seqindef;                                               \
+    int indef;                                                  \
+    retval = asn1_get_sequence(&buf,&length,&seqindef);         \
+    if (retval) clean_return(retval);                           \
+    retval = asn1buf_imbed(&subbuf,&buf,length,seqindef);       \
+    if (retval) clean_return(retval);                           \
+    next_tag()
+
+#define end_structure()                                         \
+    retval = asn1buf_sync(&buf,&subbuf,asn1class,               \
+                          tagnum,length,indef,seqindef);        \
+    if (retval) clean_return(retval)
+
+/* process fields *******************************************/
+/* normal fields ************************/
+#define get_field_body(var,decoder)             \
+    retval = decoder(&subbuf,&(var));           \
+    if (retval) clean_return(retval);           \
+    if (indef) { get_eoc(); }                   \
+    next_tag()
+
+/*
+ * error_if_bad_tag
+ *
+ * Checks that the next tag is the expected one; returns with an error
+ * if not.
+ */
+#define error_if_bad_tag(tagexpect)                                     \
+    if (tagnum != (tagexpect)) { clean_return ((tagnum < (tagexpect)) ? ASN1_MISPLACED_FIELD : ASN1_MISSING_FIELD); }
+
+/*
+ * decode a field (<[UNIVERSAL id]> <length> <contents>)
+ *  check that the id number == tagexpect then
+ *  decode into var
+ *  get the next tag
+ */
+#define get_field(var,tagexpect,decoder)                                \
+    error_if_bad_tag(tagexpect);                                        \
+    if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)   \
+        clean_return(ASN1_BAD_ID);                                      \
+    get_field_body(var,decoder)
+
+/* decode (or skip, if not present) an optional field */
+#define opt_field(var,tagexpect,decoder)                                \
+    if (asn1buf_remains(&subbuf, seqindef)) {                           \
+        if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+            clean_return(ASN1_BAD_ID);                                  \
+        if (tagnum == (tagexpect)) {                                    \
+            get_field_body(var,decoder);                                \
+        }                                                               \
+    }
+
+/* field w/ accompanying length *********/
+#define get_lenfield_body(len,var,decoder)      \
+    retval = decoder(&subbuf,&(len),&(var));    \
+    if (retval) clean_return(retval);           \
+    if (indef) { get_eoc(); }                   \
+    next_tag()
+
+/* decode a field w/ its length (for string types) */
+#define get_lenfield(len,var,tagexpect,decoder)                         \
+    error_if_bad_tag(tagexpect);                                        \
+    if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)   \
+        clean_return(ASN1_BAD_ID);                                      \
+    get_lenfield_body(len,var,decoder)
+
+/* decode an optional field w/ length */
+#define opt_lenfield(len,var,tagexpect,decoder)                         \
+    if (asn1buf_remains(&subbuf, seqindef)) {                           \
+        if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+            clean_return(ASN1_BAD_ID);                                  \
+        if (tagnum == (tagexpect)) {                                    \
+            get_lenfield_body(len,var,decoder);                         \
+        }                                                               \
+    }
+
+
+/* clean up ******************************************************/
+/* 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)                                        \
+    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
+
+#endif