1 /*
2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * src/lib/krb5/asn.1/krb5_decode.c
10  *
11  * Copyright 1994 by the Massachusetts Institute of Technology.
12  * All Rights Reserved.
13  *
14  * Export of this software from the United States of America may
15  *   require a specific license from the United States Government.
16  *   It is the responsibility of any person or organization contemplating
17  *   export to obtain such a license before exporting.
18  *
19  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
20  * distribute this software and its documentation for any purpose and
21  * without fee is hereby granted, provided that the above copyright
22  * notice appear in all copies and that both that copyright notice and
23  * this permission notice appear in supporting documentation, and that
24  * the name of M.I.T. not be used in advertising or publicity pertaining
25  * to distribution of the software without specific, written prior
26  * permission.  Furthermore if you modify this software you must label
27  * your software as modified software and not distribute it in such a
28  * fashion that it might be confused with the original M.I.T. software.
29  * M.I.T. makes no representations about the suitability of
30  * this software for any purpose.  It is provided "as is" without express
31  * or implied warranty.
32  */
33 
34 #include "krb5.h"
35 #include "krbasn1.h"
36 #include "asn1_k_decode.h"
37 #include "asn1_decode.h"
38 #include "asn1_get.h"
39 
40 /* setup *********************************************************/
41 /* set up variables */
42 /* the setup* macros can return, but are always used at function start
43    and thus need no malloc cleanup */
44 #define setup_buf_only()\
45 asn1_error_code retval;\
46 asn1buf buf;\
47 \
48 retval = asn1buf_wrap_data(&buf,code);\
49 if(retval) return retval
50 
51 #define setup_no_tagnum()\
52 asn1_class asn1class;\
53 asn1_construction construction;\
54 setup_buf_only()
55 
56 #define setup_no_length()\
57 asn1_tagnum tagnum;\
58 setup_no_tagnum()
59 
60 #define setup()\
61 unsigned int length;\
62 setup_no_length()
63 
64 /* helper macros for cleanup */
65 #define clean_return(val) { retval = val; goto error_out; }
66 
67 /* alloc_field is the first thing to allocate storage that may need cleanup */
68 #define alloc_field(var,type)\
69 var = (type*)calloc(1,sizeof(type));\
70 if((var) == NULL) clean_return(ENOMEM)
71 
72 /* process encoding header ***************************************/
73 /* decode tag and check that it == [APPLICATION tagnum] */
74 #define check_apptag(tagexpect)						\
75 {									\
76     taginfo t1;								\
77     retval = asn1_get_tag_2(&buf, &t1);					\
78     if (retval) clean_return (retval);					\
79     if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED)	\
80 	clean_return(ASN1_BAD_ID);					\
81     if (t1.tagnum != (tagexpect)) clean_return(KRB5_BADMSGTYPE);	\
82     asn1class = t1.asn1class;						\
83     construction = t1.construction;					\
84     tagnum = t1.tagnum;							\
85 }
86 
87 
88 
89 /* process a structure *******************************************/
90 
91 /* decode an explicit tag and place the number in tagnum */
92 #define next_tag()				\
93 { taginfo t2;					\
94   retval = asn1_get_tag_2(&subbuf, &t2);	\
95   if(retval) clean_return(retval);		\
96   asn1class = t2.asn1class;			\
97   construction = t2.construction;		\
98   tagnum = t2.tagnum;				\
99   indef = t2.indef;				\
100   taglen = t2.length;				\
101 }
102 
103 #define get_eoc()						\
104 {								\
105     taginfo t3;							\
106     retval = asn1_get_tag_2(&subbuf, &t3);			\
107     if (retval) return retval;					\
108     if (t3.asn1class != UNIVERSAL || t3.tagnum || t3.indef)	\
109         return ASN1_MISSING_EOC;				\
110     asn1class = t3.asn1class;					\
111     construction = t3.construction;				\
112     tagnum = t3.tagnum;						\
113     indef = t3.indef;						\
114 }
115 
116 /* decode sequence header and initialize tagnum with the first field */
117 #define begin_structure()\
118 unsigned int taglen;\
119 asn1buf subbuf;\
120 int seqindef;\
121 int indef;\
122 retval = asn1_get_sequence(&buf,&length,&seqindef);\
123 if(retval) clean_return(retval);\
124 retval = asn1buf_imbed(&subbuf,&buf,length,seqindef);\
125 if(retval) clean_return(retval);\
126 next_tag()
127 
128 #define end_structure()\
129 retval = asn1buf_sync(&buf,&subbuf,asn1class,tagnum,length,indef,seqindef);\
130 if (retval) clean_return(retval)
131 
132 /* process fields *******************************************/
133 /* normal fields ************************/
134 #define get_field_body(var,decoder)\
135 retval = decoder(&subbuf,&(var));\
136 if(retval) clean_return(retval);\
137 if (indef) { get_eoc(); }\
138 next_tag()
139 
140 /* decode a field (<[UNIVERSAL id]> <length> <contents>)
141     check that the id number == tagexpect then
142     decode into var
143     get the next tag */
144 #define get_field(var,tagexpect,decoder)\
145 if(tagnum > (tagexpect)) clean_return(ASN1_MISSING_FIELD);\
146 if(tagnum < (tagexpect)) clean_return(ASN1_MISPLACED_FIELD);\
147 if(asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)\
148   clean_return(ASN1_BAD_ID);\
149 get_field_body(var,decoder)
150 
151 /* decode (or skip, if not present) an optional field */
152 #define opt_field(var,tagexpect,decoder)				\
153   if (asn1buf_remains(&subbuf, seqindef)) {				\
154     if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)	\
155       clean_return(ASN1_BAD_ID);					\
156     if (tagnum == (tagexpect)) {					\
157       get_field_body(var,decoder);					\
158     }									\
159   }
160 
161 /* field w/ accompanying length *********/
162 #define get_lenfield_body(len,var,decoder)\
163 retval = decoder(&subbuf,&(len),&(var));\
164 if(retval) clean_return(retval);\
165 if (indef) { get_eoc(); }\
166 next_tag()
167 
168 /* decode a field w/ its length (for string types) */
169 #define get_lenfield(len,var,tagexpect,decoder)\
170 if(tagnum > (tagexpect)) clean_return(ASN1_MISSING_FIELD);\
171 if(tagnum < (tagexpect)) clean_return(ASN1_MISPLACED_FIELD);\
172 if(asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)\
173   clean_return(ASN1_BAD_ID);\
174 get_lenfield_body(len,var,decoder)
175 
176 /* decode an optional field w/ length */
177 #define opt_lenfield(len,var,tagexpect,decoder)				\
178   if (asn1buf_remains(&subbuf, seqindef)) {				\
179     if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)	\
180       clean_return(ASN1_BAD_ID);					\
181     if (tagnum == (tagexpect)) {					\
182       get_lenfield_body(len,var,decoder);				\
183     }									\
184   }
185 
186 
187 /* clean up ******************************************************/
188 /* finish up */
189 /* to make things less painful, assume the cleanup is passed rep */
190 #define cleanup(cleanup_routine)\
191    return 0; \
192 error_out: \
193    if (rep && *rep) { \
194 	cleanup_routine(*rep); \
195 	*rep = NULL; \
196    } \
197    return retval;
198 
199 #define cleanup_none()\
200    return 0; \
201 error_out: \
202    return retval;
203 
204 #define cleanup_manual()\
205    return 0;
206 
207 #define free_field(rep,f) if ((rep)->f) free((rep)->f)
208 #define clear_field(rep,f) (*(rep))->f = 0
209 
210 krb5_error_code decode_krb5_authenticator(const krb5_data *code, krb5_authenticator **rep)
211 {
212   setup();
213   alloc_field(*rep,krb5_authenticator);
214   clear_field(rep,subkey);
215   clear_field(rep,checksum);
216   clear_field(rep,client);
217 
218   check_apptag(2);
219   { begin_structure();
220     { krb5_kvno kvno;
221       get_field(kvno,0,asn1_decode_kvno);
222       if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
223     alloc_field((*rep)->client,krb5_principal_data);
224     get_field((*rep)->client,1,asn1_decode_realm);
225     get_field((*rep)->client,2,asn1_decode_principal_name);
226     if(tagnum == 3){
227       alloc_field((*rep)->checksum,krb5_checksum);
228       get_field(*((*rep)->checksum),3,asn1_decode_checksum); }
229     get_field((*rep)->cusec,4,asn1_decode_int32);
230     get_field((*rep)->ctime,5,asn1_decode_kerberos_time);
231     if(tagnum == 6){ alloc_field((*rep)->subkey,krb5_keyblock); }
232     opt_field(*((*rep)->subkey),6,asn1_decode_encryption_key);
233     opt_field((*rep)->seq_number,7,asn1_decode_seqnum);
234     opt_field((*rep)->authorization_data,8,asn1_decode_authorization_data);
235     (*rep)->magic = KV5M_AUTHENTICATOR;
236     end_structure();
237   }
238   cleanup_manual();
239 error_out:
240   if (rep && *rep) {
241       free_field(*rep,subkey);
242       free_field(*rep,checksum);
243       free_field(*rep,client);
244       free(*rep);
245       *rep = NULL; /* Solaris: prevent double free's and bogus derefs */
246   }
247   return retval;
248 }
249 
250 krb5_error_code
251 KRB5_CALLCONV
252 krb5_decode_ticket(const krb5_data *code, krb5_ticket **rep)
253 {
254     return decode_krb5_ticket(code, rep);
255 }
256 
257 krb5_error_code decode_krb5_ticket(const krb5_data *code, krb5_ticket **rep)
258 {
259   setup();
260   alloc_field(*rep,krb5_ticket);
261   clear_field(rep,server);
262 
263   check_apptag(1);
264   { begin_structure();
265     { krb5_kvno kvno;
266       get_field(kvno,0,asn1_decode_kvno);
267       if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO);
268     }
269     alloc_field((*rep)->server,krb5_principal_data);
270     get_field((*rep)->server,1,asn1_decode_realm);
271     get_field((*rep)->server,2,asn1_decode_principal_name);
272     get_field((*rep)->enc_part,3,asn1_decode_encrypted_data);
273     (*rep)->magic = KV5M_TICKET;
274     end_structure();
275   }
276   cleanup_manual();
277 error_out:
278   if (rep && *rep) {
279       free_field(*rep,server);
280       free(*rep);
281       *rep = NULL; /* Solaris: prevent double free's and bogus derefs */
282   }
283   return retval;
284 }
285 
286 krb5_error_code decode_krb5_encryption_key(const krb5_data *code, krb5_keyblock **rep)
287 {
288   setup();
289   alloc_field(*rep,krb5_keyblock);
290 
291   { begin_structure();
292     get_field((*rep)->enctype,0,asn1_decode_enctype);
293     get_lenfield((*rep)->length,(*rep)->contents,1,asn1_decode_octetstring);
294     end_structure();
295     (*rep)->magic = KV5M_KEYBLOCK;
296   }
297   cleanup(free);
298 }
299 
300 krb5_error_code decode_krb5_enc_tkt_part(const krb5_data *code, krb5_enc_tkt_part **rep)
301 {
302   setup();
303   alloc_field(*rep,krb5_enc_tkt_part);
304   clear_field(rep,session);
305   clear_field(rep,client);
306 
307   check_apptag(3);
308   { begin_structure();
309     get_field((*rep)->flags,0,asn1_decode_ticket_flags);
310     alloc_field((*rep)->session,krb5_keyblock);
311     get_field(*((*rep)->session),1,asn1_decode_encryption_key);
312     alloc_field((*rep)->client,krb5_principal_data);
313     get_field((*rep)->client,2,asn1_decode_realm);
314     get_field((*rep)->client,3,asn1_decode_principal_name);
315     get_field((*rep)->transited,4,asn1_decode_transited_encoding);
316     get_field((*rep)->times.authtime,5,asn1_decode_kerberos_time);
317     if (tagnum == 6)
318       { get_field((*rep)->times.starttime,6,asn1_decode_kerberos_time); }
319     else
320       (*rep)->times.starttime=(*rep)->times.authtime;
321     get_field((*rep)->times.endtime,7,asn1_decode_kerberos_time);
322     opt_field((*rep)->times.renew_till,8,asn1_decode_kerberos_time);
323     opt_field((*rep)->caddrs,9,asn1_decode_host_addresses);
324     opt_field((*rep)->authorization_data,10,asn1_decode_authorization_data);
325     (*rep)->magic = KV5M_ENC_TKT_PART;
326     end_structure();
327   }
328   cleanup_manual();
329 error_out:
330   if (rep && *rep) {
331       free_field(*rep,session);
332       free_field(*rep,client);
333       free(*rep);
334       *rep = NULL; /* Solaris: prevent double free's and bogus derefs */
335   }
336   return retval;
337 }
338 
339 krb5_error_code decode_krb5_enc_kdc_rep_part(const krb5_data *code, krb5_enc_kdc_rep_part **rep)
340 {
341   taginfo t4;
342   setup_buf_only();
343   alloc_field(*rep,krb5_enc_kdc_rep_part);
344 
345   retval = asn1_get_tag_2(&buf, &t4);
346   if (retval) clean_return(retval);
347   if (t4.asn1class != APPLICATION || t4.construction != CONSTRUCTED) clean_return(ASN1_BAD_ID);
348   if (t4.tagnum == 25) (*rep)->msg_type = KRB5_AS_REP;
349   else if(t4.tagnum == 26) (*rep)->msg_type = KRB5_TGS_REP;
350   else clean_return(KRB5_BADMSGTYPE);
351 
352   retval = asn1_decode_enc_kdc_rep_part(&buf,*rep);
353   if(retval) clean_return(retval);
354 
355   cleanup(free);
356 }
357 
358 krb5_error_code decode_krb5_as_rep(const krb5_data *code, krb5_kdc_rep **rep)
359 {
360   setup_no_length();
361   alloc_field(*rep,krb5_kdc_rep);
362 
363   check_apptag(11);
364   retval = asn1_decode_kdc_rep(&buf,*rep);
365   if(retval) clean_return(retval);
366 #ifdef KRB5_MSGTYPE_STRICT
367   if((*rep)->msg_type != KRB5_AS_REP)
368     clean_return(KRB5_BADMSGTYPE);
369 #endif
370 
371   cleanup(free);
372 }
373 
374 krb5_error_code decode_krb5_tgs_rep(const krb5_data *code, krb5_kdc_rep **rep)
375 {
376   setup_no_length();
377   alloc_field(*rep,krb5_kdc_rep);
378 
379   check_apptag(13);
380   retval = asn1_decode_kdc_rep(&buf,*rep);
381   if(retval) clean_return(retval);
382 #ifdef KRB5_MSGTYPE_STRICT
383   if((*rep)->msg_type != KRB5_TGS_REP) clean_return(KRB5_BADMSGTYPE);
384 #endif
385 
386   cleanup(free);
387 }
388 
389 krb5_error_code decode_krb5_ap_req(const krb5_data *code, krb5_ap_req **rep)
390 {
391   setup();
392   alloc_field(*rep,krb5_ap_req);
393   clear_field(rep,ticket);
394 
395   check_apptag(14);
396   { begin_structure();
397     { krb5_kvno kvno;
398       get_field(kvno,0,asn1_decode_kvno);
399       if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
400     { krb5_msgtype msg_type;
401       get_field(msg_type,1,asn1_decode_msgtype);
402 #ifdef KRB5_MSGTYPE_STRICT
403       if(msg_type != KRB5_AP_REQ) clean_return(KRB5_BADMSGTYPE);
404 #endif
405     }
406     get_field((*rep)->ap_options,2,asn1_decode_ap_options);
407     alloc_field((*rep)->ticket,krb5_ticket);
408     get_field(*((*rep)->ticket),3,asn1_decode_ticket);
409     get_field((*rep)->authenticator,4,asn1_decode_encrypted_data);
410     end_structure();
411     (*rep)->magic = KV5M_AP_REQ;
412   }
413   cleanup_manual();
414 error_out:
415   if (rep && *rep) {
416       free_field(*rep,ticket);
417       free(*rep);
418       *rep = NULL; /* Solaris: prevent double free's and bogus derefs */
419   }
420   return retval;
421 }
422 
423 krb5_error_code decode_krb5_ap_rep(const krb5_data *code, krb5_ap_rep **rep)
424 {
425   setup();
426   alloc_field(*rep,krb5_ap_rep);
427 
428   check_apptag(15);
429   { begin_structure();
430     { krb5_kvno kvno;
431       get_field(kvno,0,asn1_decode_kvno);
432       if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
433     { krb5_msgtype msg_type;
434       get_field(msg_type,1,asn1_decode_msgtype);
435 #ifdef KRB5_MSGTYPE_STRICT
436       if(msg_type != KRB5_AP_REP) clean_return(KRB5_BADMSGTYPE);
437 #endif
438     }
439     get_field((*rep)->enc_part,2,asn1_decode_encrypted_data);
440     end_structure();
441     (*rep)->magic = KV5M_AP_REP;
442   }
443   cleanup(free);
444 }
445 
446 krb5_error_code decode_krb5_ap_rep_enc_part(const krb5_data *code, krb5_ap_rep_enc_part **rep)
447 {
448   setup();
449   alloc_field(*rep,krb5_ap_rep_enc_part);
450   clear_field(rep,subkey);
451 
452   check_apptag(27);
453   { begin_structure();
454     get_field((*rep)->ctime,0,asn1_decode_kerberos_time);
455     get_field((*rep)->cusec,1,asn1_decode_int32);
456     if(tagnum == 2){ alloc_field((*rep)->subkey,krb5_keyblock); }
457     opt_field(*((*rep)->subkey),2,asn1_decode_encryption_key);
458     opt_field((*rep)->seq_number,3,asn1_decode_seqnum);
459     end_structure();
460     (*rep)->magic = KV5M_AP_REP_ENC_PART;
461   }
462   cleanup_manual();
463 error_out:
464   if (rep && *rep) {
465       free_field(*rep,subkey);
466       free(*rep);
467       *rep = NULL; /* Solaris: prevent double free's and bogus derefs */
468   }
469   return retval;
470 }
471 
472 krb5_error_code decode_krb5_as_req(const krb5_data *code, krb5_kdc_req **rep)
473 {
474   setup_no_length();
475   alloc_field(*rep,krb5_kdc_req);
476 
477   check_apptag(10);
478   retval = asn1_decode_kdc_req(&buf,*rep);
479   if(retval) clean_return(retval);
480 #ifdef KRB5_MSGTYPE_STRICT
481   if((*rep)->msg_type != KRB5_AS_REQ) clean_return(KRB5_BADMSGTYPE);
482 #endif
483 
484   cleanup(free);
485 }
486 
487 krb5_error_code decode_krb5_tgs_req(const krb5_data *code, krb5_kdc_req **rep)
488 {
489   setup_no_length();
490   alloc_field(*rep,krb5_kdc_req);
491 
492   check_apptag(12);
493   retval = asn1_decode_kdc_req(&buf,*rep);
494   if(retval) clean_return(retval);
495 #ifdef KRB5_MSGTYPE_STRICT
496   if((*rep)->msg_type != KRB5_TGS_REQ) clean_return(KRB5_BADMSGTYPE);
497 #endif
498 
499   cleanup(free);
500 }
501 
502 krb5_error_code decode_krb5_kdc_req_body(const krb5_data *code, krb5_kdc_req **rep)
503 {
504   setup_buf_only();
505   alloc_field(*rep,krb5_kdc_req);
506 
507   retval = asn1_decode_kdc_req_body(&buf,*rep);
508   if(retval) clean_return(retval);
509 
510   cleanup(free);
511 }
512 
513 /*
514  * decode_krb5_safe_with_body
515  *
516  * Like decode_krb5_safe(), but grabs the encoding of the
517  * KRB-SAFE-BODY as well, in case re-encoding would produce a
518  * different encoding.  (Yes, we're using DER, but there's this
519  * annoying problem with pre-1.3.x code using signed sequence numbers,
520  * which we permissively decode and cram into unsigned 32-bit numbers.
521  * When they're re-encoded, they're no longer negative if they started
522  * out negative, so checksum verification fails.)
523  *
524  * This does *not* perform any copying; the returned pointer to the
525  * encoded KRB-SAFE-BODY points into the input buffer.
526  */
527 krb5_error_code decode_krb5_safe_with_body(
528   const krb5_data *code,
529   krb5_safe **rep,
530   krb5_data *body)
531 {
532   krb5_data tmpbody;
533   setup();
534   alloc_field(*rep,krb5_safe);
535   clear_field(rep,checksum);
536 
537   check_apptag(20);
538   { begin_structure();
539     { krb5_kvno kvno;
540       get_field(kvno,0,asn1_decode_kvno);
541       if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
542     { krb5_msgtype msg_type;
543       get_field(msg_type,1,asn1_decode_msgtype);
544 #ifdef KRB5_MSGTYPE_STRICT
545       if(msg_type != KRB5_SAFE) clean_return(KRB5_BADMSGTYPE);
546 #endif
547     }
548     /*
549      * Gross kludge to extract pointer to encoded safe-body.  Relies
550      * on tag prefetch done by next_tag().  Don't handle indefinite
551      * encoding, as it's too much work.
552      */
553     if (!indef) {
554       tmpbody.length = taglen;
555       tmpbody.data = subbuf.next;
556     } else {
557       tmpbody.length = 0;
558       tmpbody.data = NULL;
559     }
560     get_field(**rep,2,asn1_decode_krb_safe_body);
561     alloc_field((*rep)->checksum,krb5_checksum);
562     get_field(*((*rep)->checksum),3,asn1_decode_checksum);
563   (*rep)->magic = KV5M_SAFE;
564     end_structure();
565   }
566   if (body != NULL)
567     *body = tmpbody;
568   cleanup_manual();
569 error_out:
570   if (rep && *rep) {
571       free_field(*rep,checksum);
572       free(*rep);
573       *rep = NULL; /* Solaris: prevent double free's and bogus derefs */
574   }
575   return retval;
576 }
577 
578 krb5_error_code decode_krb5_safe(const krb5_data *code, krb5_safe **rep)
579 {
580   return decode_krb5_safe_with_body(code, rep, NULL);
581 }
582 
583 krb5_error_code decode_krb5_priv(const krb5_data *code, krb5_priv **rep)
584 {
585   setup();
586   alloc_field(*rep,krb5_priv);
587 
588   check_apptag(21);
589   { begin_structure();
590     { krb5_kvno kvno;
591       get_field(kvno,0,asn1_decode_kvno);
592       if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
593     { krb5_msgtype msg_type;
594       get_field(msg_type,1,asn1_decode_msgtype);
595 #ifdef KRB5_MSGTYPE_STRICT
596       if(msg_type != KRB5_PRIV) clean_return(KRB5_BADMSGTYPE);
597 #endif
598     }
599     get_field((*rep)->enc_part,3,asn1_decode_encrypted_data);
600     (*rep)->magic = KV5M_PRIV;
601     end_structure();
602   }
603   cleanup(free);
604 }
605 
606 krb5_error_code decode_krb5_enc_priv_part(const krb5_data *code, krb5_priv_enc_part **rep)
607 {
608   setup();
609   alloc_field(*rep,krb5_priv_enc_part);
610   clear_field(rep,r_address);
611   clear_field(rep,s_address);
612 
613   check_apptag(28);
614   { begin_structure();
615     get_lenfield((*rep)->user_data.length,(*rep)->user_data.data,0,asn1_decode_charstring);
616     opt_field((*rep)->timestamp,1,asn1_decode_kerberos_time);
617     opt_field((*rep)->usec,2,asn1_decode_int32);
618     opt_field((*rep)->seq_number,3,asn1_decode_seqnum);
619     alloc_field((*rep)->s_address,krb5_address);
620     get_field(*((*rep)->s_address),4,asn1_decode_host_address);
621     if(tagnum == 5){ alloc_field((*rep)->r_address,krb5_address); }
622     opt_field(*((*rep)->r_address),5,asn1_decode_host_address);
623     (*rep)->magic = KV5M_PRIV_ENC_PART;
624     end_structure();
625   }
626   cleanup_manual();
627 error_out:
628   if (rep && *rep) {
629       free_field(*rep,r_address);
630       free_field(*rep,s_address);
631       free(*rep);
632       *rep = NULL; /* Solaris: prevent double free's and bogus derefs */
633   }
634   return retval;
635 }
636 
637 krb5_error_code decode_krb5_cred(const krb5_data *code, krb5_cred **rep)
638 {
639   setup();
640   alloc_field(*rep,krb5_cred);
641 
642   check_apptag(22);
643   { begin_structure();
644     { krb5_kvno kvno;
645       get_field(kvno,0,asn1_decode_kvno);
646       if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
647     { krb5_msgtype msg_type;
648       get_field(msg_type,1,asn1_decode_msgtype);
649 #ifdef KRB5_MSGTYPE_STRICT
650       if(msg_type != KRB5_CRED) clean_return(KRB5_BADMSGTYPE);
651 #endif
652     }
653     get_field((*rep)->tickets,2,asn1_decode_sequence_of_ticket);
654     get_field((*rep)->enc_part,3,asn1_decode_encrypted_data);
655     (*rep)->magic = KV5M_CRED;
656     end_structure();
657   }
658   cleanup(free);
659 }
660 
661 krb5_error_code decode_krb5_enc_cred_part(const krb5_data *code, krb5_cred_enc_part **rep)
662 {
663   setup();
664   alloc_field(*rep,krb5_cred_enc_part);
665   clear_field(rep,r_address);
666   clear_field(rep,s_address);
667 
668   check_apptag(29);
669   { begin_structure();
670     get_field((*rep)->ticket_info,0,asn1_decode_sequence_of_krb_cred_info);
671     opt_field((*rep)->nonce,1,asn1_decode_int32);
672     opt_field((*rep)->timestamp,2,asn1_decode_kerberos_time);
673     opt_field((*rep)->usec,3,asn1_decode_int32);
674     if(tagnum == 4){ alloc_field((*rep)->s_address,krb5_address); }
675     opt_field(*((*rep)->s_address),4,asn1_decode_host_address);
676     if(tagnum == 5){ alloc_field((*rep)->r_address,krb5_address); }
677     opt_field(*((*rep)->r_address),5,asn1_decode_host_address);
678     (*rep)->magic = KV5M_CRED_ENC_PART;
679     end_structure();
680   }
681   cleanup_manual();
682 error_out:
683   if (rep && *rep) {
684       free_field(*rep,r_address);
685       free_field(*rep,s_address);
686       free(*rep);
687       *rep = NULL; /* Solaris: prevent double free's and bogus derefs */
688   }
689   return retval;
690 }
691 
692 
693 krb5_error_code decode_krb5_error(const krb5_data *code, krb5_error **rep)
694 {
695   setup();
696   alloc_field(*rep,krb5_error);
697   clear_field(rep,server);
698   clear_field(rep,client);
699 
700   check_apptag(30);
701   { begin_structure();
702     { krb5_kvno kvno;
703       get_field(kvno,0,asn1_decode_kvno);
704       if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
705     { krb5_msgtype msg_type;
706       get_field(msg_type,1,asn1_decode_msgtype);
707 #ifdef KRB5_MSGTYPE_STRICT
708       if(msg_type != KRB5_ERROR) clean_return(KRB5_BADMSGTYPE);
709 #endif
710     }
711     opt_field((*rep)->ctime,2,asn1_decode_kerberos_time);
712     opt_field((*rep)->cusec,3,asn1_decode_int32);
713     get_field((*rep)->stime,4,asn1_decode_kerberos_time);
714     get_field((*rep)->susec,5,asn1_decode_int32);
715     get_field((*rep)->error,6,asn1_decode_ui_4);
716     if(tagnum == 7){ alloc_field((*rep)->client,krb5_principal_data); }
717     opt_field((*rep)->client,7,asn1_decode_realm);
718     opt_field((*rep)->client,8,asn1_decode_principal_name);
719     alloc_field((*rep)->server,krb5_principal_data);
720     get_field((*rep)->server,9,asn1_decode_realm);
721     get_field((*rep)->server,10,asn1_decode_principal_name);
722     opt_lenfield((*rep)->text.length,(*rep)->text.data,11,asn1_decode_generalstring);
723     opt_lenfield((*rep)->e_data.length,(*rep)->e_data.data,12,asn1_decode_charstring);
724     (*rep)->magic = KV5M_ERROR;
725     end_structure();
726   }
727   cleanup_manual();
728 error_out:
729   if (rep && *rep) {
730       free_field(*rep,server);
731       free_field(*rep,client);
732       free(*rep);
733       *rep = NULL; /* Solaris: prevent double free's and bogus derefs */
734   }
735   return retval;
736 }
737 
738 krb5_error_code decode_krb5_authdata(const krb5_data *code, krb5_authdata ***rep)
739 {
740   setup_buf_only();
741   *rep = 0;
742   retval = asn1_decode_authorization_data(&buf,rep);
743   if(retval) clean_return(retval);
744   cleanup_none();		/* we're not allocating anything here... */
745 }
746 
747 krb5_error_code decode_krb5_pwd_sequence(const krb5_data *code, passwd_phrase_element **rep)
748 {
749   setup_buf_only();
750   alloc_field(*rep,passwd_phrase_element);
751   retval = asn1_decode_passwdsequence(&buf,*rep);
752   if(retval) clean_return(retval);
753   cleanup(free);
754 }
755 
756 krb5_error_code decode_krb5_pwd_data(const krb5_data *code, krb5_pwd_data **rep)
757 {
758   setup();
759   alloc_field(*rep,krb5_pwd_data);
760   { begin_structure();
761     get_field((*rep)->sequence_count,0,asn1_decode_int);
762     get_field((*rep)->element,1,asn1_decode_sequence_of_passwdsequence);
763     (*rep)->magic = KV5M_PWD_DATA;
764     end_structure (); }
765   cleanup(free);
766 }
767 
768 krb5_error_code decode_krb5_padata_sequence(const krb5_data *code, krb5_pa_data ***rep)
769 {
770   setup_buf_only();
771   *rep = 0;
772   retval = asn1_decode_sequence_of_pa_data(&buf,rep);
773   if(retval) clean_return(retval);
774   cleanup_none();		/* we're not allocating anything here */
775 }
776 
777 krb5_error_code decode_krb5_alt_method(const krb5_data *code, krb5_alt_method **rep)
778 {
779   setup();
780   alloc_field(*rep,krb5_alt_method);
781   { begin_structure();
782     get_field((*rep)->method,0,asn1_decode_int32);
783     if (tagnum == 1) {
784 	get_lenfield((*rep)->length,(*rep)->data,1,asn1_decode_octetstring);
785     } else {
786 	(*rep)->length = 0;
787 	(*rep)->data = 0;
788     }
789     (*rep)->magic = KV5M_ALT_METHOD;
790     end_structure();
791   }
792   cleanup(free);
793 }
794 
795 krb5_error_code decode_krb5_etype_info(const krb5_data *code, krb5_etype_info_entry ***rep)
796 {
797   setup_buf_only();
798   *rep = 0;
799   retval = asn1_decode_etype_info(&buf,rep);
800   if(retval) clean_return(retval);
801   cleanup_none();		/* we're not allocating anything here */
802 }
803 
804 krb5_error_code decode_krb5_etype_info2(const krb5_data *code, krb5_etype_info_entry ***rep)
805 {
806     setup_buf_only();
807     *rep = 0;
808     retval = asn1_decode_etype_info2(&buf,rep, 0);
809     if (retval == ASN1_BAD_ID) {
810 	retval = asn1buf_wrap_data(&buf,code);
811 	if(retval) clean_return(retval);
812 	retval = asn1_decode_etype_info2(&buf, rep, 1);
813     }
814     if(retval) clean_return(retval);
815     cleanup_none();		/* we're not allocating anything here */
816 }
817 
818 
819 krb5_error_code decode_krb5_enc_data(const krb5_data *code, krb5_enc_data **rep)
820 {
821   setup_buf_only();
822   alloc_field(*rep,krb5_enc_data);
823 
824   retval = asn1_decode_encrypted_data(&buf,*rep);
825   if(retval) clean_return(retval);
826 
827   cleanup(free);
828 }
829 
830 krb5_error_code decode_krb5_pa_enc_ts(const krb5_data *code, krb5_pa_enc_ts **rep)
831 {
832   setup();
833   alloc_field(*rep,krb5_pa_enc_ts);
834   { begin_structure();
835     get_field((*rep)->patimestamp,0,asn1_decode_kerberos_time);
836     if (tagnum == 1) {
837 	get_field((*rep)->pausec,1,asn1_decode_int32);
838     } else
839 	(*rep)->pausec = 0;
840     end_structure (); }
841   cleanup(free);
842 }
843 
844 krb5_error_code decode_krb5_sam_challenge(const krb5_data *code, krb5_sam_challenge **rep)
845 {
846   setup_buf_only();
847   alloc_field(*rep,krb5_sam_challenge);
848 
849   retval = asn1_decode_sam_challenge(&buf,*rep);
850   if(retval) clean_return(retval);
851 
852   cleanup(free);
853 }
854 
855 krb5_error_code decode_krb5_sam_challenge_2(const krb5_data *code, krb5_sam_challenge_2 **rep)
856 {
857   setup_buf_only();
858   alloc_field(*rep,krb5_sam_challenge_2);
859 
860   retval = asn1_decode_sam_challenge_2(&buf,*rep);
861   if(retval) clean_return(retval);
862 
863   cleanup(free);
864 }
865 
866 krb5_error_code decode_krb5_sam_challenge_2_body(const krb5_data *code, krb5_sam_challenge_2_body **rep)
867 {
868   setup_buf_only();
869   alloc_field(*rep, krb5_sam_challenge_2_body);
870 
871   retval = asn1_decode_sam_challenge_2_body(&buf, *rep);
872   if(retval) clean_return(retval);
873 
874   cleanup(free);
875 }
876 
877 krb5_error_code decode_krb5_enc_sam_key(const krb5_data *code, krb5_sam_key **rep)
878 {
879   setup_buf_only();
880   alloc_field(*rep,krb5_sam_key);
881 
882   retval = asn1_decode_enc_sam_key(&buf,*rep);
883   if(retval) clean_return(retval);
884 
885   cleanup(free);
886 }
887 
888 krb5_error_code decode_krb5_enc_sam_response_enc(const krb5_data *code, krb5_enc_sam_response_enc **rep)
889 {
890   setup_buf_only();
891   alloc_field(*rep,krb5_enc_sam_response_enc);
892 
893   retval = asn1_decode_enc_sam_response_enc(&buf,*rep);
894   if(retval) clean_return(retval);
895 
896   cleanup(free);
897 }
898 
899 krb5_error_code decode_krb5_enc_sam_response_enc_2(const krb5_data *code, krb5_enc_sam_response_enc_2 **rep)
900 {
901   setup_buf_only();
902   alloc_field(*rep,krb5_enc_sam_response_enc_2);
903 
904   retval = asn1_decode_enc_sam_response_enc_2(&buf,*rep);
905   if(retval) clean_return(retval);
906 
907   cleanup(free);
908 }
909 
910 krb5_error_code decode_krb5_sam_response(const krb5_data *code, krb5_sam_response **rep)
911 {
912   setup_buf_only();
913   alloc_field(*rep,krb5_sam_response);
914 
915   retval = asn1_decode_sam_response(&buf,*rep);
916   if(retval) clean_return(retval);
917 
918   cleanup(free);
919 }
920 
921 krb5_error_code decode_krb5_sam_response_2(const krb5_data *code, krb5_sam_response_2 **rep)
922 {
923   setup_buf_only();
924   alloc_field(*rep,krb5_sam_response_2);
925 
926   retval = asn1_decode_sam_response_2(&buf,*rep);
927   if(retval) clean_return(retval);
928 
929   cleanup(free);
930 }
931 
932 krb5_error_code decode_krb5_predicted_sam_response(const krb5_data *code, krb5_predicted_sam_response **rep)
933 {
934   setup_buf_only();		/* preallocated */
935   alloc_field(*rep,krb5_predicted_sam_response);
936 
937   retval = asn1_decode_predicted_sam_response(&buf,*rep);
938   if(retval) clean_return(retval);
939 
940   cleanup(free);
941 }
942 
943