Fix memory leak; free enctypes after use
[krb5.git] / src / lib / krb5 / krb / gc_via_tkt.c
1 /*
2  * lib/krb5/krb/gc_via_tgt.c
3  *
4  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  M.I.T. makes no representations about the suitability of
20  * this software for any purpose.  It is provided "as is" without express
21  * or implied warranty.
22  * 
23  *
24  * Given a tkt, and a target cred, get it.
25  * Assumes that the kdc_rep has been decrypted.
26  */
27
28 #include "k5-int.h"
29 #include "int-proto.h"
30
31 #define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew)
32
33 static krb5_error_code
34 krb5_kdcrep2creds(context, pkdcrep, address, psectkt, ppcreds)
35     krb5_context          context;
36     krb5_kdc_rep        * pkdcrep;
37     krb5_address *const * address;
38     krb5_data           * psectkt;
39     krb5_creds         ** ppcreds;
40 {
41     krb5_error_code retval;  
42     krb5_data *pdata;
43   
44     if ((*ppcreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) {
45         return ENOMEM;
46     }
47
48     memset(*ppcreds, 0, sizeof(krb5_creds));
49
50     if ((retval = krb5_copy_principal(context, pkdcrep->client,
51                                      &(*ppcreds)->client)))
52         goto cleanup;
53
54     if ((retval = krb5_copy_principal(context, pkdcrep->enc_part2->server,
55                                      &(*ppcreds)->server)))
56         goto cleanup;
57
58     if ((retval = krb5_copy_keyblock_contents(context, 
59                                               pkdcrep->enc_part2->session,
60                                               &(*ppcreds)->keyblock)))
61         goto cleanup;
62
63     if ((retval = krb5_copy_data(context, psectkt, &pdata)))
64         goto cleanup;
65     (*ppcreds)->second_ticket = *pdata;
66     krb5_xfree(pdata);
67
68     (*ppcreds)->ticket_flags = pkdcrep->enc_part2->flags;
69     (*ppcreds)->times = pkdcrep->enc_part2->times;
70     (*ppcreds)->magic = KV5M_CREDS;
71
72     (*ppcreds)->authdata = NULL;                        /* not used */
73     (*ppcreds)->is_skey = psectkt->length != 0;
74
75     if (pkdcrep->enc_part2->caddrs) {
76         if ((retval = krb5_copy_addresses(context, pkdcrep->enc_part2->caddrs,
77                                           &(*ppcreds)->addresses)))
78             goto cleanup_keyblock;
79     } else {
80         /* no addresses in the list means we got what we had */
81         if ((retval = krb5_copy_addresses(context, address,
82                                           &(*ppcreds)->addresses)))
83             goto cleanup_keyblock;
84     }
85
86     if ((retval = encode_krb5_ticket(pkdcrep->ticket, &pdata)))
87         goto cleanup_keyblock;
88
89     (*ppcreds)->ticket = *pdata;
90     free(pdata);
91     return 0;
92
93 cleanup_keyblock:
94     krb5_free_keyblock(context, &(*ppcreds)->keyblock);
95
96 cleanup:
97     free (*ppcreds);
98     return retval;
99 }
100  
101 krb5_error_code INTERFACE
102 krb5_get_cred_via_tkt (context, tkt, kdcoptions, address, in_cred, out_cred)
103     krb5_context          context;
104     krb5_creds          * tkt;
105     const krb5_flags      kdcoptions;
106     krb5_address *const * address;
107     krb5_creds          * in_cred;
108     krb5_creds         ** out_cred;
109 {
110     krb5_error_code retval;
111     krb5_kdc_rep *dec_rep;
112     krb5_error *err_reply;
113     krb5_response tgsrep;
114     krb5_enctype *enctypes = 0;
115
116     /* tkt->client must be equal to in_cred->client */
117     if (!krb5_principal_compare(context, tkt->client, in_cred->client))
118         return KRB5_PRINC_NOMATCH;
119
120     if (!tkt->ticket.length)
121         return KRB5_NO_TKT_SUPPLIED;
122
123     if ((kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) && 
124         (!in_cred->second_ticket.length))
125         return(KRB5_NO_2ND_TKT);
126
127
128     /* check if we have the right TGT                    */
129     /* tkt->server must be equal to                      */
130     /* krbtgt/realmof(cred->server)@realmof(tgt->server) */
131 /*
132     {
133     krb5_principal tempprinc;
134         if (retval = krb5_tgtname(context, 
135                      krb5_princ_realm(context, in_cred->server),
136                      krb5_princ_realm(context, tkt->server), &tempprinc))
137             return(retval);
138
139         if (!krb5_principal_compare(context, tempprinc, tkt->server)) {
140             krb5_free_principal(context, tempprinc);
141             return (KRB5_PRINC_NOMATCH);
142         }
143     krb5_free_principal(context, tempprinc);
144     }
145 */
146
147     if (in_cred->keyblock.enctype) {
148         enctypes = (krb5_enctype *) malloc(sizeof(krb5_enctype)*2);
149         if (!enctypes)
150             return ENOMEM;
151         enctypes[0] = in_cred->keyblock.enctype;
152         enctypes[1] = 0;
153     }
154     
155     retval = krb5_send_tgs(context, kdcoptions, &in_cred->times, enctypes, 
156                            in_cred->server, address, in_cred->authdata,
157                            0,           /* no padata */
158                            (kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) ? 
159                            &in_cred->second_ticket : NULL,
160                            tkt, &tgsrep);
161     if (enctypes)
162         free(enctypes);
163     if (retval)
164         return retval;
165
166     switch (tgsrep.message_type) {
167     case KRB5_TGS_REP:
168         break;
169     case KRB5_ERROR:
170     default:
171         if (krb5_is_krb_error(&tgsrep.response))
172             retval = decode_krb5_error(&tgsrep.response, &err_reply);
173         else
174             retval = KRB5KRB_AP_ERR_MSG_TYPE;
175
176         if (retval)                     /* neither proper reply nor error! */
177             goto error_4;
178
179         retval = err_reply->error + ERROR_TABLE_BASE_krb5;
180
181         krb5_free_error(context, err_reply);
182         goto error_4;
183     }
184
185     if ((retval = krb5_decode_kdc_rep(context, &tgsrep.response,
186                                       &tkt->keyblock, &dec_rep)))
187         goto error_4;
188
189     if (dec_rep->msg_type != KRB5_TGS_REP) {
190         retval = KRB5KRB_AP_ERR_MSG_TYPE;
191         goto error_3;
192     }
193    
194     /* make sure the response hasn't been tampered with..... */
195     retval = 0;
196
197     if (!krb5_principal_compare(context, dec_rep->client, tkt->client))
198         retval = KRB5_KDCREP_MODIFIED;
199
200     if (!krb5_principal_compare(context, dec_rep->enc_part2->server, in_cred->server))
201         retval = KRB5_KDCREP_MODIFIED;
202
203     if (!krb5_principal_compare(context, dec_rep->ticket->server, in_cred->server))
204         retval = KRB5_KDCREP_MODIFIED;
205
206     if (dec_rep->enc_part2->nonce != tgsrep.expected_nonce)
207         retval = KRB5_KDCREP_MODIFIED;
208
209     if ((kdcoptions & KDC_OPT_POSTDATED) &&
210         (in_cred->times.starttime != 0) &&
211         (in_cred->times.starttime != dec_rep->enc_part2->times.starttime))
212         retval = KRB5_KDCREP_MODIFIED;
213
214     if ((in_cred->times.endtime != 0) &&
215         (dec_rep->enc_part2->times.endtime > in_cred->times.endtime))
216         retval = KRB5_KDCREP_MODIFIED;
217
218     if ((kdcoptions & KDC_OPT_RENEWABLE) &&
219         (in_cred->times.renew_till != 0) &&
220         (dec_rep->enc_part2->times.renew_till > in_cred->times.renew_till))
221         retval = KRB5_KDCREP_MODIFIED;
222
223     if ((kdcoptions & KDC_OPT_RENEWABLE_OK) &&
224         (dec_rep->enc_part2->flags & KDC_OPT_RENEWABLE) &&
225         (in_cred->times.endtime != 0) &&
226         (dec_rep->enc_part2->times.renew_till > in_cred->times.endtime))
227         retval = KRB5_KDCREP_MODIFIED;
228
229     if (retval != 0)
230         goto error_3;
231
232     if (!in_cred->times.starttime &&
233         !in_clock_skew(dec_rep->enc_part2->times.starttime,
234                        tgsrep.request_time)) {
235         retval = KRB5_KDCREP_SKEW;
236         goto error_3;
237     }
238     
239     retval = krb5_kdcrep2creds(context, dec_rep, address, 
240                                &in_cred->second_ticket,  out_cred);
241
242 error_3:;
243     memset(dec_rep->enc_part2->session->contents, 0,
244            dec_rep->enc_part2->session->length);
245     krb5_free_kdc_rep(context, dec_rep);
246
247 error_4:;
248     free(tgsrep.response.data);
249     return retval;
250 }