get_in_tkt.c (krb5_get_in_tkt): If kdc_settime is enabled, then set
[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 extern krb5_deltat krb5_clockskew;
32 #define in_clock_skew(date, now) (labs((date)-(now)) < krb5_clockskew)
33
34 static krb5_error_code
35 krb5_kdcrep2creds(context, pkdcrep, address, psectkt, ppcreds)
36     krb5_context          context;
37     krb5_kdc_rep        * pkdcrep;
38     krb5_address *const * address;
39     krb5_data           * psectkt;
40     krb5_creds         ** ppcreds;
41 {
42     krb5_error_code retval;  
43     krb5_data *pdata;
44   
45     if ((*ppcreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) {
46         return ENOMEM;
47     }
48
49     memset(*ppcreds, 0, sizeof(krb5_creds));
50
51     if ((retval = krb5_copy_principal(context, pkdcrep->client,
52                                      &(*ppcreds)->client)))
53         goto cleanup;
54
55     if ((retval = krb5_copy_principal(context, pkdcrep->enc_part2->server,
56                                      &(*ppcreds)->server)))
57         goto cleanup;
58
59     if ((retval = krb5_copy_keyblock_contents(context, 
60                                               pkdcrep->enc_part2->session,
61                                               &(*ppcreds)->keyblock)))
62         goto cleanup;
63
64     if ((retval = krb5_copy_data(context, psectkt, &pdata)))
65         goto cleanup;
66     (*ppcreds)->second_ticket = *pdata;
67     krb5_xfree(pdata);
68
69     (*ppcreds)->keyblock.etype = pkdcrep->ticket->enc_part.etype;
70     (*ppcreds)->ticket_flags = pkdcrep->enc_part2->flags;
71     (*ppcreds)->times = pkdcrep->enc_part2->times;
72     (*ppcreds)->magic = KV5M_CREDS;
73
74     (*ppcreds)->authdata = NULL;                        /* not used */
75     (*ppcreds)->is_skey = 0;                            /* not used */
76
77     if (pkdcrep->enc_part2->caddrs) {
78         if ((retval = krb5_copy_addresses(context, pkdcrep->enc_part2->caddrs,
79                                           &(*ppcreds)->addresses)))
80             goto cleanup_keyblock;
81     } else {
82         /* no addresses in the list means we got what we had */
83         if ((retval = krb5_copy_addresses(context, address,
84                                           &(*ppcreds)->addresses)))
85             goto cleanup_keyblock;
86     }
87
88     if ((retval = encode_krb5_ticket(pkdcrep->ticket, &pdata)))
89         goto cleanup_keyblock;
90
91     (*ppcreds)->ticket = *pdata;
92     return 0;
93
94 cleanup_keyblock:
95     krb5_free_keyblock(context, &(*ppcreds)->keyblock);
96
97 cleanup:
98     free (*ppcreds);
99     return retval;
100 }
101  
102 krb5_error_code INTERFACE
103 krb5_get_cred_via_tkt (context, tkt, kdcoptions, address, in_cred, out_cred)
104     krb5_context          context;
105     krb5_creds          * tkt;
106     const krb5_flags      kdcoptions;
107     krb5_address *const * address;
108     krb5_creds          * in_cred;
109     krb5_creds         ** out_cred;
110 {
111     krb5_error_code retval;
112     krb5_kdc_rep *dec_rep;
113     krb5_error *err_reply;
114     krb5_response tgsrep;
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 ((retval = krb5_send_tgs(context, kdcoptions, &in_cred->times, NULL, 
148                                 in_cred->server, address, in_cred->authdata,
149                                 0,              /* no padata */
150                                 (kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) ? 
151                                 &in_cred->second_ticket : NULL,
152                                 tkt, &tgsrep)))
153         return retval;
154
155     switch (tgsrep.message_type) {
156     case KRB5_TGS_REP:
157         break;
158     case KRB5_ERROR:
159     default:
160         if (krb5_is_krb_error(&tgsrep.response))
161             retval = decode_krb5_error(&tgsrep.response, &err_reply);
162         else
163             retval = KRB5KRB_AP_ERR_MSG_TYPE;
164
165         if (retval)                     /* neither proper reply nor error! */
166             goto error_4;
167
168         retval = err_reply->error + ERROR_TABLE_BASE_krb5;
169
170         krb5_free_error(context, err_reply);
171         goto error_4;
172     }
173
174     if ((retval = krb5_decode_kdc_rep(context, &tgsrep.response,
175                                       &tkt->keyblock,
176                                       tkt->keyblock.etype, &dec_rep)))
177         goto error_4;
178
179     if (dec_rep->msg_type != KRB5_TGS_REP) {
180         retval = KRB5KRB_AP_ERR_MSG_TYPE;
181         goto error_3;
182     }
183     
184     /* make sure the response hasn't been tampered with..... */
185     if (!krb5_principal_compare(context, dec_rep->client, tkt->client) ||
186         !krb5_principal_compare(context, dec_rep->enc_part2->server,
187                                 in_cred->server) ||
188         !krb5_principal_compare(context, dec_rep->ticket->server,
189                                 in_cred->server) ||
190         (dec_rep->enc_part2->nonce != tgsrep.expected_nonce) ||
191         ((in_cred->times.starttime != 0) &&
192          (in_cred->times.starttime != dec_rep->enc_part2->times.starttime)) ||
193         ((in_cred->times.endtime != 0) &&
194          (dec_rep->enc_part2->times.endtime > in_cred->times.endtime)) ||
195         ((kdcoptions & KDC_OPT_RENEWABLE) &&
196          (in_cred->times.renew_till != 0) &&
197          (dec_rep->enc_part2->times.renew_till > in_cred->times.renew_till)) ||
198         ((kdcoptions & KDC_OPT_RENEWABLE_OK) &&
199          (dec_rep->enc_part2->flags & KDC_OPT_RENEWABLE) &&
200          (in_cred->times.endtime != 0) &&
201          (dec_rep->enc_part2->times.renew_till > in_cred->times.endtime))
202         ) {
203         retval = KRB5_KDCREP_MODIFIED;
204         goto error_3;
205     }
206
207     if (!in_cred->times.starttime &&
208         !in_clock_skew(dec_rep->enc_part2->times.starttime,
209                        tgsrep.request_time)) {
210         retval = KRB5_KDCREP_SKEW;
211         goto error_3;
212     }
213     
214     retval = krb5_kdcrep2creds(context, dec_rep, address, 
215                                &in_cred->second_ticket,  out_cred);
216
217 error_3:;
218     memset(dec_rep->enc_part2->session->contents, 0,
219            dec_rep->enc_part2->session->length);
220     krb5_free_kdc_rep(context, dec_rep);
221
222 error_4:;
223     free(tgsrep.response.data);
224     return retval;
225 }