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