2 * lib/krb5/krb/gc_via_tgt.c
4 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
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.
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.
24 * Given a tkt, and a target cred, get it.
25 * Assumes that the kdc_rep has been decrypted.
29 #include "int-proto.h"
31 #define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew)
33 static krb5_error_code
34 krb5_kdcrep2creds(context, pkdcrep, address, psectkt, ppcreds)
36 krb5_kdc_rep * pkdcrep;
37 krb5_address *const * address;
39 krb5_creds ** ppcreds;
41 krb5_error_code retval;
44 if ((*ppcreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) {
48 memset(*ppcreds, 0, sizeof(krb5_creds));
50 if ((retval = krb5_copy_principal(context, pkdcrep->client,
51 &(*ppcreds)->client)))
54 if ((retval = krb5_copy_principal(context, pkdcrep->enc_part2->server,
55 &(*ppcreds)->server)))
58 if ((retval = krb5_copy_keyblock_contents(context,
59 pkdcrep->enc_part2->session,
60 &(*ppcreds)->keyblock)))
63 if ((retval = krb5_copy_data(context, psectkt, &pdata)))
65 (*ppcreds)->second_ticket = *pdata;
68 (*ppcreds)->ticket_flags = pkdcrep->enc_part2->flags;
69 (*ppcreds)->times = pkdcrep->enc_part2->times;
70 (*ppcreds)->magic = KV5M_CREDS;
72 (*ppcreds)->authdata = NULL; /* not used */
73 (*ppcreds)->is_skey = psectkt->length != 0;
75 if (pkdcrep->enc_part2->caddrs) {
76 if ((retval = krb5_copy_addresses(context, pkdcrep->enc_part2->caddrs,
77 &(*ppcreds)->addresses)))
78 goto cleanup_keyblock;
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;
86 if ((retval = encode_krb5_ticket(pkdcrep->ticket, &pdata)))
87 goto cleanup_keyblock;
89 (*ppcreds)->ticket = *pdata;
94 krb5_free_keyblock(context, &(*ppcreds)->keyblock);
101 krb5_error_code INTERFACE
102 krb5_get_cred_via_tkt (context, tkt, kdcoptions, address, in_cred, out_cred)
103 krb5_context context;
105 const krb5_flags kdcoptions;
106 krb5_address *const * address;
107 krb5_creds * in_cred;
108 krb5_creds ** out_cred;
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;
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;
120 if (!tkt->ticket.length)
121 return KRB5_NO_TKT_SUPPLIED;
123 if ((kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) &&
124 (!in_cred->second_ticket.length))
125 return(KRB5_NO_2ND_TKT);
128 /* check if we have the right TGT */
129 /* tkt->server must be equal to */
130 /* krbtgt/realmof(cred->server)@realmof(tgt->server) */
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))
139 if (!krb5_principal_compare(context, tempprinc, tkt->server)) {
140 krb5_free_principal(context, tempprinc);
141 return (KRB5_PRINC_NOMATCH);
143 krb5_free_principal(context, tempprinc);
147 if (in_cred->keyblock.enctype) {
148 enctypes = (krb5_enctype *) malloc(sizeof(krb5_enctype)*2);
151 enctypes[0] = in_cred->keyblock.enctype;
155 retval = krb5_send_tgs(context, kdcoptions, &in_cred->times, enctypes,
156 in_cred->server, address, in_cred->authdata,
158 (kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) ?
159 &in_cred->second_ticket : NULL,
166 switch (tgsrep.message_type) {
171 if (krb5_is_krb_error(&tgsrep.response))
172 retval = decode_krb5_error(&tgsrep.response, &err_reply);
174 retval = KRB5KRB_AP_ERR_MSG_TYPE;
176 if (retval) /* neither proper reply nor error! */
179 retval = err_reply->error + ERROR_TABLE_BASE_krb5;
181 krb5_free_error(context, err_reply);
185 if ((retval = krb5_decode_kdc_rep(context, &tgsrep.response,
186 &tkt->keyblock, &dec_rep)))
189 if (dec_rep->msg_type != KRB5_TGS_REP) {
190 retval = KRB5KRB_AP_ERR_MSG_TYPE;
194 /* make sure the response hasn't been tampered with..... */
197 if (!krb5_principal_compare(context, dec_rep->client, tkt->client))
198 retval = KRB5_KDCREP_MODIFIED;
200 if (!krb5_principal_compare(context, dec_rep->enc_part2->server, in_cred->server))
201 retval = KRB5_KDCREP_MODIFIED;
203 if (!krb5_principal_compare(context, dec_rep->ticket->server, in_cred->server))
204 retval = KRB5_KDCREP_MODIFIED;
206 if (dec_rep->enc_part2->nonce != tgsrep.expected_nonce)
207 retval = KRB5_KDCREP_MODIFIED;
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;
214 if ((in_cred->times.endtime != 0) &&
215 (dec_rep->enc_part2->times.endtime > in_cred->times.endtime))
216 retval = KRB5_KDCREP_MODIFIED;
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;
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;
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;
239 retval = krb5_kdcrep2creds(context, dec_rep, address,
240 &in_cred->second_ticket, out_cred);
243 memset(dec_rep->enc_part2->session->contents, 0,
244 dec_rep->enc_part2->session->length);
245 krb5_free_kdc_rep(context, dec_rep);
248 free(tgsrep.response.data);