Windows global stuff:
[krb5.git] / src / lib / krb5 / krb / gc_via_tgt.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 tgt, and a target cred, get it.
25  */
26
27 #include "k5-int.h"
28 #include "int-proto.h"
29
30 krb5_error_code
31 krb5_get_cred_via_tgt (context, tgt, kdcoptions, sumtype, in_cred, out_cred)
32     krb5_context context;
33     krb5_creds * tgt;
34     const krb5_flags kdcoptions;
35     const krb5_cksumtype sumtype;
36     krb5_creds * in_cred;
37     krb5_creds ** out_cred;
38 {
39     krb5_error_code retval;
40     krb5_principal tempprinc;
41     krb5_data *scratch;
42     krb5_kdc_rep *dec_rep;
43     krb5_error *err_reply;
44     krb5_response tgsrep;
45
46     /* tgt->client must be equal to in_cred->client */
47     if (!krb5_principal_compare(context, tgt->client, in_cred->client))
48         return KRB5_PRINC_NOMATCH;
49
50     if (!tgt->ticket.length)
51         return(KRB5_NO_TKT_SUPPLIED);
52
53     /* check if we have the right TGT                    */
54     /* tgt->server must be equal to                      */
55     /* krbtgt/realmof(cred->server)@realmof(tgt->server) */
56
57     if (retval = krb5_tgtname(context, 
58                      krb5_princ_realm(context, in_cred->server),
59                      krb5_princ_realm(context, tgt->server), &tempprinc))
60         return(retval);
61
62     if (!krb5_principal_compare(context, tempprinc, tgt->server)) {
63         retval = KRB5_PRINC_NOMATCH;
64         goto error_5;
65     }
66
67     if (retval = krb5_send_tgs(context, kdcoptions, &in_cred->times, NULL, 
68                                sumtype, in_cred->server, tgt->addresses,
69                                in_cred->authdata,
70                                0,               /* no padata */
71                                0,               /* no second ticket */
72                                tgt, &tgsrep))
73         goto error_5;
74
75     switch (tgsrep.message_type) {
76     case KRB5_TGS_REP:
77         break;
78     case KRB5_ERROR:
79     default:
80         if (krb5_is_krb_error(&tgsrep.response))
81             retval = decode_krb5_error(&tgsrep.response, &err_reply);
82         else
83             retval = KRB5KRB_AP_ERR_MSG_TYPE;
84
85         if (retval)                     /* neither proper reply nor error! */
86             goto error_4;
87
88 #if 0
89         /* XXX need access to the actual assembled request...
90            need a change to send_tgs */
91         if ((err_reply->ctime != request.ctime) ||
92             !krb5_principal_compare(context, err_reply->server, request.server) ||
93             !krb5_principal_compare(context, err_reply->client, request.client))
94             retval = KRB5_KDCREP_MODIFIED;
95         else
96 #endif
97             retval = err_reply->error + ERROR_TABLE_BASE_krb5;
98
99         krb5_free_error(context, err_reply);
100         goto error_4;
101     }
102
103     if (retval = krb5_decode_kdc_rep(context, &tgsrep.response, &tgt->keyblock,
104                                      tgt->keyblock.etype, &dec_rep))
105         goto error_4;
106
107     if (dec_rep->msg_type != KRB5_TGS_REP) {
108         retval = KRB5KRB_AP_ERR_MSG_TYPE;
109         goto error_3;
110     }
111     
112     /* now it's decrypted and ready for prime time */
113     if (!krb5_principal_compare(context, dec_rep->client, tgt->client)) {
114         retval = KRB5_KDCREP_MODIFIED;
115         goto error_3;
116     }
117
118     /* get a cred structure */
119     /* The caller is responsible for cleaning up */
120     if (((*out_cred) = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) {
121         retval = ENOMEM;
122         goto error_2;
123     }
124     memset((*out_cred), 0, sizeof(krb5_creds));
125
126     /* Copy the client straigt from in_cred */
127     if (retval = krb5_copy_principal(context, in_cred->client, 
128                                      &(*out_cred)->client)) {
129         goto error_2;
130     }
131
132     /* put pieces into out_cred-> */
133     if (retval = krb5_copy_keyblock_contents(context, 
134                                              dec_rep->enc_part2->session,
135                                              &(*out_cred)->keyblock)) {
136         goto error_2;
137     }
138
139     (*out_cred)->keyblock.etype = dec_rep->ticket->enc_part.etype;
140     (*out_cred)->times = dec_rep->enc_part2->times;
141
142 #if 0
143     /* XXX probably need access to the request */
144     /* check the contents for sanity: */
145     if (!krb5_principal_compare(context, dec_rep->client, request.client)
146         || !krb5_principal_compare(context, dec_rep->enc_part2->server, request.server)
147         || !krb5_principal_compare(context, dec_rep->ticket->server, request.server)
148         || (request.nonce != dec_rep->enc_part2->nonce)
149         /* XXX check for extraneous flags */
150         /* XXX || (!krb5_addresses_compare(context, addrs, dec_rep->enc_part2->caddrs)) */
151         || ((request.from != 0) &&
152             (request.from != dec_rep->enc_part2->times.starttime))
153         || ((request.till != 0) &&
154             (dec_rep->enc_part2->times.endtime > request.till))
155         || ((request.kdc_options & KDC_OPT_RENEWABLE) &&
156             (request.rtime != 0) &&
157             (dec_rep->enc_part2->times.renew_till > request.rtime))
158         || ((request.kdc_options & KDC_OPT_RENEWABLE_OK) &&
159             (dec_rep->enc_part2->flags & KDC_OPT_RENEWABLE) &&
160             (request.till != 0) &&
161             (dec_rep->enc_part2->times.renew_till > request.till))
162         )
163         retval = KRB5_KDCREP_MODIFIED;
164
165     if (!request.from && !in_clock_skew(dec_rep->enc_part2->times.starttime)) {
166         retval = KRB5_KDCREP_SKEW;
167         goto error_1;
168     }
169     
170 #endif
171
172     (*out_cred)->ticket_flags = dec_rep->enc_part2->flags;
173     (*out_cred)->is_skey = FALSE;
174     if (dec_rep->enc_part2->caddrs) {
175         if (retval = krb5_copy_addresses(context, dec_rep->enc_part2->caddrs,
176                                          &(*out_cred)->addresses)) {
177             goto error_1;
178         }
179     } else {
180         /* no addresses in the list means we got what we had */
181         if (retval = krb5_copy_addresses(context, tgt->addresses,
182                                          &(*out_cred)->addresses)) {
183             goto error_1;
184         }
185     }
186     if (retval = krb5_copy_principal(context, dec_rep->enc_part2->server,
187                                      &(*out_cred)->server)) {
188         goto error_1;
189     }
190
191     if (retval = encode_krb5_ticket(dec_rep->ticket, &scratch)) {
192         krb5_free_addresses(context, (*out_cred)->addresses);
193         goto error_1;
194     }
195
196     (*out_cred)->ticket = *scratch;
197     krb5_xfree(scratch);
198
199 error_1:;
200     if (retval)
201         memset((*out_cred)->keyblock.contents, 0, (*out_cred)->keyblock.length);
202
203 error_2:;
204     if (retval)
205         krb5_free_creds(context, *out_cred);
206
207 error_3:;
208     memset(dec_rep->enc_part2->session->contents, 0,
209            dec_rep->enc_part2->session->length);
210     krb5_free_kdc_rep(context, dec_rep);
211
212 error_4:;
213     free(tgsrep.response.data);
214
215 error_5:;
216     krb5_free_principal(context, tempprinc);
217     return retval;
218 }