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