1ae771770SStanislav Sedov
2b528cefcSMark Murray /*
3ae771770SStanislav Sedov * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
4b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden).
5b528cefcSMark Murray * All rights reserved.
6b528cefcSMark Murray *
7b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without
8b528cefcSMark Murray * modification, are permitted provided that the following conditions
9b528cefcSMark Murray * are met:
10b528cefcSMark Murray *
11b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright
12b528cefcSMark Murray * notice, this list of conditions and the following disclaimer.
13b528cefcSMark Murray *
14b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright
15b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the
16b528cefcSMark Murray * documentation and/or other materials provided with the distribution.
17b528cefcSMark Murray *
18b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors
19b528cefcSMark Murray * may be used to endorse or promote products derived from this software
20b528cefcSMark Murray * without specific prior written permission.
21b528cefcSMark Murray *
22b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32b528cefcSMark Murray * SUCH DAMAGE.
33b528cefcSMark Murray */
34b528cefcSMark Murray
35ae771770SStanislav Sedov #include "krb5_locl.h"
36b528cefcSMark Murray
37b528cefcSMark Murray static krb5_error_code
decrypt_tkt_enc_part(krb5_context context,krb5_keyblock * key,EncryptedData * enc_part,EncTicketPart * decr_part)38b528cefcSMark Murray decrypt_tkt_enc_part (krb5_context context,
39b528cefcSMark Murray krb5_keyblock *key,
40b528cefcSMark Murray EncryptedData *enc_part,
41b528cefcSMark Murray EncTicketPart *decr_part)
42b528cefcSMark Murray {
43b528cefcSMark Murray krb5_error_code ret;
44b528cefcSMark Murray krb5_data plain;
45b528cefcSMark Murray size_t len;
46b528cefcSMark Murray krb5_crypto crypto;
47b528cefcSMark Murray
485e9cd1aeSAssar Westerlund ret = krb5_crypto_init(context, key, 0, &crypto);
495e9cd1aeSAssar Westerlund if (ret)
505e9cd1aeSAssar Westerlund return ret;
51b528cefcSMark Murray ret = krb5_decrypt_EncryptedData (context,
52b528cefcSMark Murray crypto,
53b528cefcSMark Murray KRB5_KU_TICKET,
54b528cefcSMark Murray enc_part,
55b528cefcSMark Murray &plain);
56b528cefcSMark Murray krb5_crypto_destroy(context, crypto);
57b528cefcSMark Murray if (ret)
58b528cefcSMark Murray return ret;
59b528cefcSMark Murray
60ae771770SStanislav Sedov ret = decode_EncTicketPart(plain.data, plain.length, decr_part, &len);
61ae771770SStanislav Sedov if (ret)
62ae771770SStanislav Sedov krb5_set_error_message(context, ret,
63ae771770SStanislav Sedov N_("Failed to decode encrypted "
64ae771770SStanislav Sedov "ticket part", ""));
65b528cefcSMark Murray krb5_data_free (&plain);
66b528cefcSMark Murray return ret;
67b528cefcSMark Murray }
68b528cefcSMark Murray
69b528cefcSMark Murray static krb5_error_code
decrypt_authenticator(krb5_context context,EncryptionKey * key,EncryptedData * enc_part,Authenticator * authenticator,krb5_key_usage usage)70b528cefcSMark Murray decrypt_authenticator (krb5_context context,
71b528cefcSMark Murray EncryptionKey *key,
72b528cefcSMark Murray EncryptedData *enc_part,
735e9cd1aeSAssar Westerlund Authenticator *authenticator,
745e9cd1aeSAssar Westerlund krb5_key_usage usage)
75b528cefcSMark Murray {
76b528cefcSMark Murray krb5_error_code ret;
77b528cefcSMark Murray krb5_data plain;
78b528cefcSMark Murray size_t len;
79b528cefcSMark Murray krb5_crypto crypto;
80b528cefcSMark Murray
815e9cd1aeSAssar Westerlund ret = krb5_crypto_init(context, key, 0, &crypto);
825e9cd1aeSAssar Westerlund if (ret)
835e9cd1aeSAssar Westerlund return ret;
845e9cd1aeSAssar Westerlund ret = krb5_decrypt_EncryptedData (context,
855e9cd1aeSAssar Westerlund crypto,
865e9cd1aeSAssar Westerlund usage /* KRB5_KU_AP_REQ_AUTH */,
875e9cd1aeSAssar Westerlund enc_part,
885e9cd1aeSAssar Westerlund &plain);
895e9cd1aeSAssar Westerlund /* for backwards compatibility, also try the old usage */
905e9cd1aeSAssar Westerlund if (ret && usage == KRB5_KU_TGS_REQ_AUTH)
91b528cefcSMark Murray ret = krb5_decrypt_EncryptedData (context,
92b528cefcSMark Murray crypto,
93b528cefcSMark Murray KRB5_KU_AP_REQ_AUTH,
94b528cefcSMark Murray enc_part,
95b528cefcSMark Murray &plain);
96b528cefcSMark Murray krb5_crypto_destroy(context, crypto);
97b528cefcSMark Murray if (ret)
98b528cefcSMark Murray return ret;
99b528cefcSMark Murray
100ae771770SStanislav Sedov ret = decode_Authenticator(plain.data, plain.length,
101b528cefcSMark Murray authenticator, &len);
102b528cefcSMark Murray krb5_data_free (&plain);
103b528cefcSMark Murray return ret;
104b528cefcSMark Murray }
105b528cefcSMark Murray
106ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_decode_ap_req(krb5_context context,const krb5_data * inbuf,krb5_ap_req * ap_req)107b528cefcSMark Murray krb5_decode_ap_req(krb5_context context,
108b528cefcSMark Murray const krb5_data *inbuf,
109b528cefcSMark Murray krb5_ap_req *ap_req)
110b528cefcSMark Murray {
111b528cefcSMark Murray krb5_error_code ret;
112b528cefcSMark Murray size_t len;
113b528cefcSMark Murray ret = decode_AP_REQ(inbuf->data, inbuf->length, ap_req, &len);
114b528cefcSMark Murray if (ret)
115b528cefcSMark Murray return ret;
116b528cefcSMark Murray if (ap_req->pvno != 5){
117b528cefcSMark Murray free_AP_REQ(ap_req);
118ae771770SStanislav Sedov krb5_clear_error_message (context);
119b528cefcSMark Murray return KRB5KRB_AP_ERR_BADVERSION;
120b528cefcSMark Murray }
121b528cefcSMark Murray if (ap_req->msg_type != krb_ap_req){
122b528cefcSMark Murray free_AP_REQ(ap_req);
123ae771770SStanislav Sedov krb5_clear_error_message (context);
124b528cefcSMark Murray return KRB5KRB_AP_ERR_MSG_TYPE;
125b528cefcSMark Murray }
126b528cefcSMark Murray if (ap_req->ticket.tkt_vno != 5){
127b528cefcSMark Murray free_AP_REQ(ap_req);
128ae771770SStanislav Sedov krb5_clear_error_message (context);
129b528cefcSMark Murray return KRB5KRB_AP_ERR_BADVERSION;
130b528cefcSMark Murray }
131b528cefcSMark Murray return 0;
132b528cefcSMark Murray }
133b528cefcSMark Murray
1341c43270aSJacques Vidrine static krb5_error_code
check_transited(krb5_context context,Ticket * ticket,EncTicketPart * enc)1351c43270aSJacques Vidrine check_transited(krb5_context context, Ticket *ticket, EncTicketPart *enc)
1361c43270aSJacques Vidrine {
1371c43270aSJacques Vidrine char **realms;
138ae771770SStanislav Sedov unsigned int num_realms, n;
1391c43270aSJacques Vidrine krb5_error_code ret;
1401c43270aSJacques Vidrine
141c19800e8SDoug Rabson /*
142c19800e8SDoug Rabson * Windows 2000 and 2003 uses this inside their TGT so it's normaly
143c19800e8SDoug Rabson * not seen by others, however, samba4 joined with a Windows AD as
144c19800e8SDoug Rabson * a Domain Controller gets exposed to this.
145c19800e8SDoug Rabson */
146c19800e8SDoug Rabson if(enc->transited.tr_type == 0 && enc->transited.contents.length == 0)
147c19800e8SDoug Rabson return 0;
148c19800e8SDoug Rabson
1491c43270aSJacques Vidrine if(enc->transited.tr_type != DOMAIN_X500_COMPRESS)
1501c43270aSJacques Vidrine return KRB5KDC_ERR_TRTYPE_NOSUPP;
1511c43270aSJacques Vidrine
1521c43270aSJacques Vidrine if(enc->transited.contents.length == 0)
1531c43270aSJacques Vidrine return 0;
1541c43270aSJacques Vidrine
1551c43270aSJacques Vidrine ret = krb5_domain_x500_decode(context, enc->transited.contents,
1561c43270aSJacques Vidrine &realms, &num_realms,
1571c43270aSJacques Vidrine enc->crealm,
1581c43270aSJacques Vidrine ticket->realm);
1591c43270aSJacques Vidrine if(ret)
1601c43270aSJacques Vidrine return ret;
1611c43270aSJacques Vidrine ret = krb5_check_transited(context, enc->crealm,
1621c43270aSJacques Vidrine ticket->realm,
1631c43270aSJacques Vidrine realms, num_realms, NULL);
164ae771770SStanislav Sedov for (n = 0; n < num_realms; n++)
165ae771770SStanislav Sedov free(realms[n]);
1661c43270aSJacques Vidrine free(realms);
1671c43270aSJacques Vidrine return ret;
1681c43270aSJacques Vidrine }
1691c43270aSJacques Vidrine
170c19800e8SDoug Rabson static krb5_error_code
find_etypelist(krb5_context context,krb5_auth_context auth_context,EtypeList * etypes)171c19800e8SDoug Rabson find_etypelist(krb5_context context,
172c19800e8SDoug Rabson krb5_auth_context auth_context,
173c19800e8SDoug Rabson EtypeList *etypes)
174c19800e8SDoug Rabson {
175c19800e8SDoug Rabson krb5_error_code ret;
176c19800e8SDoug Rabson krb5_authdata *ad;
177c19800e8SDoug Rabson krb5_authdata adIfRelevant;
178c19800e8SDoug Rabson unsigned i;
179c19800e8SDoug Rabson
180ae771770SStanislav Sedov memset(&adIfRelevant, 0, sizeof(adIfRelevant));
181c19800e8SDoug Rabson
182c19800e8SDoug Rabson etypes->len = 0;
183c19800e8SDoug Rabson etypes->val = NULL;
184c19800e8SDoug Rabson
185c19800e8SDoug Rabson ad = auth_context->authenticator->authorization_data;
186c19800e8SDoug Rabson if (ad == NULL)
187c19800e8SDoug Rabson return 0;
188c19800e8SDoug Rabson
189c19800e8SDoug Rabson for (i = 0; i < ad->len; i++) {
190c19800e8SDoug Rabson if (ad->val[i].ad_type == KRB5_AUTHDATA_IF_RELEVANT) {
191c19800e8SDoug Rabson ret = decode_AD_IF_RELEVANT(ad->val[i].ad_data.data,
192c19800e8SDoug Rabson ad->val[i].ad_data.length,
193c19800e8SDoug Rabson &adIfRelevant,
194c19800e8SDoug Rabson NULL);
195c19800e8SDoug Rabson if (ret)
196c19800e8SDoug Rabson return ret;
197c19800e8SDoug Rabson
198c19800e8SDoug Rabson if (adIfRelevant.len == 1 &&
199c19800e8SDoug Rabson adIfRelevant.val[0].ad_type ==
200c19800e8SDoug Rabson KRB5_AUTHDATA_GSS_API_ETYPE_NEGOTIATION) {
201c19800e8SDoug Rabson break;
202c19800e8SDoug Rabson }
203c19800e8SDoug Rabson free_AD_IF_RELEVANT(&adIfRelevant);
204c19800e8SDoug Rabson adIfRelevant.len = 0;
205c19800e8SDoug Rabson }
206c19800e8SDoug Rabson }
207c19800e8SDoug Rabson
208c19800e8SDoug Rabson if (adIfRelevant.len == 0)
209c19800e8SDoug Rabson return 0;
210c19800e8SDoug Rabson
211c19800e8SDoug Rabson ret = decode_EtypeList(adIfRelevant.val[0].ad_data.data,
212c19800e8SDoug Rabson adIfRelevant.val[0].ad_data.length,
213c19800e8SDoug Rabson etypes,
214c19800e8SDoug Rabson NULL);
215c19800e8SDoug Rabson if (ret)
216ae771770SStanislav Sedov krb5_clear_error_message(context);
217c19800e8SDoug Rabson
218c19800e8SDoug Rabson free_AD_IF_RELEVANT(&adIfRelevant);
219c19800e8SDoug Rabson
220c19800e8SDoug Rabson return ret;
221c19800e8SDoug Rabson }
222c19800e8SDoug Rabson
223ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_decrypt_ticket(krb5_context context,Ticket * ticket,krb5_keyblock * key,EncTicketPart * out,krb5_flags flags)224b528cefcSMark Murray krb5_decrypt_ticket(krb5_context context,
225b528cefcSMark Murray Ticket *ticket,
226b528cefcSMark Murray krb5_keyblock *key,
227b528cefcSMark Murray EncTicketPart *out,
228b528cefcSMark Murray krb5_flags flags)
229b528cefcSMark Murray {
230b528cefcSMark Murray EncTicketPart t;
231b528cefcSMark Murray krb5_error_code ret;
232b528cefcSMark Murray ret = decrypt_tkt_enc_part (context, key, &ticket->enc_part, &t);
233b528cefcSMark Murray if (ret)
234b528cefcSMark Murray return ret;
235b528cefcSMark Murray
236b528cefcSMark Murray {
23713e3f4d6SMark Murray krb5_timestamp now;
238b528cefcSMark Murray time_t start = t.authtime;
239b528cefcSMark Murray
240b528cefcSMark Murray krb5_timeofday (context, &now);
241b528cefcSMark Murray if(t.starttime)
242b528cefcSMark Murray start = *t.starttime;
243b528cefcSMark Murray if(start - now > context->max_skew
244b528cefcSMark Murray || (t.flags.invalid
2455e9cd1aeSAssar Westerlund && !(flags & KRB5_VERIFY_AP_REQ_IGNORE_INVALID))) {
2465e9cd1aeSAssar Westerlund free_EncTicketPart(&t);
247ae771770SStanislav Sedov krb5_clear_error_message (context);
248b528cefcSMark Murray return KRB5KRB_AP_ERR_TKT_NYV;
2495e9cd1aeSAssar Westerlund }
2505e9cd1aeSAssar Westerlund if(now - t.endtime > context->max_skew) {
2515e9cd1aeSAssar Westerlund free_EncTicketPart(&t);
252ae771770SStanislav Sedov krb5_clear_error_message (context);
253b528cefcSMark Murray return KRB5KRB_AP_ERR_TKT_EXPIRED;
254b528cefcSMark Murray }
2551c43270aSJacques Vidrine
2561c43270aSJacques Vidrine if(!t.flags.transited_policy_checked) {
2571c43270aSJacques Vidrine ret = check_transited(context, ticket, &t);
2581c43270aSJacques Vidrine if(ret) {
2591c43270aSJacques Vidrine free_EncTicketPart(&t);
2601c43270aSJacques Vidrine return ret;
2611c43270aSJacques Vidrine }
2621c43270aSJacques Vidrine }
2635e9cd1aeSAssar Westerlund }
264b528cefcSMark Murray
265b528cefcSMark Murray if(out)
266b528cefcSMark Murray *out = t;
267b528cefcSMark Murray else
268b528cefcSMark Murray free_EncTicketPart(&t);
269b528cefcSMark Murray return 0;
270b528cefcSMark Murray }
271b528cefcSMark Murray
272ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_verify_authenticator_checksum(krb5_context context,krb5_auth_context ac,void * data,size_t len)273b528cefcSMark Murray krb5_verify_authenticator_checksum(krb5_context context,
274b528cefcSMark Murray krb5_auth_context ac,
275b528cefcSMark Murray void *data,
276b528cefcSMark Murray size_t len)
277b528cefcSMark Murray {
278b528cefcSMark Murray krb5_error_code ret;
279b528cefcSMark Murray krb5_keyblock *key;
280b528cefcSMark Murray krb5_authenticator authenticator;
281b528cefcSMark Murray krb5_crypto crypto;
282b528cefcSMark Murray
2834137ff4cSJacques Vidrine ret = krb5_auth_con_getauthenticator (context,
284b528cefcSMark Murray ac,
285b528cefcSMark Murray &authenticator);
286b528cefcSMark Murray if(ret)
287b528cefcSMark Murray return ret;
288c19800e8SDoug Rabson if(authenticator->cksum == NULL) {
289c19800e8SDoug Rabson krb5_free_authenticator(context, &authenticator);
290b528cefcSMark Murray return -17;
291c19800e8SDoug Rabson }
292b528cefcSMark Murray ret = krb5_auth_con_getkey(context, ac, &key);
293b528cefcSMark Murray if(ret) {
294b528cefcSMark Murray krb5_free_authenticator(context, &authenticator);
295b528cefcSMark Murray return ret;
296b528cefcSMark Murray }
297b528cefcSMark Murray ret = krb5_crypto_init(context, key, 0, &crypto);
298b528cefcSMark Murray if(ret)
299b528cefcSMark Murray goto out;
300b528cefcSMark Murray ret = krb5_verify_checksum (context,
301b528cefcSMark Murray crypto,
302b528cefcSMark Murray KRB5_KU_AP_REQ_AUTH_CKSUM,
303b528cefcSMark Murray data,
304b528cefcSMark Murray len,
305b528cefcSMark Murray authenticator->cksum);
306b528cefcSMark Murray krb5_crypto_destroy(context, crypto);
307b528cefcSMark Murray out:
308b528cefcSMark Murray krb5_free_authenticator(context, &authenticator);
309b528cefcSMark Murray krb5_free_keyblock(context, key);
310b528cefcSMark Murray return ret;
311b528cefcSMark Murray }
312b528cefcSMark Murray
313283d988cSMark Murray
314ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_verify_ap_req(krb5_context context,krb5_auth_context * auth_context,krb5_ap_req * ap_req,krb5_const_principal server,krb5_keyblock * keyblock,krb5_flags flags,krb5_flags * ap_req_options,krb5_ticket ** ticket)315b528cefcSMark Murray krb5_verify_ap_req(krb5_context context,
316b528cefcSMark Murray krb5_auth_context *auth_context,
317b528cefcSMark Murray krb5_ap_req *ap_req,
318b528cefcSMark Murray krb5_const_principal server,
319b528cefcSMark Murray krb5_keyblock *keyblock,
320b528cefcSMark Murray krb5_flags flags,
321b528cefcSMark Murray krb5_flags *ap_req_options,
322b528cefcSMark Murray krb5_ticket **ticket)
323b528cefcSMark Murray {
3245e9cd1aeSAssar Westerlund return krb5_verify_ap_req2 (context,
3255e9cd1aeSAssar Westerlund auth_context,
3265e9cd1aeSAssar Westerlund ap_req,
3275e9cd1aeSAssar Westerlund server,
3285e9cd1aeSAssar Westerlund keyblock,
3295e9cd1aeSAssar Westerlund flags,
3305e9cd1aeSAssar Westerlund ap_req_options,
3315e9cd1aeSAssar Westerlund ticket,
3325e9cd1aeSAssar Westerlund KRB5_KU_AP_REQ_AUTH);
3335e9cd1aeSAssar Westerlund }
3345e9cd1aeSAssar Westerlund
335ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_verify_ap_req2(krb5_context context,krb5_auth_context * auth_context,krb5_ap_req * ap_req,krb5_const_principal server,krb5_keyblock * keyblock,krb5_flags flags,krb5_flags * ap_req_options,krb5_ticket ** ticket,krb5_key_usage usage)3365e9cd1aeSAssar Westerlund krb5_verify_ap_req2(krb5_context context,
3375e9cd1aeSAssar Westerlund krb5_auth_context *auth_context,
3385e9cd1aeSAssar Westerlund krb5_ap_req *ap_req,
3395e9cd1aeSAssar Westerlund krb5_const_principal server,
3405e9cd1aeSAssar Westerlund krb5_keyblock *keyblock,
3415e9cd1aeSAssar Westerlund krb5_flags flags,
3425e9cd1aeSAssar Westerlund krb5_flags *ap_req_options,
3435e9cd1aeSAssar Westerlund krb5_ticket **ticket,
3445e9cd1aeSAssar Westerlund krb5_key_usage usage)
3455e9cd1aeSAssar Westerlund {
346c19800e8SDoug Rabson krb5_ticket *t;
347b528cefcSMark Murray krb5_auth_context ac;
348b528cefcSMark Murray krb5_error_code ret;
349c19800e8SDoug Rabson EtypeList etypes;
350c19800e8SDoug Rabson
351c19800e8SDoug Rabson if (ticket)
352c19800e8SDoug Rabson *ticket = NULL;
353b528cefcSMark Murray
3545e9cd1aeSAssar Westerlund if (auth_context && *auth_context) {
355b528cefcSMark Murray ac = *auth_context;
3565e9cd1aeSAssar Westerlund } else {
3575e9cd1aeSAssar Westerlund ret = krb5_auth_con_init (context, &ac);
3585e9cd1aeSAssar Westerlund if (ret)
3595e9cd1aeSAssar Westerlund return ret;
3605e9cd1aeSAssar Westerlund }
361b528cefcSMark Murray
362c19800e8SDoug Rabson t = calloc(1, sizeof(*t));
363c19800e8SDoug Rabson if (t == NULL) {
364c19800e8SDoug Rabson ret = ENOMEM;
365ae771770SStanislav Sedov krb5_clear_error_message (context);
366c19800e8SDoug Rabson goto out;
367c19800e8SDoug Rabson }
368c19800e8SDoug Rabson
369b528cefcSMark Murray if (ap_req->ap_options.use_session_key && ac->keyblock){
370b528cefcSMark Murray ret = krb5_decrypt_ticket(context, &ap_req->ticket,
371b528cefcSMark Murray ac->keyblock,
372c19800e8SDoug Rabson &t->ticket,
373b528cefcSMark Murray flags);
374b528cefcSMark Murray krb5_free_keyblock(context, ac->keyblock);
375b528cefcSMark Murray ac->keyblock = NULL;
376b528cefcSMark Murray }else
377b528cefcSMark Murray ret = krb5_decrypt_ticket(context, &ap_req->ticket,
378b528cefcSMark Murray keyblock,
379c19800e8SDoug Rabson &t->ticket,
380b528cefcSMark Murray flags);
381b528cefcSMark Murray
382b528cefcSMark Murray if(ret)
3835e9cd1aeSAssar Westerlund goto out;
384b528cefcSMark Murray
385c19800e8SDoug Rabson ret = _krb5_principalname2krb5_principal(context,
386c19800e8SDoug Rabson &t->server,
387c19800e8SDoug Rabson ap_req->ticket.sname,
388b528cefcSMark Murray ap_req->ticket.realm);
389c19800e8SDoug Rabson if (ret) goto out;
390c19800e8SDoug Rabson ret = _krb5_principalname2krb5_principal(context,
391c19800e8SDoug Rabson &t->client,
392c19800e8SDoug Rabson t->ticket.cname,
393c19800e8SDoug Rabson t->ticket.crealm);
394c19800e8SDoug Rabson if (ret) goto out;
395b528cefcSMark Murray
396b528cefcSMark Murray ret = decrypt_authenticator (context,
397c19800e8SDoug Rabson &t->ticket.key,
398b528cefcSMark Murray &ap_req->authenticator,
3995e9cd1aeSAssar Westerlund ac->authenticator,
4005e9cd1aeSAssar Westerlund usage);
4015e9cd1aeSAssar Westerlund if (ret)
402c19800e8SDoug Rabson goto out;
403b528cefcSMark Murray
404b528cefcSMark Murray {
405b528cefcSMark Murray krb5_principal p1, p2;
406b528cefcSMark Murray krb5_boolean res;
407b528cefcSMark Murray
408c19800e8SDoug Rabson _krb5_principalname2krb5_principal(context,
409c19800e8SDoug Rabson &p1,
410b528cefcSMark Murray ac->authenticator->cname,
411b528cefcSMark Murray ac->authenticator->crealm);
412c19800e8SDoug Rabson _krb5_principalname2krb5_principal(context,
413c19800e8SDoug Rabson &p2,
414c19800e8SDoug Rabson t->ticket.cname,
415c19800e8SDoug Rabson t->ticket.crealm);
416b528cefcSMark Murray res = krb5_principal_compare (context, p1, p2);
417b528cefcSMark Murray krb5_free_principal (context, p1);
418b528cefcSMark Murray krb5_free_principal (context, p2);
4195e9cd1aeSAssar Westerlund if (!res) {
4205e9cd1aeSAssar Westerlund ret = KRB5KRB_AP_ERR_BADMATCH;
421ae771770SStanislav Sedov krb5_clear_error_message (context);
422c19800e8SDoug Rabson goto out;
4235e9cd1aeSAssar Westerlund }
424b528cefcSMark Murray }
425b528cefcSMark Murray
426b528cefcSMark Murray /* check addresses */
427b528cefcSMark Murray
428c19800e8SDoug Rabson if (t->ticket.caddr
429b528cefcSMark Murray && ac->remote_address
430b528cefcSMark Murray && !krb5_address_search (context,
431b528cefcSMark Murray ac->remote_address,
432c19800e8SDoug Rabson t->ticket.caddr)) {
4335e9cd1aeSAssar Westerlund ret = KRB5KRB_AP_ERR_BADADDR;
434ae771770SStanislav Sedov krb5_clear_error_message (context);
435c19800e8SDoug Rabson goto out;
436c19800e8SDoug Rabson }
437c19800e8SDoug Rabson
438c19800e8SDoug Rabson /* check timestamp in authenticator */
439c19800e8SDoug Rabson {
440c19800e8SDoug Rabson krb5_timestamp now;
441c19800e8SDoug Rabson
442c19800e8SDoug Rabson krb5_timeofday (context, &now);
443c19800e8SDoug Rabson
444c19800e8SDoug Rabson if (abs(ac->authenticator->ctime - now) > context->max_skew) {
445c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_SKEW;
446ae771770SStanislav Sedov krb5_clear_error_message (context);
447c19800e8SDoug Rabson goto out;
448c19800e8SDoug Rabson }
4495e9cd1aeSAssar Westerlund }
450b528cefcSMark Murray
451b528cefcSMark Murray if (ac->authenticator->seq_number)
4524137ff4cSJacques Vidrine krb5_auth_con_setremoteseqnumber(context, ac,
4534137ff4cSJacques Vidrine *ac->authenticator->seq_number);
454b528cefcSMark Murray
455b528cefcSMark Murray /* XXX - Xor sequence numbers */
456b528cefcSMark Murray
457b528cefcSMark Murray if (ac->authenticator->subkey) {
4584137ff4cSJacques Vidrine ret = krb5_auth_con_setremotesubkey(context, ac,
4594137ff4cSJacques Vidrine ac->authenticator->subkey);
4604137ff4cSJacques Vidrine if (ret)
461c19800e8SDoug Rabson goto out;
462c19800e8SDoug Rabson }
463c19800e8SDoug Rabson
464c19800e8SDoug Rabson ret = find_etypelist(context, ac, &etypes);
465c19800e8SDoug Rabson if (ret)
466c19800e8SDoug Rabson goto out;
467c19800e8SDoug Rabson
468c19800e8SDoug Rabson ac->keytype = ETYPE_NULL;
469c19800e8SDoug Rabson
470c19800e8SDoug Rabson if (etypes.val) {
471ae771770SStanislav Sedov size_t i;
472c19800e8SDoug Rabson
473c19800e8SDoug Rabson for (i = 0; i < etypes.len; i++) {
474c19800e8SDoug Rabson if (krb5_enctype_valid(context, etypes.val[i]) == 0) {
475c19800e8SDoug Rabson ac->keytype = etypes.val[i];
476c19800e8SDoug Rabson break;
477c19800e8SDoug Rabson }
478c19800e8SDoug Rabson }
479b528cefcSMark Murray }
480b528cefcSMark Murray
481ae771770SStanislav Sedov /* save key */
482ae771770SStanislav Sedov ret = krb5_copy_keyblock(context, &t->ticket.key, &ac->keyblock);
483ae771770SStanislav Sedov if (ret) goto out;
484ae771770SStanislav Sedov
485b528cefcSMark Murray if (ap_req_options) {
486b528cefcSMark Murray *ap_req_options = 0;
487c19800e8SDoug Rabson if (ac->keytype != ETYPE_NULL)
488c19800e8SDoug Rabson *ap_req_options |= AP_OPTS_USE_SUBKEY;
489b528cefcSMark Murray if (ap_req->ap_options.use_session_key)
490b528cefcSMark Murray *ap_req_options |= AP_OPTS_USE_SESSION_KEY;
491b528cefcSMark Murray if (ap_req->ap_options.mutual_required)
492b528cefcSMark Murray *ap_req_options |= AP_OPTS_MUTUAL_REQUIRED;
493b528cefcSMark Murray }
494b528cefcSMark Murray
495c19800e8SDoug Rabson if(ticket)
496c19800e8SDoug Rabson *ticket = t;
497c19800e8SDoug Rabson else
498c19800e8SDoug Rabson krb5_free_ticket (context, t);
4995e9cd1aeSAssar Westerlund if (auth_context) {
5005e9cd1aeSAssar Westerlund if (*auth_context == NULL)
5015e9cd1aeSAssar Westerlund *auth_context = ac;
5025e9cd1aeSAssar Westerlund } else
5035e9cd1aeSAssar Westerlund krb5_auth_con_free (context, ac);
504c19800e8SDoug Rabson free_EtypeList(&etypes);
505b528cefcSMark Murray return 0;
5065e9cd1aeSAssar Westerlund out:
507c19800e8SDoug Rabson if (t)
508c19800e8SDoug Rabson krb5_free_ticket (context, t);
5095e9cd1aeSAssar Westerlund if (auth_context == NULL || *auth_context == NULL)
5105e9cd1aeSAssar Westerlund krb5_auth_con_free (context, ac);
5115e9cd1aeSAssar Westerlund return ret;
512b528cefcSMark Murray }
513b528cefcSMark Murray
514c19800e8SDoug Rabson /*
515c19800e8SDoug Rabson *
516c19800e8SDoug Rabson */
517b528cefcSMark Murray
518c19800e8SDoug Rabson struct krb5_rd_req_in_ctx_data {
519c19800e8SDoug Rabson krb5_keytab keytab;
520c19800e8SDoug Rabson krb5_keyblock *keyblock;
521c19800e8SDoug Rabson krb5_boolean check_pac;
522c19800e8SDoug Rabson };
523c19800e8SDoug Rabson
524c19800e8SDoug Rabson struct krb5_rd_req_out_ctx_data {
525c19800e8SDoug Rabson krb5_keyblock *keyblock;
526c19800e8SDoug Rabson krb5_flags ap_req_options;
527c19800e8SDoug Rabson krb5_ticket *ticket;
528ae771770SStanislav Sedov krb5_principal server;
529c19800e8SDoug Rabson };
530c19800e8SDoug Rabson
531ae771770SStanislav Sedov /**
532ae771770SStanislav Sedov * Allocate a krb5_rd_req_in_ctx as an input parameter to
533ae771770SStanislav Sedov * krb5_rd_req_ctx(). The caller should free the context with
534ae771770SStanislav Sedov * krb5_rd_req_in_ctx_free() when done with the context.
535c19800e8SDoug Rabson *
536ae771770SStanislav Sedov * @param context Keberos 5 context.
537ae771770SStanislav Sedov * @param ctx in ctx to krb5_rd_req_ctx().
538ae771770SStanislav Sedov *
539ae771770SStanislav Sedov * @return Kerberos 5 error code, see krb5_get_error_message().
540ae771770SStanislav Sedov *
541ae771770SStanislav Sedov * @ingroup krb5_auth
542c19800e8SDoug Rabson */
543c19800e8SDoug Rabson
544ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_in_ctx_alloc(krb5_context context,krb5_rd_req_in_ctx * ctx)545c19800e8SDoug Rabson krb5_rd_req_in_ctx_alloc(krb5_context context, krb5_rd_req_in_ctx *ctx)
546c19800e8SDoug Rabson {
547c19800e8SDoug Rabson *ctx = calloc(1, sizeof(**ctx));
548c19800e8SDoug Rabson if (*ctx == NULL) {
549ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM,
550ae771770SStanislav Sedov N_("malloc: out of memory", ""));
551c19800e8SDoug Rabson return ENOMEM;
552c19800e8SDoug Rabson }
553c19800e8SDoug Rabson (*ctx)->check_pac = (context->flags & KRB5_CTX_F_CHECK_PAC) ? 1 : 0;
554c19800e8SDoug Rabson return 0;
555c19800e8SDoug Rabson }
556c19800e8SDoug Rabson
557ae771770SStanislav Sedov /**
558ae771770SStanislav Sedov * Set the keytab that krb5_rd_req_ctx() will use.
559ae771770SStanislav Sedov *
560ae771770SStanislav Sedov * @param context Keberos 5 context.
561ae771770SStanislav Sedov * @param in in ctx to krb5_rd_req_ctx().
562ae771770SStanislav Sedov * @param keytab keytab that krb5_rd_req_ctx() will use, only copy the
563ae771770SStanislav Sedov * pointer, so the caller must free they keytab after
564ae771770SStanislav Sedov * krb5_rd_req_in_ctx_free() is called.
565ae771770SStanislav Sedov *
566ae771770SStanislav Sedov * @return Kerberos 5 error code, see krb5_get_error_message().
567ae771770SStanislav Sedov *
568ae771770SStanislav Sedov * @ingroup krb5_auth
569ae771770SStanislav Sedov */
570ae771770SStanislav Sedov
571ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_in_set_keytab(krb5_context context,krb5_rd_req_in_ctx in,krb5_keytab keytab)572c19800e8SDoug Rabson krb5_rd_req_in_set_keytab(krb5_context context,
573c19800e8SDoug Rabson krb5_rd_req_in_ctx in,
574c19800e8SDoug Rabson krb5_keytab keytab)
575c19800e8SDoug Rabson {
576ae771770SStanislav Sedov in->keytab = keytab;
577c19800e8SDoug Rabson return 0;
578c19800e8SDoug Rabson }
579c19800e8SDoug Rabson
580c19800e8SDoug Rabson /**
581c19800e8SDoug Rabson * Set if krb5_rq_red() is going to check the Windows PAC or not
582c19800e8SDoug Rabson *
583c19800e8SDoug Rabson * @param context Keberos 5 context.
584c19800e8SDoug Rabson * @param in krb5_rd_req_in_ctx to check the option on.
585c19800e8SDoug Rabson * @param flag flag to select if to check the pac (TRUE) or not (FALSE).
586c19800e8SDoug Rabson *
587c19800e8SDoug Rabson * @return Kerberos 5 error code, see krb5_get_error_message().
588c19800e8SDoug Rabson *
589ae771770SStanislav Sedov * @ingroup krb5_auth
590c19800e8SDoug Rabson */
591c19800e8SDoug Rabson
592ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_in_set_pac_check(krb5_context context,krb5_rd_req_in_ctx in,krb5_boolean flag)593c19800e8SDoug Rabson krb5_rd_req_in_set_pac_check(krb5_context context,
594c19800e8SDoug Rabson krb5_rd_req_in_ctx in,
595c19800e8SDoug Rabson krb5_boolean flag)
596c19800e8SDoug Rabson {
597c19800e8SDoug Rabson in->check_pac = flag;
598c19800e8SDoug Rabson return 0;
599c19800e8SDoug Rabson }
600c19800e8SDoug Rabson
601c19800e8SDoug Rabson
602ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_in_set_keyblock(krb5_context context,krb5_rd_req_in_ctx in,krb5_keyblock * keyblock)603c19800e8SDoug Rabson krb5_rd_req_in_set_keyblock(krb5_context context,
604c19800e8SDoug Rabson krb5_rd_req_in_ctx in,
605c19800e8SDoug Rabson krb5_keyblock *keyblock)
606c19800e8SDoug Rabson {
607c19800e8SDoug Rabson in->keyblock = keyblock; /* XXX should make copy */
608c19800e8SDoug Rabson return 0;
609c19800e8SDoug Rabson }
610c19800e8SDoug Rabson
611ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_out_get_ap_req_options(krb5_context context,krb5_rd_req_out_ctx out,krb5_flags * ap_req_options)612c19800e8SDoug Rabson krb5_rd_req_out_get_ap_req_options(krb5_context context,
613c19800e8SDoug Rabson krb5_rd_req_out_ctx out,
614c19800e8SDoug Rabson krb5_flags *ap_req_options)
615c19800e8SDoug Rabson {
616c19800e8SDoug Rabson *ap_req_options = out->ap_req_options;
617c19800e8SDoug Rabson return 0;
618c19800e8SDoug Rabson }
619c19800e8SDoug Rabson
620ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_out_get_ticket(krb5_context context,krb5_rd_req_out_ctx out,krb5_ticket ** ticket)621c19800e8SDoug Rabson krb5_rd_req_out_get_ticket(krb5_context context,
622c19800e8SDoug Rabson krb5_rd_req_out_ctx out,
623c19800e8SDoug Rabson krb5_ticket **ticket)
624c19800e8SDoug Rabson {
625c19800e8SDoug Rabson return krb5_copy_ticket(context, out->ticket, ticket);
626c19800e8SDoug Rabson }
627c19800e8SDoug Rabson
628ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_out_get_keyblock(krb5_context context,krb5_rd_req_out_ctx out,krb5_keyblock ** keyblock)629c19800e8SDoug Rabson krb5_rd_req_out_get_keyblock(krb5_context context,
630c19800e8SDoug Rabson krb5_rd_req_out_ctx out,
631c19800e8SDoug Rabson krb5_keyblock **keyblock)
632c19800e8SDoug Rabson {
633c19800e8SDoug Rabson return krb5_copy_keyblock(context, out->keyblock, keyblock);
634c19800e8SDoug Rabson }
635c19800e8SDoug Rabson
636ae771770SStanislav Sedov /**
637ae771770SStanislav Sedov * Get the principal that was used in the request from the
638ae771770SStanislav Sedov * client. Might not match whats in the ticket if krb5_rd_req_ctx()
639ae771770SStanislav Sedov * searched in the keytab for a matching key.
640ae771770SStanislav Sedov *
641ae771770SStanislav Sedov * @param context a Kerberos 5 context.
642ae771770SStanislav Sedov * @param out a krb5_rd_req_out_ctx from krb5_rd_req_ctx().
643ae771770SStanislav Sedov * @param principal return principal, free with krb5_free_principal().
644ae771770SStanislav Sedov *
645ae771770SStanislav Sedov * @ingroup krb5_auth
646ae771770SStanislav Sedov */
647ae771770SStanislav Sedov
648ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_out_get_server(krb5_context context,krb5_rd_req_out_ctx out,krb5_principal * principal)649ae771770SStanislav Sedov krb5_rd_req_out_get_server(krb5_context context,
650ae771770SStanislav Sedov krb5_rd_req_out_ctx out,
651ae771770SStanislav Sedov krb5_principal *principal)
652ae771770SStanislav Sedov {
653ae771770SStanislav Sedov return krb5_copy_principal(context, out->server, principal);
654ae771770SStanislav Sedov }
655ae771770SStanislav Sedov
656ae771770SStanislav Sedov KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_rd_req_in_ctx_free(krb5_context context,krb5_rd_req_in_ctx ctx)657c19800e8SDoug Rabson krb5_rd_req_in_ctx_free(krb5_context context, krb5_rd_req_in_ctx ctx)
658c19800e8SDoug Rabson {
659c19800e8SDoug Rabson free(ctx);
660c19800e8SDoug Rabson }
661c19800e8SDoug Rabson
662ae771770SStanislav Sedov /**
663ae771770SStanislav Sedov * Free the krb5_rd_req_out_ctx.
664ae771770SStanislav Sedov *
665ae771770SStanislav Sedov * @param context Keberos 5 context.
666ae771770SStanislav Sedov * @param ctx krb5_rd_req_out_ctx context to free.
667ae771770SStanislav Sedov *
668ae771770SStanislav Sedov * @ingroup krb5_auth
669ae771770SStanislav Sedov */
670c19800e8SDoug Rabson
671ae771770SStanislav Sedov KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_rd_req_out_ctx_free(krb5_context context,krb5_rd_req_out_ctx ctx)672c19800e8SDoug Rabson krb5_rd_req_out_ctx_free(krb5_context context, krb5_rd_req_out_ctx ctx)
673c19800e8SDoug Rabson {
674ae771770SStanislav Sedov if (ctx->ticket)
675ae771770SStanislav Sedov krb5_free_ticket(context, ctx->ticket);
676ae771770SStanislav Sedov if (ctx->keyblock)
677c19800e8SDoug Rabson krb5_free_keyblock(context, ctx->keyblock);
678ae771770SStanislav Sedov if (ctx->server)
679ae771770SStanislav Sedov krb5_free_principal(context, ctx->server);
680c19800e8SDoug Rabson free(ctx);
681c19800e8SDoug Rabson }
682c19800e8SDoug Rabson
683c19800e8SDoug Rabson /*
684c19800e8SDoug Rabson *
685c19800e8SDoug Rabson */
686c19800e8SDoug Rabson
687ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req(krb5_context context,krb5_auth_context * auth_context,const krb5_data * inbuf,krb5_const_principal server,krb5_keytab keytab,krb5_flags * ap_req_options,krb5_ticket ** ticket)688c19800e8SDoug Rabson krb5_rd_req(krb5_context context,
689c19800e8SDoug Rabson krb5_auth_context *auth_context,
690c19800e8SDoug Rabson const krb5_data *inbuf,
691c19800e8SDoug Rabson krb5_const_principal server,
692c19800e8SDoug Rabson krb5_keytab keytab,
693c19800e8SDoug Rabson krb5_flags *ap_req_options,
694c19800e8SDoug Rabson krb5_ticket **ticket)
695c19800e8SDoug Rabson {
696c19800e8SDoug Rabson krb5_error_code ret;
697c19800e8SDoug Rabson krb5_rd_req_in_ctx in;
698c19800e8SDoug Rabson krb5_rd_req_out_ctx out;
699c19800e8SDoug Rabson
700c19800e8SDoug Rabson ret = krb5_rd_req_in_ctx_alloc(context, &in);
701c19800e8SDoug Rabson if (ret)
702c19800e8SDoug Rabson return ret;
703c19800e8SDoug Rabson
704c19800e8SDoug Rabson ret = krb5_rd_req_in_set_keytab(context, in, keytab);
705c19800e8SDoug Rabson if (ret) {
706c19800e8SDoug Rabson krb5_rd_req_in_ctx_free(context, in);
707c19800e8SDoug Rabson return ret;
708c19800e8SDoug Rabson }
709c19800e8SDoug Rabson
710c19800e8SDoug Rabson ret = krb5_rd_req_ctx(context, auth_context, inbuf, server, in, &out);
711c19800e8SDoug Rabson krb5_rd_req_in_ctx_free(context, in);
712c19800e8SDoug Rabson if (ret)
713c19800e8SDoug Rabson return ret;
714c19800e8SDoug Rabson
715c19800e8SDoug Rabson if (ap_req_options)
716c19800e8SDoug Rabson *ap_req_options = out->ap_req_options;
717c19800e8SDoug Rabson if (ticket) {
718c19800e8SDoug Rabson ret = krb5_copy_ticket(context, out->ticket, ticket);
719c19800e8SDoug Rabson if (ret)
720c19800e8SDoug Rabson goto out;
721c19800e8SDoug Rabson }
722c19800e8SDoug Rabson
723c19800e8SDoug Rabson out:
724c19800e8SDoug Rabson krb5_rd_req_out_ctx_free(context, out);
725c19800e8SDoug Rabson return ret;
726c19800e8SDoug Rabson }
727c19800e8SDoug Rabson
728c19800e8SDoug Rabson /*
729c19800e8SDoug Rabson *
730c19800e8SDoug Rabson */
731c19800e8SDoug Rabson
732ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_with_keyblock(krb5_context context,krb5_auth_context * auth_context,const krb5_data * inbuf,krb5_const_principal server,krb5_keyblock * keyblock,krb5_flags * ap_req_options,krb5_ticket ** ticket)733b528cefcSMark Murray krb5_rd_req_with_keyblock(krb5_context context,
734b528cefcSMark Murray krb5_auth_context *auth_context,
735b528cefcSMark Murray const krb5_data *inbuf,
736b528cefcSMark Murray krb5_const_principal server,
737b528cefcSMark Murray krb5_keyblock *keyblock,
738b528cefcSMark Murray krb5_flags *ap_req_options,
739b528cefcSMark Murray krb5_ticket **ticket)
740b528cefcSMark Murray {
741b528cefcSMark Murray krb5_error_code ret;
742c19800e8SDoug Rabson krb5_rd_req_in_ctx in;
743c19800e8SDoug Rabson krb5_rd_req_out_ctx out;
744b528cefcSMark Murray
745c19800e8SDoug Rabson ret = krb5_rd_req_in_ctx_alloc(context, &in);
746b528cefcSMark Murray if (ret)
747b528cefcSMark Murray return ret;
748b528cefcSMark Murray
749c19800e8SDoug Rabson ret = krb5_rd_req_in_set_keyblock(context, in, keyblock);
750c19800e8SDoug Rabson if (ret) {
751c19800e8SDoug Rabson krb5_rd_req_in_ctx_free(context, in);
752b528cefcSMark Murray return ret;
753b528cefcSMark Murray }
754b528cefcSMark Murray
755c19800e8SDoug Rabson ret = krb5_rd_req_ctx(context, auth_context, inbuf, server, in, &out);
756c19800e8SDoug Rabson krb5_rd_req_in_ctx_free(context, in);
757c19800e8SDoug Rabson if (ret)
758c19800e8SDoug Rabson return ret;
759c19800e8SDoug Rabson
760c19800e8SDoug Rabson if (ap_req_options)
761c19800e8SDoug Rabson *ap_req_options = out->ap_req_options;
762c19800e8SDoug Rabson if (ticket) {
763c19800e8SDoug Rabson ret = krb5_copy_ticket(context, out->ticket, ticket);
764c19800e8SDoug Rabson if (ret)
765c19800e8SDoug Rabson goto out;
766c19800e8SDoug Rabson }
767c19800e8SDoug Rabson
768c19800e8SDoug Rabson out:
769c19800e8SDoug Rabson krb5_rd_req_out_ctx_free(context, out);
770c19800e8SDoug Rabson return ret;
771c19800e8SDoug Rabson }
772c19800e8SDoug Rabson
773c19800e8SDoug Rabson /*
774c19800e8SDoug Rabson *
775c19800e8SDoug Rabson */
776c19800e8SDoug Rabson
777b528cefcSMark Murray static krb5_error_code
get_key_from_keytab(krb5_context context,krb5_ap_req * ap_req,krb5_const_principal server,krb5_keytab keytab,krb5_keyblock ** out_key)778b528cefcSMark Murray get_key_from_keytab(krb5_context context,
779b528cefcSMark Murray krb5_ap_req *ap_req,
780b528cefcSMark Murray krb5_const_principal server,
781b528cefcSMark Murray krb5_keytab keytab,
78213e3f4d6SMark Murray krb5_keyblock **out_key)
783b528cefcSMark Murray {
784b528cefcSMark Murray krb5_keytab_entry entry;
785b528cefcSMark Murray krb5_error_code ret;
786b528cefcSMark Murray int kvno;
787b528cefcSMark Murray krb5_keytab real_keytab;
788b528cefcSMark Murray
789b528cefcSMark Murray if(keytab == NULL)
790b528cefcSMark Murray krb5_kt_default(context, &real_keytab);
791b528cefcSMark Murray else
792b528cefcSMark Murray real_keytab = keytab;
793b528cefcSMark Murray
794b528cefcSMark Murray if (ap_req->ticket.enc_part.kvno)
795b528cefcSMark Murray kvno = *ap_req->ticket.enc_part.kvno;
796b528cefcSMark Murray else
797b528cefcSMark Murray kvno = 0;
798b528cefcSMark Murray
799b528cefcSMark Murray ret = krb5_kt_get_entry (context,
800b528cefcSMark Murray real_keytab,
801b528cefcSMark Murray server,
802b528cefcSMark Murray kvno,
803b528cefcSMark Murray ap_req->ticket.enc_part.etype,
804b528cefcSMark Murray &entry);
805*ed549cb0SCy Schubert if(ret == 0) {
80613e3f4d6SMark Murray ret = krb5_copy_keyblock(context, &entry.keyblock, out_key);
807b528cefcSMark Murray krb5_kt_free_entry(context, &entry);
808*ed549cb0SCy Schubert }
809b528cefcSMark Murray if(keytab == NULL)
810b528cefcSMark Murray krb5_kt_close(context, real_keytab);
811b528cefcSMark Murray
812b528cefcSMark Murray return ret;
813b528cefcSMark Murray }
814b528cefcSMark Murray
815ae771770SStanislav Sedov /**
816ae771770SStanislav Sedov * The core server function that verify application authentication
817ae771770SStanislav Sedov * requests from clients.
818c19800e8SDoug Rabson *
819ae771770SStanislav Sedov * @param context Keberos 5 context.
820ae771770SStanislav Sedov * @param auth_context the authentication context, can be NULL, then
821ae771770SStanislav Sedov * default values for the authentication context will used.
822ae771770SStanislav Sedov * @param inbuf the (AP-REQ) authentication buffer
823ae771770SStanislav Sedov *
824ae771770SStanislav Sedov * @param server the server with authenticate as, if NULL the function
825ae771770SStanislav Sedov * will try to find any available credential in the keytab
826ae771770SStanislav Sedov * that will verify the reply. The function will prefer the
827ae771770SStanislav Sedov * server the server client specified in the AP-REQ, but if
828ae771770SStanislav Sedov * there is no mach, it will try all keytab entries for a
829ae771770SStanislav Sedov * match. This have serious performance issues for larger keytabs.
830ae771770SStanislav Sedov *
831ae771770SStanislav Sedov * @param inctx control the behavior of the function, if NULL, the
832ae771770SStanislav Sedov * default behavior is used.
833ae771770SStanislav Sedov * @param outctx the return outctx, free with krb5_rd_req_out_ctx_free().
834ae771770SStanislav Sedov * @return Kerberos 5 error code, see krb5_get_error_message().
835ae771770SStanislav Sedov *
836ae771770SStanislav Sedov * @ingroup krb5_auth
837c19800e8SDoug Rabson */
838c19800e8SDoug Rabson
839ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_ctx(krb5_context context,krb5_auth_context * auth_context,const krb5_data * inbuf,krb5_const_principal server,krb5_rd_req_in_ctx inctx,krb5_rd_req_out_ctx * outctx)840c19800e8SDoug Rabson krb5_rd_req_ctx(krb5_context context,
841b528cefcSMark Murray krb5_auth_context *auth_context,
842b528cefcSMark Murray const krb5_data *inbuf,
843b528cefcSMark Murray krb5_const_principal server,
844c19800e8SDoug Rabson krb5_rd_req_in_ctx inctx,
845c19800e8SDoug Rabson krb5_rd_req_out_ctx *outctx)
846b528cefcSMark Murray {
847b528cefcSMark Murray krb5_error_code ret;
848b528cefcSMark Murray krb5_ap_req ap_req;
849c19800e8SDoug Rabson krb5_rd_req_out_ctx o = NULL;
850ae771770SStanislav Sedov krb5_keytab id = NULL, keytab = NULL;
851ae771770SStanislav Sedov krb5_principal service = NULL;
852c19800e8SDoug Rabson
853ae771770SStanislav Sedov *outctx = NULL;
854ae771770SStanislav Sedov
855ae771770SStanislav Sedov o = calloc(1, sizeof(*o));
856ae771770SStanislav Sedov if (o == NULL) {
857ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM,
858ae771770SStanislav Sedov N_("malloc: out of memory", ""));
859ae771770SStanislav Sedov return ENOMEM;
860ae771770SStanislav Sedov }
861b528cefcSMark Murray
862b528cefcSMark Murray if (*auth_context == NULL) {
863b528cefcSMark Murray ret = krb5_auth_con_init(context, auth_context);
864b528cefcSMark Murray if (ret)
865c19800e8SDoug Rabson goto out;
866b528cefcSMark Murray }
867b528cefcSMark Murray
868b528cefcSMark Murray ret = krb5_decode_ap_req(context, inbuf, &ap_req);
869b528cefcSMark Murray if(ret)
870c19800e8SDoug Rabson goto out;
871b528cefcSMark Murray
872ae771770SStanislav Sedov /* Save that principal that was in the request */
873ae771770SStanislav Sedov ret = _krb5_principalname2krb5_principal(context,
874ae771770SStanislav Sedov &o->server,
875ae771770SStanislav Sedov ap_req.ticket.sname,
876ae771770SStanislav Sedov ap_req.ticket.realm);
877ae771770SStanislav Sedov if (ret)
878ae771770SStanislav Sedov goto out;
879ae771770SStanislav Sedov
880ae771770SStanislav Sedov if (ap_req.ap_options.use_session_key &&
881ae771770SStanislav Sedov (*auth_context)->keyblock == NULL) {
882ae771770SStanislav Sedov ret = KRB5KRB_AP_ERR_NOKEY;
883ae771770SStanislav Sedov krb5_set_error_message(context, ret,
884ae771770SStanislav Sedov N_("krb5_rd_req: user to user auth "
885ae771770SStanislav Sedov "without session key given", ""));
886ae771770SStanislav Sedov goto out;
887ae771770SStanislav Sedov }
888ae771770SStanislav Sedov
889ae771770SStanislav Sedov if (inctx && inctx->keytab)
890ae771770SStanislav Sedov id = inctx->keytab;
891ae771770SStanislav Sedov
892ae771770SStanislav Sedov if((*auth_context)->keyblock){
893ae771770SStanislav Sedov ret = krb5_copy_keyblock(context,
894ae771770SStanislav Sedov (*auth_context)->keyblock,
895ae771770SStanislav Sedov &o->keyblock);
896ae771770SStanislav Sedov if (ret)
897ae771770SStanislav Sedov goto out;
898ae771770SStanislav Sedov } else if(inctx && inctx->keyblock){
899ae771770SStanislav Sedov ret = krb5_copy_keyblock(context,
900ae771770SStanislav Sedov inctx->keyblock,
901ae771770SStanislav Sedov &o->keyblock);
902ae771770SStanislav Sedov if (ret)
903ae771770SStanislav Sedov goto out;
904ae771770SStanislav Sedov } else {
905ae771770SStanislav Sedov
906ae771770SStanislav Sedov if(id == NULL) {
907ae771770SStanislav Sedov krb5_kt_default(context, &keytab);
908ae771770SStanislav Sedov id = keytab;
909ae771770SStanislav Sedov }
910ae771770SStanislav Sedov if (id == NULL)
911ae771770SStanislav Sedov goto out;
912ae771770SStanislav Sedov
913b528cefcSMark Murray if (server == NULL) {
914c19800e8SDoug Rabson ret = _krb5_principalname2krb5_principal(context,
915c19800e8SDoug Rabson &service,
916b528cefcSMark Murray ap_req.ticket.sname,
917b528cefcSMark Murray ap_req.ticket.realm);
918c19800e8SDoug Rabson if (ret)
919c19800e8SDoug Rabson goto out;
920b528cefcSMark Murray server = service;
921b528cefcSMark Murray }
922c19800e8SDoug Rabson
923b528cefcSMark Murray ret = get_key_from_keytab(context,
924b528cefcSMark Murray &ap_req,
925b528cefcSMark Murray server,
926ae771770SStanislav Sedov id,
927c19800e8SDoug Rabson &o->keyblock);
928ae771770SStanislav Sedov if (ret) {
929ae771770SStanislav Sedov /* If caller specified a server, fail. */
930ae771770SStanislav Sedov if (service == NULL && (context->flags & KRB5_CTX_F_RD_REQ_IGNORE) == 0)
9311c43270aSJacques Vidrine goto out;
932ae771770SStanislav Sedov /* Otherwise, fall back to iterating over the keytab. This
933ae771770SStanislav Sedov * have serious performace issues for larger keytab.
934ae771770SStanislav Sedov */
935ae771770SStanislav Sedov o->keyblock = NULL;
936b528cefcSMark Murray }
937ae771770SStanislav Sedov }
938ae771770SStanislav Sedov
939ae771770SStanislav Sedov if (o->keyblock) {
940ae771770SStanislav Sedov /*
941ae771770SStanislav Sedov * We got an exact keymatch, use that.
942ae771770SStanislav Sedov */
943b528cefcSMark Murray
944c19800e8SDoug Rabson ret = krb5_verify_ap_req2(context,
945b528cefcSMark Murray auth_context,
946b528cefcSMark Murray &ap_req,
947b528cefcSMark Murray server,
948c19800e8SDoug Rabson o->keyblock,
949b528cefcSMark Murray 0,
950c19800e8SDoug Rabson &o->ap_req_options,
951c19800e8SDoug Rabson &o->ticket,
952c19800e8SDoug Rabson KRB5_KU_AP_REQ_AUTH);
953b528cefcSMark Murray
954c19800e8SDoug Rabson if (ret)
955c19800e8SDoug Rabson goto out;
956b528cefcSMark Murray
957ae771770SStanislav Sedov } else {
958ae771770SStanislav Sedov /*
959ae771770SStanislav Sedov * Interate over keytab to find a key that can decrypt the request.
960ae771770SStanislav Sedov */
961ae771770SStanislav Sedov
962ae771770SStanislav Sedov krb5_keytab_entry entry;
963ae771770SStanislav Sedov krb5_kt_cursor cursor;
964ae771770SStanislav Sedov int done = 0, kvno = 0;
965ae771770SStanislav Sedov
966ae771770SStanislav Sedov memset(&cursor, 0, sizeof(cursor));
967ae771770SStanislav Sedov
968ae771770SStanislav Sedov if (ap_req.ticket.enc_part.kvno)
969ae771770SStanislav Sedov kvno = *ap_req.ticket.enc_part.kvno;
970ae771770SStanislav Sedov
971ae771770SStanislav Sedov ret = krb5_kt_start_seq_get(context, id, &cursor);
972ae771770SStanislav Sedov if (ret)
973ae771770SStanislav Sedov goto out;
974ae771770SStanislav Sedov
975ae771770SStanislav Sedov done = 0;
976ae771770SStanislav Sedov while (!done) {
977ae771770SStanislav Sedov krb5_principal p;
978ae771770SStanislav Sedov
979ae771770SStanislav Sedov ret = krb5_kt_next_entry(context, id, &entry, &cursor);
980ae771770SStanislav Sedov if (ret) {
981ae771770SStanislav Sedov _krb5_kt_principal_not_found(context, ret, id, o->server,
982ae771770SStanislav Sedov ap_req.ticket.enc_part.etype,
983ae771770SStanislav Sedov kvno);
984ae771770SStanislav Sedov goto out;
985ae771770SStanislav Sedov }
986ae771770SStanislav Sedov
987ae771770SStanislav Sedov if (entry.keyblock.keytype != ap_req.ticket.enc_part.etype) {
988ae771770SStanislav Sedov krb5_kt_free_entry (context, &entry);
989ae771770SStanislav Sedov continue;
990ae771770SStanislav Sedov }
991ae771770SStanislav Sedov
992ae771770SStanislav Sedov ret = krb5_verify_ap_req2(context,
993ae771770SStanislav Sedov auth_context,
994ae771770SStanislav Sedov &ap_req,
995ae771770SStanislav Sedov server,
996ae771770SStanislav Sedov &entry.keyblock,
997ae771770SStanislav Sedov 0,
998ae771770SStanislav Sedov &o->ap_req_options,
999ae771770SStanislav Sedov &o->ticket,
1000ae771770SStanislav Sedov KRB5_KU_AP_REQ_AUTH);
1001ae771770SStanislav Sedov if (ret) {
1002ae771770SStanislav Sedov krb5_kt_free_entry (context, &entry);
1003ae771770SStanislav Sedov continue;
1004ae771770SStanislav Sedov }
1005ae771770SStanislav Sedov
1006ae771770SStanislav Sedov /*
1007ae771770SStanislav Sedov * Found a match, save the keyblock for PAC processing,
1008ae771770SStanislav Sedov * and update the service principal in the ticket to match
1009ae771770SStanislav Sedov * whatever is in the keytab.
1010ae771770SStanislav Sedov */
1011ae771770SStanislav Sedov
1012ae771770SStanislav Sedov ret = krb5_copy_keyblock(context,
1013ae771770SStanislav Sedov &entry.keyblock,
1014ae771770SStanislav Sedov &o->keyblock);
1015ae771770SStanislav Sedov if (ret) {
1016ae771770SStanislav Sedov krb5_kt_free_entry (context, &entry);
1017ae771770SStanislav Sedov goto out;
1018ae771770SStanislav Sedov }
1019ae771770SStanislav Sedov
1020ae771770SStanislav Sedov ret = krb5_copy_principal(context, entry.principal, &p);
1021ae771770SStanislav Sedov if (ret) {
1022ae771770SStanislav Sedov krb5_kt_free_entry (context, &entry);
1023ae771770SStanislav Sedov goto out;
1024ae771770SStanislav Sedov }
1025ae771770SStanislav Sedov krb5_free_principal(context, o->ticket->server);
1026ae771770SStanislav Sedov o->ticket->server = p;
1027ae771770SStanislav Sedov
1028ae771770SStanislav Sedov krb5_kt_free_entry (context, &entry);
1029ae771770SStanislav Sedov
1030ae771770SStanislav Sedov done = 1;
1031ae771770SStanislav Sedov }
1032ae771770SStanislav Sedov krb5_kt_end_seq_get (context, id, &cursor);
1033ae771770SStanislav Sedov }
1034ae771770SStanislav Sedov
1035c19800e8SDoug Rabson /* If there is a PAC, verify its server signature */
1036ae771770SStanislav Sedov if (inctx == NULL || inctx->check_pac) {
1037c19800e8SDoug Rabson krb5_pac pac;
1038c19800e8SDoug Rabson krb5_data data;
1039c19800e8SDoug Rabson
1040c19800e8SDoug Rabson ret = krb5_ticket_get_authorization_data_type(context,
1041c19800e8SDoug Rabson o->ticket,
1042c19800e8SDoug Rabson KRB5_AUTHDATA_WIN2K_PAC,
1043c19800e8SDoug Rabson &data);
1044c19800e8SDoug Rabson if (ret == 0) {
1045c19800e8SDoug Rabson ret = krb5_pac_parse(context, data.data, data.length, &pac);
1046c19800e8SDoug Rabson krb5_data_free(&data);
1047c19800e8SDoug Rabson if (ret)
1048c19800e8SDoug Rabson goto out;
1049c19800e8SDoug Rabson
1050c19800e8SDoug Rabson ret = krb5_pac_verify(context,
1051c19800e8SDoug Rabson pac,
1052c19800e8SDoug Rabson o->ticket->ticket.authtime,
1053c19800e8SDoug Rabson o->ticket->client,
1054c19800e8SDoug Rabson o->keyblock,
1055c19800e8SDoug Rabson NULL);
1056c19800e8SDoug Rabson krb5_pac_free(context, pac);
1057c19800e8SDoug Rabson if (ret)
1058c19800e8SDoug Rabson goto out;
1059ae771770SStanislav Sedov } else
1060c19800e8SDoug Rabson ret = 0;
1061c19800e8SDoug Rabson }
1062b528cefcSMark Murray out:
1063ae771770SStanislav Sedov
1064c19800e8SDoug Rabson if (ret || outctx == NULL) {
1065c19800e8SDoug Rabson krb5_rd_req_out_ctx_free(context, o);
1066c19800e8SDoug Rabson } else
1067c19800e8SDoug Rabson *outctx = o;
1068c19800e8SDoug Rabson
1069b528cefcSMark Murray free_AP_REQ(&ap_req);
1070ae771770SStanislav Sedov
1071b528cefcSMark Murray if (service)
1072b528cefcSMark Murray krb5_free_principal(context, service);
1073ae771770SStanislav Sedov
1074ae771770SStanislav Sedov if (keytab)
1075ae771770SStanislav Sedov krb5_kt_close(context, keytab);
1076ae771770SStanislav Sedov
1077b528cefcSMark Murray return ret;
1078b528cefcSMark Murray }
1079