xref: /freebsd/crypto/heimdal/lib/krb5/ticket.c (revision ae77177087c655fc883075af4f425b37e032cd05)
1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov  * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6*ae771770SStanislav Sedov  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7*ae771770SStanislav Sedov  *
8b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
9b528cefcSMark Murray  * modification, are permitted provided that the following conditions
10b528cefcSMark Murray  * are met:
11b528cefcSMark Murray  *
12b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
13b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
14b528cefcSMark Murray  *
15b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
16b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
17b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
18b528cefcSMark Murray  *
19b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
20b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
21b528cefcSMark Murray  *    without specific prior written permission.
22b528cefcSMark Murray  *
23b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33b528cefcSMark Murray  * SUCH DAMAGE.
34b528cefcSMark Murray  */
35b528cefcSMark Murray 
36b528cefcSMark Murray #include "krb5_locl.h"
37b528cefcSMark Murray 
38*ae771770SStanislav Sedov /**
39*ae771770SStanislav Sedov  * Free ticket and content
40*ae771770SStanislav Sedov  *
41*ae771770SStanislav Sedov  * @param context a Kerberos 5 context
42*ae771770SStanislav Sedov  * @param ticket ticket to free
43*ae771770SStanislav Sedov  *
44*ae771770SStanislav Sedov  * @return Returns 0 to indicate success.  Otherwise an kerberos et
45*ae771770SStanislav Sedov  * error code is returned, see krb5_get_error_message().
46*ae771770SStanislav Sedov  *
47*ae771770SStanislav Sedov  * @ingroup krb5
48*ae771770SStanislav Sedov  */
49b528cefcSMark Murray 
50*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
51b528cefcSMark Murray krb5_free_ticket(krb5_context context,
52b528cefcSMark Murray 		 krb5_ticket *ticket)
53b528cefcSMark Murray {
54b528cefcSMark Murray     free_EncTicketPart(&ticket->ticket);
55b528cefcSMark Murray     krb5_free_principal(context, ticket->client);
56b528cefcSMark Murray     krb5_free_principal(context, ticket->server);
57c19800e8SDoug Rabson     free(ticket);
58b528cefcSMark Murray     return 0;
59b528cefcSMark Murray }
60b528cefcSMark Murray 
61*ae771770SStanislav Sedov /**
62*ae771770SStanislav Sedov  * Copy ticket and content
63*ae771770SStanislav Sedov  *
64*ae771770SStanislav Sedov  * @param context a Kerberos 5 context
65*ae771770SStanislav Sedov  * @param from ticket to copy
66*ae771770SStanislav Sedov  * @param to new copy of ticket, free with krb5_free_ticket()
67*ae771770SStanislav Sedov  *
68*ae771770SStanislav Sedov  * @return Returns 0 to indicate success.  Otherwise an kerberos et
69*ae771770SStanislav Sedov  * error code is returned, see krb5_get_error_message().
70*ae771770SStanislav Sedov  *
71*ae771770SStanislav Sedov  * @ingroup krb5
72*ae771770SStanislav Sedov  */
73*ae771770SStanislav Sedov 
74*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
75b528cefcSMark Murray krb5_copy_ticket(krb5_context context,
76b528cefcSMark Murray 		 const krb5_ticket *from,
77b528cefcSMark Murray 		 krb5_ticket **to)
78b528cefcSMark Murray {
79b528cefcSMark Murray     krb5_error_code ret;
801c43270aSJacques Vidrine     krb5_ticket *tmp;
811c43270aSJacques Vidrine 
821c43270aSJacques Vidrine     *to = NULL;
831c43270aSJacques Vidrine     tmp = malloc(sizeof(*tmp));
84adb0ddaeSAssar Westerlund     if(tmp == NULL) {
85*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
86*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
87b528cefcSMark Murray 	return ENOMEM;
88adb0ddaeSAssar Westerlund     }
89b528cefcSMark Murray     if((ret = copy_EncTicketPart(&from->ticket, &tmp->ticket))){
90b528cefcSMark Murray 	free(tmp);
91b528cefcSMark Murray 	return ret;
92b528cefcSMark Murray     }
93b528cefcSMark Murray     ret = krb5_copy_principal(context, from->client, &tmp->client);
94b528cefcSMark Murray     if(ret){
95b528cefcSMark Murray 	free_EncTicketPart(&tmp->ticket);
961c43270aSJacques Vidrine 	free(tmp);
97b528cefcSMark Murray 	return ret;
98b528cefcSMark Murray     }
991c43270aSJacques Vidrine     ret = krb5_copy_principal(context, from->server, &tmp->server);
100b528cefcSMark Murray     if(ret){
101b528cefcSMark Murray 	krb5_free_principal(context, tmp->client);
102b528cefcSMark Murray 	free_EncTicketPart(&tmp->ticket);
1031c43270aSJacques Vidrine 	free(tmp);
104b528cefcSMark Murray 	return ret;
105b528cefcSMark Murray     }
106b528cefcSMark Murray     *to = tmp;
107b528cefcSMark Murray     return 0;
108b528cefcSMark Murray }
109c19800e8SDoug Rabson 
110*ae771770SStanislav Sedov /**
111*ae771770SStanislav Sedov  * Return client principal in ticket
112*ae771770SStanislav Sedov  *
113*ae771770SStanislav Sedov  * @param context a Kerberos 5 context
114*ae771770SStanislav Sedov  * @param ticket ticket to copy
115*ae771770SStanislav Sedov  * @param client client principal, free with krb5_free_principal()
116*ae771770SStanislav Sedov  *
117*ae771770SStanislav Sedov  * @return Returns 0 to indicate success.  Otherwise an kerberos et
118*ae771770SStanislav Sedov  * error code is returned, see krb5_get_error_message().
119*ae771770SStanislav Sedov  *
120*ae771770SStanislav Sedov  * @ingroup krb5
121*ae771770SStanislav Sedov  */
122*ae771770SStanislav Sedov 
123*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
124c19800e8SDoug Rabson krb5_ticket_get_client(krb5_context context,
125c19800e8SDoug Rabson 		       const krb5_ticket *ticket,
126c19800e8SDoug Rabson 		       krb5_principal *client)
127c19800e8SDoug Rabson {
128c19800e8SDoug Rabson     return krb5_copy_principal(context, ticket->client, client);
129c19800e8SDoug Rabson }
130c19800e8SDoug Rabson 
131*ae771770SStanislav Sedov /**
132*ae771770SStanislav Sedov  * Return server principal in ticket
133*ae771770SStanislav Sedov  *
134*ae771770SStanislav Sedov  * @param context a Kerberos 5 context
135*ae771770SStanislav Sedov  * @param ticket ticket to copy
136*ae771770SStanislav Sedov  * @param server server principal, free with krb5_free_principal()
137*ae771770SStanislav Sedov  *
138*ae771770SStanislav Sedov  * @return Returns 0 to indicate success.  Otherwise an kerberos et
139*ae771770SStanislav Sedov  * error code is returned, see krb5_get_error_message().
140*ae771770SStanislav Sedov  *
141*ae771770SStanislav Sedov  * @ingroup krb5
142*ae771770SStanislav Sedov  */
143*ae771770SStanislav Sedov 
144*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
145c19800e8SDoug Rabson krb5_ticket_get_server(krb5_context context,
146c19800e8SDoug Rabson 		       const krb5_ticket *ticket,
147c19800e8SDoug Rabson 		       krb5_principal *server)
148c19800e8SDoug Rabson {
149c19800e8SDoug Rabson     return krb5_copy_principal(context, ticket->server, server);
150c19800e8SDoug Rabson }
151c19800e8SDoug Rabson 
152*ae771770SStanislav Sedov /**
153*ae771770SStanislav Sedov  * Return end time of ticket
154*ae771770SStanislav Sedov  *
155*ae771770SStanislav Sedov  * @param context a Kerberos 5 context
156*ae771770SStanislav Sedov  * @param ticket ticket to copy
157*ae771770SStanislav Sedov  *
158*ae771770SStanislav Sedov  * @return end time of ticket
159*ae771770SStanislav Sedov  *
160*ae771770SStanislav Sedov  * @ingroup krb5
161*ae771770SStanislav Sedov  */
162*ae771770SStanislav Sedov 
163*ae771770SStanislav Sedov KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL
164c19800e8SDoug Rabson krb5_ticket_get_endtime(krb5_context context,
165c19800e8SDoug Rabson 			const krb5_ticket *ticket)
166c19800e8SDoug Rabson {
167c19800e8SDoug Rabson     return ticket->ticket.endtime;
168c19800e8SDoug Rabson }
169c19800e8SDoug Rabson 
170*ae771770SStanislav Sedov /**
171*ae771770SStanislav Sedov  * Get the flags from the Kerberos ticket
172*ae771770SStanislav Sedov  *
173*ae771770SStanislav Sedov  * @param context Kerberos context
174*ae771770SStanislav Sedov  * @param ticket Kerberos ticket
175*ae771770SStanislav Sedov  *
176*ae771770SStanislav Sedov  * @return ticket flags
177*ae771770SStanislav Sedov  *
178*ae771770SStanislav Sedov  * @ingroup krb5_ticket
179*ae771770SStanislav Sedov  */
180*ae771770SStanislav Sedov KRB5_LIB_FUNCTION unsigned long KRB5_LIB_CALL
181*ae771770SStanislav Sedov krb5_ticket_get_flags(krb5_context context,
182*ae771770SStanislav Sedov 		      const krb5_ticket *ticket)
183*ae771770SStanislav Sedov {
184*ae771770SStanislav Sedov     return TicketFlags2int(ticket->ticket.flags);
185*ae771770SStanislav Sedov }
186*ae771770SStanislav Sedov 
187c19800e8SDoug Rabson static int
188c19800e8SDoug Rabson find_type_in_ad(krb5_context context,
189c19800e8SDoug Rabson 		int type,
190c19800e8SDoug Rabson 		krb5_data *data,
191c19800e8SDoug Rabson 		krb5_boolean *found,
192c19800e8SDoug Rabson 		krb5_boolean failp,
193c19800e8SDoug Rabson 		krb5_keyblock *sessionkey,
194c19800e8SDoug Rabson 		const AuthorizationData *ad,
195c19800e8SDoug Rabson 		int level)
196c19800e8SDoug Rabson {
197c19800e8SDoug Rabson     krb5_error_code ret = 0;
198*ae771770SStanislav Sedov     size_t i;
199c19800e8SDoug Rabson 
200c19800e8SDoug Rabson     if (level > 9) {
201c19800e8SDoug Rabson 	ret = ENOENT; /* XXX */
202*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
203*ae771770SStanislav Sedov 			       N_("Authorization data nested deeper "
204*ae771770SStanislav Sedov 				  "then %d levels, stop searching", ""),
205*ae771770SStanislav Sedov 			       level);
206c19800e8SDoug Rabson 	goto out;
207c19800e8SDoug Rabson     }
208c19800e8SDoug Rabson 
209c19800e8SDoug Rabson     /*
210c19800e8SDoug Rabson      * Only copy out the element the first time we get to it, we need
211c19800e8SDoug Rabson      * to run over the whole authorization data fields to check if
212c19800e8SDoug Rabson      * there are any container clases we need to care about.
213c19800e8SDoug Rabson      */
214c19800e8SDoug Rabson     for (i = 0; i < ad->len; i++) {
215c19800e8SDoug Rabson 	if (!*found && ad->val[i].ad_type == type) {
216c19800e8SDoug Rabson 	    ret = der_copy_octet_string(&ad->val[i].ad_data, data);
217c19800e8SDoug Rabson 	    if (ret) {
218*ae771770SStanislav Sedov 		krb5_set_error_message(context, ret,
219*ae771770SStanislav Sedov 				       N_("malloc: out of memory", ""));
220c19800e8SDoug Rabson 		goto out;
221c19800e8SDoug Rabson 	    }
222c19800e8SDoug Rabson 	    *found = TRUE;
223c19800e8SDoug Rabson 	    continue;
224c19800e8SDoug Rabson 	}
225c19800e8SDoug Rabson 	switch (ad->val[i].ad_type) {
226c19800e8SDoug Rabson 	case KRB5_AUTHDATA_IF_RELEVANT: {
227c19800e8SDoug Rabson 	    AuthorizationData child;
228c19800e8SDoug Rabson 	    ret = decode_AuthorizationData(ad->val[i].ad_data.data,
229c19800e8SDoug Rabson 					   ad->val[i].ad_data.length,
230c19800e8SDoug Rabson 					   &child,
231c19800e8SDoug Rabson 					   NULL);
232c19800e8SDoug Rabson 	    if (ret) {
233*ae771770SStanislav Sedov 		krb5_set_error_message(context, ret,
234*ae771770SStanislav Sedov 				       N_("Failed to decode "
235*ae771770SStanislav Sedov 					  "IF_RELEVANT with %d", ""),
236*ae771770SStanislav Sedov 				       (int)ret);
237c19800e8SDoug Rabson 		goto out;
238c19800e8SDoug Rabson 	    }
239c19800e8SDoug Rabson 	    ret = find_type_in_ad(context, type, data, found, FALSE,
240c19800e8SDoug Rabson 				  sessionkey, &child, level + 1);
241c19800e8SDoug Rabson 	    free_AuthorizationData(&child);
242c19800e8SDoug Rabson 	    if (ret)
243c19800e8SDoug Rabson 		goto out;
244c19800e8SDoug Rabson 	    break;
245c19800e8SDoug Rabson 	}
246c19800e8SDoug Rabson #if 0 /* XXX test */
247c19800e8SDoug Rabson 	case KRB5_AUTHDATA_KDC_ISSUED: {
248c19800e8SDoug Rabson 	    AD_KDCIssued child;
249c19800e8SDoug Rabson 
250c19800e8SDoug Rabson 	    ret = decode_AD_KDCIssued(ad->val[i].ad_data.data,
251c19800e8SDoug Rabson 				      ad->val[i].ad_data.length,
252c19800e8SDoug Rabson 				      &child,
253c19800e8SDoug Rabson 				      NULL);
254c19800e8SDoug Rabson 	    if (ret) {
255*ae771770SStanislav Sedov 		krb5_set_error_message(context, ret,
256*ae771770SStanislav Sedov 				       N_("Failed to decode "
257*ae771770SStanislav Sedov 					  "AD_KDCIssued with %d", ""),
258*ae771770SStanislav Sedov 				       ret);
259c19800e8SDoug Rabson 		goto out;
260c19800e8SDoug Rabson 	    }
261c19800e8SDoug Rabson 	    if (failp) {
262c19800e8SDoug Rabson 		krb5_boolean valid;
263c19800e8SDoug Rabson 		krb5_data buf;
264c19800e8SDoug Rabson 		size_t len;
265c19800e8SDoug Rabson 
266c19800e8SDoug Rabson 		ASN1_MALLOC_ENCODE(AuthorizationData, buf.data, buf.length,
267c19800e8SDoug Rabson 				   &child.elements, &len, ret);
268c19800e8SDoug Rabson 		if (ret) {
269c19800e8SDoug Rabson 		    free_AD_KDCIssued(&child);
270*ae771770SStanislav Sedov 		    krb5_clear_error_message(context);
271c19800e8SDoug Rabson 		    goto out;
272c19800e8SDoug Rabson 		}
273c19800e8SDoug Rabson 		if(buf.length != len)
274c19800e8SDoug Rabson 		    krb5_abortx(context, "internal error in ASN.1 encoder");
275c19800e8SDoug Rabson 
276c19800e8SDoug Rabson 		ret = krb5_c_verify_checksum(context, sessionkey, 19, &buf,
277c19800e8SDoug Rabson 					     &child.ad_checksum, &valid);
278c19800e8SDoug Rabson 		krb5_data_free(&buf);
279c19800e8SDoug Rabson 		if (ret) {
280c19800e8SDoug Rabson 		    free_AD_KDCIssued(&child);
281c19800e8SDoug Rabson 		    goto out;
282c19800e8SDoug Rabson 		}
283c19800e8SDoug Rabson 		if (!valid) {
284*ae771770SStanislav Sedov 		    krb5_clear_error_message(context);
285c19800e8SDoug Rabson 		    ret = ENOENT;
286c19800e8SDoug Rabson 		    free_AD_KDCIssued(&child);
287c19800e8SDoug Rabson 		    goto out;
288c19800e8SDoug Rabson 		}
289c19800e8SDoug Rabson 	    }
290c19800e8SDoug Rabson 	    ret = find_type_in_ad(context, type, data, found, failp, sessionkey,
291c19800e8SDoug Rabson 				  &child.elements, level + 1);
292c19800e8SDoug Rabson 	    free_AD_KDCIssued(&child);
293c19800e8SDoug Rabson 	    if (ret)
294c19800e8SDoug Rabson 		goto out;
295c19800e8SDoug Rabson 	    break;
296c19800e8SDoug Rabson 	}
297c19800e8SDoug Rabson #endif
298c19800e8SDoug Rabson 	case KRB5_AUTHDATA_AND_OR:
299c19800e8SDoug Rabson 	    if (!failp)
300c19800e8SDoug Rabson 		break;
301c19800e8SDoug Rabson 	    ret = ENOENT; /* XXX */
302*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
303*ae771770SStanislav Sedov 				   N_("Authorization data contains "
304*ae771770SStanislav Sedov 				      "AND-OR element that is unknown to the "
305*ae771770SStanislav Sedov 				      "application", ""));
306c19800e8SDoug Rabson 	    goto out;
307c19800e8SDoug Rabson 	default:
308c19800e8SDoug Rabson 	    if (!failp)
309c19800e8SDoug Rabson 		break;
310c19800e8SDoug Rabson 	    ret = ENOENT; /* XXX */
311*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
312*ae771770SStanislav Sedov 				   N_("Authorization data contains "
313*ae771770SStanislav Sedov 				      "unknown type (%d) ", ""),
314*ae771770SStanislav Sedov 				   ad->val[i].ad_type);
315c19800e8SDoug Rabson 	    goto out;
316c19800e8SDoug Rabson 	}
317c19800e8SDoug Rabson     }
318c19800e8SDoug Rabson out:
319c19800e8SDoug Rabson     if (ret) {
320c19800e8SDoug Rabson 	if (*found) {
321c19800e8SDoug Rabson 	    krb5_data_free(data);
322c19800e8SDoug Rabson 	    *found = 0;
323c19800e8SDoug Rabson 	}
324c19800e8SDoug Rabson     }
325c19800e8SDoug Rabson     return ret;
326c19800e8SDoug Rabson }
327c19800e8SDoug Rabson 
328*ae771770SStanislav Sedov /**
329*ae771770SStanislav Sedov  * Extract the authorization data type of type from the ticket. Store
330*ae771770SStanislav Sedov  * the field in data. This function is to use for kerberos
331*ae771770SStanislav Sedov  * applications.
332*ae771770SStanislav Sedov  *
333*ae771770SStanislav Sedov  * @param context a Kerberos 5 context
334*ae771770SStanislav Sedov  * @param ticket Kerberos ticket
335*ae771770SStanislav Sedov  * @param type type to fetch
336*ae771770SStanislav Sedov  * @param data returned data, free with krb5_data_free()
337*ae771770SStanislav Sedov  *
338*ae771770SStanislav Sedov  * @ingroup krb5
339c19800e8SDoug Rabson  */
340c19800e8SDoug Rabson 
341*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
342c19800e8SDoug Rabson krb5_ticket_get_authorization_data_type(krb5_context context,
343c19800e8SDoug Rabson 					krb5_ticket *ticket,
344c19800e8SDoug Rabson 					int type,
345c19800e8SDoug Rabson 					krb5_data *data)
346c19800e8SDoug Rabson {
347c19800e8SDoug Rabson     AuthorizationData *ad;
348c19800e8SDoug Rabson     krb5_error_code ret;
349c19800e8SDoug Rabson     krb5_boolean found = FALSE;
350c19800e8SDoug Rabson 
351c19800e8SDoug Rabson     krb5_data_zero(data);
352c19800e8SDoug Rabson 
353c19800e8SDoug Rabson     ad = ticket->ticket.authorization_data;
354c19800e8SDoug Rabson     if (ticket->ticket.authorization_data == NULL) {
355*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOENT,
356*ae771770SStanislav Sedov 			       N_("Ticket have not authorization data", ""));
357c19800e8SDoug Rabson 	return ENOENT; /* XXX */
358c19800e8SDoug Rabson     }
359c19800e8SDoug Rabson 
360c19800e8SDoug Rabson     ret = find_type_in_ad(context, type, data, &found, TRUE,
361c19800e8SDoug Rabson 			  &ticket->ticket.key, ad, 0);
362c19800e8SDoug Rabson     if (ret)
363c19800e8SDoug Rabson 	return ret;
364c19800e8SDoug Rabson     if (!found) {
365*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOENT,
366*ae771770SStanislav Sedov 			       N_("Ticket have not "
367*ae771770SStanislav Sedov 				  "authorization data of type %d", ""),
368*ae771770SStanislav Sedov 			       type);
369c19800e8SDoug Rabson 	return ENOENT; /* XXX */
370c19800e8SDoug Rabson     }
371c19800e8SDoug Rabson     return 0;
372c19800e8SDoug Rabson }
373*ae771770SStanislav Sedov 
374*ae771770SStanislav Sedov static krb5_error_code
375*ae771770SStanislav Sedov check_server_referral(krb5_context context,
376*ae771770SStanislav Sedov 		      krb5_kdc_rep *rep,
377*ae771770SStanislav Sedov 		      unsigned flags,
378*ae771770SStanislav Sedov 		      krb5_const_principal requested,
379*ae771770SStanislav Sedov 		      krb5_const_principal returned,
380*ae771770SStanislav Sedov 		      krb5_keyblock * key)
381*ae771770SStanislav Sedov {
382*ae771770SStanislav Sedov     krb5_error_code ret;
383*ae771770SStanislav Sedov     PA_ServerReferralData ref;
384*ae771770SStanislav Sedov     krb5_crypto session;
385*ae771770SStanislav Sedov     EncryptedData ed;
386*ae771770SStanislav Sedov     size_t len;
387*ae771770SStanislav Sedov     krb5_data data;
388*ae771770SStanislav Sedov     PA_DATA *pa;
389*ae771770SStanislav Sedov     int i = 0, cmp;
390*ae771770SStanislav Sedov 
391*ae771770SStanislav Sedov     if (rep->kdc_rep.padata == NULL)
392*ae771770SStanislav Sedov 	goto noreferral;
393*ae771770SStanislav Sedov 
394*ae771770SStanislav Sedov     pa = krb5_find_padata(rep->kdc_rep.padata->val,
395*ae771770SStanislav Sedov 			  rep->kdc_rep.padata->len,
396*ae771770SStanislav Sedov 			  KRB5_PADATA_SERVER_REFERRAL, &i);
397*ae771770SStanislav Sedov     if (pa == NULL)
398*ae771770SStanislav Sedov 	goto noreferral;
399*ae771770SStanislav Sedov 
400*ae771770SStanislav Sedov     memset(&ed, 0, sizeof(ed));
401*ae771770SStanislav Sedov     memset(&ref, 0, sizeof(ref));
402*ae771770SStanislav Sedov 
403*ae771770SStanislav Sedov     ret = decode_EncryptedData(pa->padata_value.data,
404*ae771770SStanislav Sedov 			       pa->padata_value.length,
405*ae771770SStanislav Sedov 			       &ed, &len);
406*ae771770SStanislav Sedov     if (ret)
407*ae771770SStanislav Sedov 	return ret;
408*ae771770SStanislav Sedov     if (len != pa->padata_value.length) {
409*ae771770SStanislav Sedov 	free_EncryptedData(&ed);
410*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
411*ae771770SStanislav Sedov 			       N_("Referral EncryptedData wrong for realm %s",
412*ae771770SStanislav Sedov 				  "realm"), requested->realm);
413*ae771770SStanislav Sedov 	return KRB5KRB_AP_ERR_MODIFIED;
414*ae771770SStanislav Sedov     }
415*ae771770SStanislav Sedov 
416*ae771770SStanislav Sedov     ret = krb5_crypto_init(context, key, 0, &session);
417*ae771770SStanislav Sedov     if (ret) {
418*ae771770SStanislav Sedov 	free_EncryptedData(&ed);
419*ae771770SStanislav Sedov 	return ret;
420*ae771770SStanislav Sedov     }
421*ae771770SStanislav Sedov 
422*ae771770SStanislav Sedov     ret = krb5_decrypt_EncryptedData(context, session,
423*ae771770SStanislav Sedov 				     KRB5_KU_PA_SERVER_REFERRAL,
424*ae771770SStanislav Sedov 				     &ed, &data);
425*ae771770SStanislav Sedov     free_EncryptedData(&ed);
426*ae771770SStanislav Sedov     krb5_crypto_destroy(context, session);
427*ae771770SStanislav Sedov     if (ret)
428*ae771770SStanislav Sedov 	return ret;
429*ae771770SStanislav Sedov 
430*ae771770SStanislav Sedov     ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len);
431*ae771770SStanislav Sedov     if (ret) {
432*ae771770SStanislav Sedov 	krb5_data_free(&data);
433*ae771770SStanislav Sedov 	return ret;
434*ae771770SStanislav Sedov     }
435*ae771770SStanislav Sedov     krb5_data_free(&data);
436*ae771770SStanislav Sedov 
437*ae771770SStanislav Sedov     if (strcmp(requested->realm, returned->realm) != 0) {
438*ae771770SStanislav Sedov 	free_PA_ServerReferralData(&ref);
439*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
440*ae771770SStanislav Sedov 			       N_("server ref realm mismatch, "
441*ae771770SStanislav Sedov 				  "requested realm %s got back %s", ""),
442*ae771770SStanislav Sedov 			       requested->realm, returned->realm);
443*ae771770SStanislav Sedov 	return KRB5KRB_AP_ERR_MODIFIED;
444*ae771770SStanislav Sedov     }
445*ae771770SStanislav Sedov 
446*ae771770SStanislav Sedov     if (krb5_principal_is_krbtgt(context, returned)) {
447*ae771770SStanislav Sedov 	const char *realm = returned->name.name_string.val[1];
448*ae771770SStanislav Sedov 
449*ae771770SStanislav Sedov 	if (ref.referred_realm == NULL
450*ae771770SStanislav Sedov 	    || strcmp(*ref.referred_realm, realm) != 0)
451*ae771770SStanislav Sedov 	{
452*ae771770SStanislav Sedov 	    free_PA_ServerReferralData(&ref);
453*ae771770SStanislav Sedov 	    krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
454*ae771770SStanislav Sedov 				   N_("tgt returned with wrong ref", ""));
455*ae771770SStanislav Sedov 	    return KRB5KRB_AP_ERR_MODIFIED;
456*ae771770SStanislav Sedov 	}
457*ae771770SStanislav Sedov     } else if (krb5_principal_compare(context, returned, requested) == 0) {
458*ae771770SStanislav Sedov 	free_PA_ServerReferralData(&ref);
459*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
460*ae771770SStanislav Sedov 			       N_("req princ no same as returned", ""));
461*ae771770SStanislav Sedov 	return KRB5KRB_AP_ERR_MODIFIED;
462*ae771770SStanislav Sedov     }
463*ae771770SStanislav Sedov 
464*ae771770SStanislav Sedov     if (ref.requested_principal_name) {
465*ae771770SStanislav Sedov 	cmp = _krb5_principal_compare_PrincipalName(context,
466*ae771770SStanislav Sedov 						    requested,
467*ae771770SStanislav Sedov 						    ref.requested_principal_name);
468*ae771770SStanislav Sedov 	if (!cmp) {
469*ae771770SStanislav Sedov 	    free_PA_ServerReferralData(&ref);
470*ae771770SStanislav Sedov 	    krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
471*ae771770SStanislav Sedov 				   N_("referred principal not same "
472*ae771770SStanislav Sedov 				      "as requested", ""));
473*ae771770SStanislav Sedov 	    return KRB5KRB_AP_ERR_MODIFIED;
474*ae771770SStanislav Sedov 	}
475*ae771770SStanislav Sedov     } else if (flags & EXTRACT_TICKET_AS_REQ) {
476*ae771770SStanislav Sedov 	free_PA_ServerReferralData(&ref);
477*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
478*ae771770SStanislav Sedov 			       N_("Requested principal missing on AS-REQ", ""));
479*ae771770SStanislav Sedov 	return KRB5KRB_AP_ERR_MODIFIED;
480*ae771770SStanislav Sedov     }
481*ae771770SStanislav Sedov 
482*ae771770SStanislav Sedov     free_PA_ServerReferralData(&ref);
483*ae771770SStanislav Sedov 
484*ae771770SStanislav Sedov     return ret;
485*ae771770SStanislav Sedov noreferral:
486*ae771770SStanislav Sedov     /*
487*ae771770SStanislav Sedov      * Expect excact match or that we got a krbtgt
488*ae771770SStanislav Sedov      */
489*ae771770SStanislav Sedov     if (krb5_principal_compare(context, requested, returned) != TRUE &&
490*ae771770SStanislav Sedov 	(krb5_realm_compare(context, requested, returned) != TRUE &&
491*ae771770SStanislav Sedov 	 krb5_principal_is_krbtgt(context, returned) != TRUE))
492*ae771770SStanislav Sedov     {
493*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
494*ae771770SStanislav Sedov 			       N_("Not same server principal returned "
495*ae771770SStanislav Sedov 				  "as requested", ""));
496*ae771770SStanislav Sedov 	return KRB5KRB_AP_ERR_MODIFIED;
497*ae771770SStanislav Sedov     }
498*ae771770SStanislav Sedov     return 0;
499*ae771770SStanislav Sedov }
500*ae771770SStanislav Sedov 
501*ae771770SStanislav Sedov 
502*ae771770SStanislav Sedov /*
503*ae771770SStanislav Sedov  * Verify referral data
504*ae771770SStanislav Sedov  */
505*ae771770SStanislav Sedov 
506*ae771770SStanislav Sedov 
507*ae771770SStanislav Sedov static krb5_error_code
508*ae771770SStanislav Sedov check_client_referral(krb5_context context,
509*ae771770SStanislav Sedov 		      krb5_kdc_rep *rep,
510*ae771770SStanislav Sedov 		      krb5_const_principal requested,
511*ae771770SStanislav Sedov 		      krb5_const_principal mapped,
512*ae771770SStanislav Sedov 		      krb5_keyblock const * key)
513*ae771770SStanislav Sedov {
514*ae771770SStanislav Sedov     krb5_error_code ret;
515*ae771770SStanislav Sedov     PA_ClientCanonicalized canon;
516*ae771770SStanislav Sedov     krb5_crypto crypto;
517*ae771770SStanislav Sedov     krb5_data data;
518*ae771770SStanislav Sedov     PA_DATA *pa;
519*ae771770SStanislav Sedov     size_t len;
520*ae771770SStanislav Sedov     int i = 0;
521*ae771770SStanislav Sedov 
522*ae771770SStanislav Sedov     if (rep->kdc_rep.padata == NULL)
523*ae771770SStanislav Sedov 	goto noreferral;
524*ae771770SStanislav Sedov 
525*ae771770SStanislav Sedov     pa = krb5_find_padata(rep->kdc_rep.padata->val,
526*ae771770SStanislav Sedov 			  rep->kdc_rep.padata->len,
527*ae771770SStanislav Sedov 			  KRB5_PADATA_CLIENT_CANONICALIZED, &i);
528*ae771770SStanislav Sedov     if (pa == NULL)
529*ae771770SStanislav Sedov 	goto noreferral;
530*ae771770SStanislav Sedov 
531*ae771770SStanislav Sedov     ret = decode_PA_ClientCanonicalized(pa->padata_value.data,
532*ae771770SStanislav Sedov 					pa->padata_value.length,
533*ae771770SStanislav Sedov 					&canon, &len);
534*ae771770SStanislav Sedov     if (ret) {
535*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
536*ae771770SStanislav Sedov 			       N_("Failed to decode ClientCanonicalized "
537*ae771770SStanislav Sedov 				  "from realm %s", ""), requested->realm);
538*ae771770SStanislav Sedov 	return ret;
539*ae771770SStanislav Sedov     }
540*ae771770SStanislav Sedov 
541*ae771770SStanislav Sedov     ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length,
542*ae771770SStanislav Sedov 		       &canon.names, &len, ret);
543*ae771770SStanislav Sedov     if (ret) {
544*ae771770SStanislav Sedov 	free_PA_ClientCanonicalized(&canon);
545*ae771770SStanislav Sedov 	return ret;
546*ae771770SStanislav Sedov     }
547*ae771770SStanislav Sedov     if (data.length != len)
548*ae771770SStanislav Sedov 	krb5_abortx(context, "internal asn.1 error");
549*ae771770SStanislav Sedov 
550*ae771770SStanislav Sedov     ret = krb5_crypto_init(context, key, 0, &crypto);
551*ae771770SStanislav Sedov     if (ret) {
552*ae771770SStanislav Sedov 	free(data.data);
553*ae771770SStanislav Sedov 	free_PA_ClientCanonicalized(&canon);
554*ae771770SStanislav Sedov 	return ret;
555*ae771770SStanislav Sedov     }
556*ae771770SStanislav Sedov 
557*ae771770SStanislav Sedov     ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES,
558*ae771770SStanislav Sedov 			       data.data, data.length,
559*ae771770SStanislav Sedov 			       &canon.canon_checksum);
560*ae771770SStanislav Sedov     krb5_crypto_destroy(context, crypto);
561*ae771770SStanislav Sedov     free(data.data);
562*ae771770SStanislav Sedov     if (ret) {
563*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
564*ae771770SStanislav Sedov 			       N_("Failed to verify client canonicalized "
565*ae771770SStanislav Sedov 				  "data from realm %s", ""),
566*ae771770SStanislav Sedov 			       requested->realm);
567*ae771770SStanislav Sedov 	free_PA_ClientCanonicalized(&canon);
568*ae771770SStanislav Sedov 	return ret;
569*ae771770SStanislav Sedov     }
570*ae771770SStanislav Sedov 
571*ae771770SStanislav Sedov     if (!_krb5_principal_compare_PrincipalName(context,
572*ae771770SStanislav Sedov 					       requested,
573*ae771770SStanislav Sedov 					       &canon.names.requested_name))
574*ae771770SStanislav Sedov     {
575*ae771770SStanislav Sedov 	free_PA_ClientCanonicalized(&canon);
576*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
577*ae771770SStanislav Sedov 			       N_("Requested name doesn't match"
578*ae771770SStanislav Sedov 				  " in client referral", ""));
579*ae771770SStanislav Sedov 	return KRB5_PRINC_NOMATCH;
580*ae771770SStanislav Sedov     }
581*ae771770SStanislav Sedov     if (!_krb5_principal_compare_PrincipalName(context,
582*ae771770SStanislav Sedov 					       mapped,
583*ae771770SStanislav Sedov 					       &canon.names.mapped_name))
584*ae771770SStanislav Sedov     {
585*ae771770SStanislav Sedov 	free_PA_ClientCanonicalized(&canon);
586*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
587*ae771770SStanislav Sedov 			       N_("Mapped name doesn't match"
588*ae771770SStanislav Sedov 				  " in client referral", ""));
589*ae771770SStanislav Sedov 	return KRB5_PRINC_NOMATCH;
590*ae771770SStanislav Sedov     }
591*ae771770SStanislav Sedov 
592*ae771770SStanislav Sedov     return 0;
593*ae771770SStanislav Sedov 
594*ae771770SStanislav Sedov noreferral:
595*ae771770SStanislav Sedov     if (krb5_principal_compare(context, requested, mapped) == FALSE) {
596*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
597*ae771770SStanislav Sedov 			       N_("Not same client principal returned "
598*ae771770SStanislav Sedov 				  "as requested", ""));
599*ae771770SStanislav Sedov 	return KRB5KRB_AP_ERR_MODIFIED;
600*ae771770SStanislav Sedov     }
601*ae771770SStanislav Sedov     return 0;
602*ae771770SStanislav Sedov }
603*ae771770SStanislav Sedov 
604*ae771770SStanislav Sedov 
605*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
606*ae771770SStanislav Sedov decrypt_tkt (krb5_context context,
607*ae771770SStanislav Sedov 	     krb5_keyblock *key,
608*ae771770SStanislav Sedov 	     krb5_key_usage usage,
609*ae771770SStanislav Sedov 	     krb5_const_pointer decrypt_arg,
610*ae771770SStanislav Sedov 	     krb5_kdc_rep *dec_rep)
611*ae771770SStanislav Sedov {
612*ae771770SStanislav Sedov     krb5_error_code ret;
613*ae771770SStanislav Sedov     krb5_data data;
614*ae771770SStanislav Sedov     size_t size;
615*ae771770SStanislav Sedov     krb5_crypto crypto;
616*ae771770SStanislav Sedov 
617*ae771770SStanislav Sedov     ret = krb5_crypto_init(context, key, 0, &crypto);
618*ae771770SStanislav Sedov     if (ret)
619*ae771770SStanislav Sedov 	return ret;
620*ae771770SStanislav Sedov 
621*ae771770SStanislav Sedov     ret = krb5_decrypt_EncryptedData (context,
622*ae771770SStanislav Sedov 				      crypto,
623*ae771770SStanislav Sedov 				      usage,
624*ae771770SStanislav Sedov 				      &dec_rep->kdc_rep.enc_part,
625*ae771770SStanislav Sedov 				      &data);
626*ae771770SStanislav Sedov     krb5_crypto_destroy(context, crypto);
627*ae771770SStanislav Sedov 
628*ae771770SStanislav Sedov     if (ret)
629*ae771770SStanislav Sedov 	return ret;
630*ae771770SStanislav Sedov 
631*ae771770SStanislav Sedov     ret = decode_EncASRepPart(data.data,
632*ae771770SStanislav Sedov 			      data.length,
633*ae771770SStanislav Sedov 			      &dec_rep->enc_part,
634*ae771770SStanislav Sedov 			      &size);
635*ae771770SStanislav Sedov     if (ret)
636*ae771770SStanislav Sedov 	ret = decode_EncTGSRepPart(data.data,
637*ae771770SStanislav Sedov 				   data.length,
638*ae771770SStanislav Sedov 				   &dec_rep->enc_part,
639*ae771770SStanislav Sedov 				   &size);
640*ae771770SStanislav Sedov     krb5_data_free (&data);
641*ae771770SStanislav Sedov     if (ret) {
642*ae771770SStanislav Sedov         krb5_set_error_message(context, ret,
643*ae771770SStanislav Sedov 			       N_("Failed to decode encpart in ticket", ""));
644*ae771770SStanislav Sedov 	return ret;
645*ae771770SStanislav Sedov     }
646*ae771770SStanislav Sedov     return 0;
647*ae771770SStanislav Sedov }
648*ae771770SStanislav Sedov 
649*ae771770SStanislav Sedov int
650*ae771770SStanislav Sedov _krb5_extract_ticket(krb5_context context,
651*ae771770SStanislav Sedov 		     krb5_kdc_rep *rep,
652*ae771770SStanislav Sedov 		     krb5_creds *creds,
653*ae771770SStanislav Sedov 		     krb5_keyblock *key,
654*ae771770SStanislav Sedov 		     krb5_const_pointer keyseed,
655*ae771770SStanislav Sedov 		     krb5_key_usage key_usage,
656*ae771770SStanislav Sedov 		     krb5_addresses *addrs,
657*ae771770SStanislav Sedov 		     unsigned nonce,
658*ae771770SStanislav Sedov 		     unsigned flags,
659*ae771770SStanislav Sedov 		     krb5_decrypt_proc decrypt_proc,
660*ae771770SStanislav Sedov 		     krb5_const_pointer decryptarg)
661*ae771770SStanislav Sedov {
662*ae771770SStanislav Sedov     krb5_error_code ret;
663*ae771770SStanislav Sedov     krb5_principal tmp_principal;
664*ae771770SStanislav Sedov     size_t len = 0;
665*ae771770SStanislav Sedov     time_t tmp_time;
666*ae771770SStanislav Sedov     krb5_timestamp sec_now;
667*ae771770SStanislav Sedov 
668*ae771770SStanislav Sedov     /* decrypt */
669*ae771770SStanislav Sedov 
670*ae771770SStanislav Sedov     if (decrypt_proc == NULL)
671*ae771770SStanislav Sedov 	decrypt_proc = decrypt_tkt;
672*ae771770SStanislav Sedov 
673*ae771770SStanislav Sedov     ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
674*ae771770SStanislav Sedov     if (ret)
675*ae771770SStanislav Sedov 	goto out;
676*ae771770SStanislav Sedov 
677*ae771770SStanislav Sedov     /* save session key */
678*ae771770SStanislav Sedov 
679*ae771770SStanislav Sedov     creds->session.keyvalue.length = 0;
680*ae771770SStanislav Sedov     creds->session.keyvalue.data   = NULL;
681*ae771770SStanislav Sedov     creds->session.keytype = rep->enc_part.key.keytype;
682*ae771770SStanislav Sedov     ret = krb5_data_copy (&creds->session.keyvalue,
683*ae771770SStanislav Sedov 			  rep->enc_part.key.keyvalue.data,
684*ae771770SStanislav Sedov 			  rep->enc_part.key.keyvalue.length);
685*ae771770SStanislav Sedov     if (ret) {
686*ae771770SStanislav Sedov 	krb5_clear_error_message(context);
687*ae771770SStanislav Sedov 	goto out;
688*ae771770SStanislav Sedov     }
689*ae771770SStanislav Sedov 
690*ae771770SStanislav Sedov     /* compare client and save */
691*ae771770SStanislav Sedov     ret = _krb5_principalname2krb5_principal (context,
692*ae771770SStanislav Sedov 					      &tmp_principal,
693*ae771770SStanislav Sedov 					      rep->kdc_rep.cname,
694*ae771770SStanislav Sedov 					      rep->kdc_rep.crealm);
695*ae771770SStanislav Sedov     if (ret)
696*ae771770SStanislav Sedov 	goto out;
697*ae771770SStanislav Sedov 
698*ae771770SStanislav Sedov     /* check client referral and save principal */
699*ae771770SStanislav Sedov     /* anonymous here ? */
700*ae771770SStanislav Sedov     if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) {
701*ae771770SStanislav Sedov 	ret = check_client_referral(context, rep,
702*ae771770SStanislav Sedov 				    creds->client,
703*ae771770SStanislav Sedov 				    tmp_principal,
704*ae771770SStanislav Sedov 				    &creds->session);
705*ae771770SStanislav Sedov 	if (ret) {
706*ae771770SStanislav Sedov 	    krb5_free_principal (context, tmp_principal);
707*ae771770SStanislav Sedov 	    goto out;
708*ae771770SStanislav Sedov 	}
709*ae771770SStanislav Sedov     }
710*ae771770SStanislav Sedov     krb5_free_principal (context, creds->client);
711*ae771770SStanislav Sedov     creds->client = tmp_principal;
712*ae771770SStanislav Sedov 
713*ae771770SStanislav Sedov     /* check server referral and save principal */
714*ae771770SStanislav Sedov     ret = _krb5_principalname2krb5_principal (context,
715*ae771770SStanislav Sedov 					      &tmp_principal,
716*ae771770SStanislav Sedov 					      rep->kdc_rep.ticket.sname,
717*ae771770SStanislav Sedov 					      rep->kdc_rep.ticket.realm);
718*ae771770SStanislav Sedov     if (ret)
719*ae771770SStanislav Sedov 	goto out;
720*ae771770SStanislav Sedov     if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){
721*ae771770SStanislav Sedov 	ret = check_server_referral(context,
722*ae771770SStanislav Sedov 				    rep,
723*ae771770SStanislav Sedov 				    flags,
724*ae771770SStanislav Sedov 				    creds->server,
725*ae771770SStanislav Sedov 				    tmp_principal,
726*ae771770SStanislav Sedov 				    &creds->session);
727*ae771770SStanislav Sedov 	if (ret) {
728*ae771770SStanislav Sedov 	    krb5_free_principal (context, tmp_principal);
729*ae771770SStanislav Sedov 	    goto out;
730*ae771770SStanislav Sedov 	}
731*ae771770SStanislav Sedov     }
732*ae771770SStanislav Sedov     krb5_free_principal(context, creds->server);
733*ae771770SStanislav Sedov     creds->server = tmp_principal;
734*ae771770SStanislav Sedov 
735*ae771770SStanislav Sedov     /* verify names */
736*ae771770SStanislav Sedov     if(flags & EXTRACT_TICKET_MATCH_REALM){
737*ae771770SStanislav Sedov 	const char *srealm = krb5_principal_get_realm(context, creds->server);
738*ae771770SStanislav Sedov 	const char *crealm = krb5_principal_get_realm(context, creds->client);
739*ae771770SStanislav Sedov 
740*ae771770SStanislav Sedov 	if (strcmp(rep->enc_part.srealm, srealm) != 0 ||
741*ae771770SStanislav Sedov 	    strcmp(rep->enc_part.srealm, crealm) != 0)
742*ae771770SStanislav Sedov 	{
743*ae771770SStanislav Sedov 	    ret = KRB5KRB_AP_ERR_MODIFIED;
744*ae771770SStanislav Sedov 	    krb5_clear_error_message(context);
745*ae771770SStanislav Sedov 	    goto out;
746*ae771770SStanislav Sedov 	}
747*ae771770SStanislav Sedov     }
748*ae771770SStanislav Sedov 
749*ae771770SStanislav Sedov     /* compare nonces */
750*ae771770SStanislav Sedov 
751*ae771770SStanislav Sedov     if (nonce != (unsigned)rep->enc_part.nonce) {
752*ae771770SStanislav Sedov 	ret = KRB5KRB_AP_ERR_MODIFIED;
753*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
754*ae771770SStanislav Sedov 	goto out;
755*ae771770SStanislav Sedov     }
756*ae771770SStanislav Sedov 
757*ae771770SStanislav Sedov     /* set kdc-offset */
758*ae771770SStanislav Sedov 
759*ae771770SStanislav Sedov     krb5_timeofday (context, &sec_now);
760*ae771770SStanislav Sedov     if (rep->enc_part.flags.initial
761*ae771770SStanislav Sedov 	&& (flags & EXTRACT_TICKET_TIMESYNC)
762*ae771770SStanislav Sedov 	&& context->kdc_sec_offset == 0
763*ae771770SStanislav Sedov 	&& krb5_config_get_bool (context, NULL,
764*ae771770SStanislav Sedov 				 "libdefaults",
765*ae771770SStanislav Sedov 				 "kdc_timesync",
766*ae771770SStanislav Sedov 				 NULL)) {
767*ae771770SStanislav Sedov 	context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
768*ae771770SStanislav Sedov 	krb5_timeofday (context, &sec_now);
769*ae771770SStanislav Sedov     }
770*ae771770SStanislav Sedov 
771*ae771770SStanislav Sedov     /* check all times */
772*ae771770SStanislav Sedov 
773*ae771770SStanislav Sedov     if (rep->enc_part.starttime) {
774*ae771770SStanislav Sedov 	tmp_time = *rep->enc_part.starttime;
775*ae771770SStanislav Sedov     } else
776*ae771770SStanislav Sedov 	tmp_time = rep->enc_part.authtime;
777*ae771770SStanislav Sedov 
778*ae771770SStanislav Sedov     if (creds->times.starttime == 0
779*ae771770SStanislav Sedov 	&& abs(tmp_time - sec_now) > context->max_skew) {
780*ae771770SStanislav Sedov 	ret = KRB5KRB_AP_ERR_SKEW;
781*ae771770SStanislav Sedov 	krb5_set_error_message (context, ret,
782*ae771770SStanislav Sedov 				N_("time skew (%d) larger than max (%d)", ""),
783*ae771770SStanislav Sedov 			       abs(tmp_time - sec_now),
784*ae771770SStanislav Sedov 			       (int)context->max_skew);
785*ae771770SStanislav Sedov 	goto out;
786*ae771770SStanislav Sedov     }
787*ae771770SStanislav Sedov 
788*ae771770SStanislav Sedov     if (creds->times.starttime != 0
789*ae771770SStanislav Sedov 	&& tmp_time != creds->times.starttime) {
790*ae771770SStanislav Sedov 	krb5_clear_error_message (context);
791*ae771770SStanislav Sedov 	ret = KRB5KRB_AP_ERR_MODIFIED;
792*ae771770SStanislav Sedov 	goto out;
793*ae771770SStanislav Sedov     }
794*ae771770SStanislav Sedov 
795*ae771770SStanislav Sedov     creds->times.starttime = tmp_time;
796*ae771770SStanislav Sedov 
797*ae771770SStanislav Sedov     if (rep->enc_part.renew_till) {
798*ae771770SStanislav Sedov 	tmp_time = *rep->enc_part.renew_till;
799*ae771770SStanislav Sedov     } else
800*ae771770SStanislav Sedov 	tmp_time = 0;
801*ae771770SStanislav Sedov 
802*ae771770SStanislav Sedov     if (creds->times.renew_till != 0
803*ae771770SStanislav Sedov 	&& tmp_time > creds->times.renew_till) {
804*ae771770SStanislav Sedov 	krb5_clear_error_message (context);
805*ae771770SStanislav Sedov 	ret = KRB5KRB_AP_ERR_MODIFIED;
806*ae771770SStanislav Sedov 	goto out;
807*ae771770SStanislav Sedov     }
808*ae771770SStanislav Sedov 
809*ae771770SStanislav Sedov     creds->times.renew_till = tmp_time;
810*ae771770SStanislav Sedov 
811*ae771770SStanislav Sedov     creds->times.authtime = rep->enc_part.authtime;
812*ae771770SStanislav Sedov 
813*ae771770SStanislav Sedov     if (creds->times.endtime != 0
814*ae771770SStanislav Sedov 	&& rep->enc_part.endtime > creds->times.endtime) {
815*ae771770SStanislav Sedov 	krb5_clear_error_message (context);
816*ae771770SStanislav Sedov 	ret = KRB5KRB_AP_ERR_MODIFIED;
817*ae771770SStanislav Sedov 	goto out;
818*ae771770SStanislav Sedov     }
819*ae771770SStanislav Sedov 
820*ae771770SStanislav Sedov     creds->times.endtime  = rep->enc_part.endtime;
821*ae771770SStanislav Sedov 
822*ae771770SStanislav Sedov     if(rep->enc_part.caddr)
823*ae771770SStanislav Sedov 	krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
824*ae771770SStanislav Sedov     else if(addrs)
825*ae771770SStanislav Sedov 	krb5_copy_addresses (context, addrs, &creds->addresses);
826*ae771770SStanislav Sedov     else {
827*ae771770SStanislav Sedov 	creds->addresses.len = 0;
828*ae771770SStanislav Sedov 	creds->addresses.val = NULL;
829*ae771770SStanislav Sedov     }
830*ae771770SStanislav Sedov     creds->flags.b = rep->enc_part.flags;
831*ae771770SStanislav Sedov 
832*ae771770SStanislav Sedov     creds->authdata.len = 0;
833*ae771770SStanislav Sedov     creds->authdata.val = NULL;
834*ae771770SStanislav Sedov 
835*ae771770SStanislav Sedov     /* extract ticket */
836*ae771770SStanislav Sedov     ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
837*ae771770SStanislav Sedov 		       &rep->kdc_rep.ticket, &len, ret);
838*ae771770SStanislav Sedov     if(ret)
839*ae771770SStanislav Sedov 	goto out;
840*ae771770SStanislav Sedov     if (creds->ticket.length != len)
841*ae771770SStanislav Sedov 	krb5_abortx(context, "internal error in ASN.1 encoder");
842*ae771770SStanislav Sedov     creds->second_ticket.length = 0;
843*ae771770SStanislav Sedov     creds->second_ticket.data   = NULL;
844*ae771770SStanislav Sedov 
845*ae771770SStanislav Sedov 
846*ae771770SStanislav Sedov out:
847*ae771770SStanislav Sedov     memset (rep->enc_part.key.keyvalue.data, 0,
848*ae771770SStanislav Sedov 	    rep->enc_part.key.keyvalue.length);
849*ae771770SStanislav Sedov     return ret;
850*ae771770SStanislav Sedov }
851