1c19800e8SDoug Rabson /*
2ae771770SStanislav Sedov * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
3c19800e8SDoug Rabson * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson * All rights reserved.
5c19800e8SDoug Rabson *
6c19800e8SDoug Rabson * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson * are met:
9c19800e8SDoug Rabson *
10c19800e8SDoug Rabson * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson *
13c19800e8SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson * documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson *
17c19800e8SDoug Rabson * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson * may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson * without specific prior written permission.
20c19800e8SDoug Rabson *
21c19800e8SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson * SUCH DAMAGE.
32c19800e8SDoug Rabson */
33c19800e8SDoug Rabson
34ae771770SStanislav Sedov #include "gsskrb5_locl.h"
35c19800e8SDoug Rabson
36c19800e8SDoug Rabson HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
37c19800e8SDoug Rabson krb5_keytab _gsskrb5_keytab;
38c19800e8SDoug Rabson
39ae771770SStanislav Sedov static krb5_error_code
validate_keytab(krb5_context context,const char * name,krb5_keytab * id)40ae771770SStanislav Sedov validate_keytab(krb5_context context, const char *name, krb5_keytab *id)
41ae771770SStanislav Sedov {
42ae771770SStanislav Sedov krb5_error_code ret;
43ae771770SStanislav Sedov
44ae771770SStanislav Sedov ret = krb5_kt_resolve(context, name, id);
45ae771770SStanislav Sedov if (ret)
46ae771770SStanislav Sedov return ret;
47ae771770SStanislav Sedov
48ae771770SStanislav Sedov ret = krb5_kt_have_content(context, *id);
49ae771770SStanislav Sedov if (ret) {
50ae771770SStanislav Sedov krb5_kt_close(context, *id);
51ae771770SStanislav Sedov *id = NULL;
52ae771770SStanislav Sedov }
53ae771770SStanislav Sedov
54ae771770SStanislav Sedov return ret;
55ae771770SStanislav Sedov }
56ae771770SStanislav Sedov
57c19800e8SDoug Rabson OM_uint32
_gsskrb5_register_acceptor_identity(OM_uint32 * min_stat,const char * identity)58ae771770SStanislav Sedov _gsskrb5_register_acceptor_identity(OM_uint32 *min_stat, const char *identity)
59c19800e8SDoug Rabson {
60c19800e8SDoug Rabson krb5_context context;
61c19800e8SDoug Rabson krb5_error_code ret;
62c19800e8SDoug Rabson
63ae771770SStanislav Sedov *min_stat = 0;
64ae771770SStanislav Sedov
65c19800e8SDoug Rabson ret = _gsskrb5_init(&context);
66c19800e8SDoug Rabson if(ret)
67c19800e8SDoug Rabson return GSS_S_FAILURE;
68c19800e8SDoug Rabson
69c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
70c19800e8SDoug Rabson
71c19800e8SDoug Rabson if(_gsskrb5_keytab != NULL) {
72c19800e8SDoug Rabson krb5_kt_close(context, _gsskrb5_keytab);
73c19800e8SDoug Rabson _gsskrb5_keytab = NULL;
74c19800e8SDoug Rabson }
75c19800e8SDoug Rabson if (identity == NULL) {
76c19800e8SDoug Rabson ret = krb5_kt_default(context, &_gsskrb5_keytab);
77c19800e8SDoug Rabson } else {
78ae771770SStanislav Sedov /*
79ae771770SStanislav Sedov * First check if we can the keytab as is and if it has content...
80ae771770SStanislav Sedov */
81ae771770SStanislav Sedov ret = validate_keytab(context, identity, &_gsskrb5_keytab);
82ae771770SStanislav Sedov /*
83ae771770SStanislav Sedov * if it doesn't, lets prepend FILE: and try again
84ae771770SStanislav Sedov */
85ae771770SStanislav Sedov if (ret) {
86ae771770SStanislav Sedov char *p = NULL;
87ae771770SStanislav Sedov ret = asprintf(&p, "FILE:%s", identity);
88ae771770SStanislav Sedov if(ret < 0 || p == NULL) {
89c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
90c19800e8SDoug Rabson return GSS_S_FAILURE;
91c19800e8SDoug Rabson }
92ae771770SStanislav Sedov ret = validate_keytab(context, p, &_gsskrb5_keytab);
93c19800e8SDoug Rabson free(p);
94c19800e8SDoug Rabson }
95ae771770SStanislav Sedov }
96c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
97ae771770SStanislav Sedov if(ret) {
98ae771770SStanislav Sedov *min_stat = ret;
99c19800e8SDoug Rabson return GSS_S_FAILURE;
100ae771770SStanislav Sedov }
101c19800e8SDoug Rabson return GSS_S_COMPLETE;
102c19800e8SDoug Rabson }
103c19800e8SDoug Rabson
104c19800e8SDoug Rabson void
_gsskrb5i_is_cfx(krb5_context context,gsskrb5_ctx ctx,int acceptor)105ae771770SStanislav Sedov _gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor)
106c19800e8SDoug Rabson {
107ae771770SStanislav Sedov krb5_error_code ret;
108c19800e8SDoug Rabson krb5_keyblock *key;
109c19800e8SDoug Rabson
110c19800e8SDoug Rabson if (acceptor) {
111c19800e8SDoug Rabson if (ctx->auth_context->local_subkey)
112c19800e8SDoug Rabson key = ctx->auth_context->local_subkey;
113c19800e8SDoug Rabson else
114c19800e8SDoug Rabson key = ctx->auth_context->remote_subkey;
115c19800e8SDoug Rabson } else {
116c19800e8SDoug Rabson if (ctx->auth_context->remote_subkey)
117c19800e8SDoug Rabson key = ctx->auth_context->remote_subkey;
118c19800e8SDoug Rabson else
119c19800e8SDoug Rabson key = ctx->auth_context->local_subkey;
120c19800e8SDoug Rabson }
121c19800e8SDoug Rabson if (key == NULL)
122c19800e8SDoug Rabson key = ctx->auth_context->keyblock;
123c19800e8SDoug Rabson
124c19800e8SDoug Rabson if (key == NULL)
125c19800e8SDoug Rabson return;
126c19800e8SDoug Rabson
127c19800e8SDoug Rabson switch (key->keytype) {
128c19800e8SDoug Rabson case ETYPE_DES_CBC_CRC:
129c19800e8SDoug Rabson case ETYPE_DES_CBC_MD4:
130c19800e8SDoug Rabson case ETYPE_DES_CBC_MD5:
131c19800e8SDoug Rabson case ETYPE_DES3_CBC_MD5:
132ae771770SStanislav Sedov case ETYPE_OLD_DES3_CBC_SHA1:
133c19800e8SDoug Rabson case ETYPE_DES3_CBC_SHA1:
134c19800e8SDoug Rabson case ETYPE_ARCFOUR_HMAC_MD5:
135c19800e8SDoug Rabson case ETYPE_ARCFOUR_HMAC_MD5_56:
136c19800e8SDoug Rabson break;
137c19800e8SDoug Rabson default :
138ae771770SStanislav Sedov ctx->more_flags |= IS_CFX;
139ae771770SStanislav Sedov
140c19800e8SDoug Rabson if ((acceptor && ctx->auth_context->local_subkey) ||
141c19800e8SDoug Rabson (!acceptor && ctx->auth_context->remote_subkey))
142c19800e8SDoug Rabson ctx->more_flags |= ACCEPTOR_SUBKEY;
143c19800e8SDoug Rabson break;
144c19800e8SDoug Rabson }
145ae771770SStanislav Sedov if (ctx->crypto)
146ae771770SStanislav Sedov krb5_crypto_destroy(context, ctx->crypto);
147ae771770SStanislav Sedov ret = krb5_crypto_init(context, key, 0, &ctx->crypto);
148c19800e8SDoug Rabson }
149c19800e8SDoug Rabson
150c19800e8SDoug Rabson
151c19800e8SDoug Rabson static OM_uint32
gsskrb5_accept_delegated_token(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,gss_cred_id_t * delegated_cred_handle)152c19800e8SDoug Rabson gsskrb5_accept_delegated_token
153c19800e8SDoug Rabson (OM_uint32 * minor_status,
154c19800e8SDoug Rabson gsskrb5_ctx ctx,
155c19800e8SDoug Rabson krb5_context context,
156c19800e8SDoug Rabson gss_cred_id_t * delegated_cred_handle
157c19800e8SDoug Rabson )
158c19800e8SDoug Rabson {
159c19800e8SDoug Rabson krb5_ccache ccache = NULL;
160c19800e8SDoug Rabson krb5_error_code kret;
161c19800e8SDoug Rabson int32_t ac_flags, ret = GSS_S_COMPLETE;
162c19800e8SDoug Rabson
163c19800e8SDoug Rabson *minor_status = 0;
164c19800e8SDoug Rabson
165c19800e8SDoug Rabson /* XXX Create a new delegated_cred_handle? */
166c19800e8SDoug Rabson if (delegated_cred_handle == NULL) {
167c19800e8SDoug Rabson kret = krb5_cc_default (context, &ccache);
168c19800e8SDoug Rabson } else {
169c19800e8SDoug Rabson *delegated_cred_handle = NULL;
170ae771770SStanislav Sedov kret = krb5_cc_new_unique (context, krb5_cc_type_memory,
171ae771770SStanislav Sedov NULL, &ccache);
172c19800e8SDoug Rabson }
173c19800e8SDoug Rabson if (kret) {
174c19800e8SDoug Rabson ctx->flags &= ~GSS_C_DELEG_FLAG;
175c19800e8SDoug Rabson goto out;
176c19800e8SDoug Rabson }
177c19800e8SDoug Rabson
178c19800e8SDoug Rabson kret = krb5_cc_initialize(context, ccache, ctx->source);
179c19800e8SDoug Rabson if (kret) {
180c19800e8SDoug Rabson ctx->flags &= ~GSS_C_DELEG_FLAG;
181c19800e8SDoug Rabson goto out;
182c19800e8SDoug Rabson }
183c19800e8SDoug Rabson
184c19800e8SDoug Rabson krb5_auth_con_removeflags(context,
185c19800e8SDoug Rabson ctx->auth_context,
186c19800e8SDoug Rabson KRB5_AUTH_CONTEXT_DO_TIME,
187c19800e8SDoug Rabson &ac_flags);
188c19800e8SDoug Rabson kret = krb5_rd_cred2(context,
189c19800e8SDoug Rabson ctx->auth_context,
190c19800e8SDoug Rabson ccache,
191c19800e8SDoug Rabson &ctx->fwd_data);
192c19800e8SDoug Rabson krb5_auth_con_setflags(context,
193c19800e8SDoug Rabson ctx->auth_context,
194c19800e8SDoug Rabson ac_flags);
195c19800e8SDoug Rabson if (kret) {
196c19800e8SDoug Rabson ctx->flags &= ~GSS_C_DELEG_FLAG;
197c19800e8SDoug Rabson ret = GSS_S_FAILURE;
198c19800e8SDoug Rabson *minor_status = kret;
199c19800e8SDoug Rabson goto out;
200c19800e8SDoug Rabson }
201c19800e8SDoug Rabson
202c19800e8SDoug Rabson if (delegated_cred_handle) {
203c19800e8SDoug Rabson gsskrb5_cred handle;
204c19800e8SDoug Rabson
205ae771770SStanislav Sedov ret = _gsskrb5_krb5_import_cred(minor_status,
206c19800e8SDoug Rabson ccache,
207c19800e8SDoug Rabson NULL,
208c19800e8SDoug Rabson NULL,
209c19800e8SDoug Rabson delegated_cred_handle);
210c19800e8SDoug Rabson if (ret != GSS_S_COMPLETE)
211c19800e8SDoug Rabson goto out;
212c19800e8SDoug Rabson
213c19800e8SDoug Rabson handle = (gsskrb5_cred) *delegated_cred_handle;
214c19800e8SDoug Rabson
215c19800e8SDoug Rabson handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
216c19800e8SDoug Rabson krb5_cc_close(context, ccache);
217c19800e8SDoug Rabson ccache = NULL;
218c19800e8SDoug Rabson }
219c19800e8SDoug Rabson
220c19800e8SDoug Rabson out:
221c19800e8SDoug Rabson if (ccache) {
222c19800e8SDoug Rabson /* Don't destroy the default cred cache */
223c19800e8SDoug Rabson if (delegated_cred_handle == NULL)
224c19800e8SDoug Rabson krb5_cc_close(context, ccache);
225c19800e8SDoug Rabson else
226c19800e8SDoug Rabson krb5_cc_destroy(context, ccache);
227c19800e8SDoug Rabson }
228c19800e8SDoug Rabson return ret;
229c19800e8SDoug Rabson }
230c19800e8SDoug Rabson
231c19800e8SDoug Rabson static OM_uint32
gsskrb5_acceptor_ready(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,gss_cred_id_t * delegated_cred_handle)232c19800e8SDoug Rabson gsskrb5_acceptor_ready(OM_uint32 * minor_status,
233c19800e8SDoug Rabson gsskrb5_ctx ctx,
234c19800e8SDoug Rabson krb5_context context,
235c19800e8SDoug Rabson gss_cred_id_t *delegated_cred_handle)
236c19800e8SDoug Rabson {
237c19800e8SDoug Rabson OM_uint32 ret;
238c19800e8SDoug Rabson int32_t seq_number;
239c19800e8SDoug Rabson int is_cfx = 0;
240c19800e8SDoug Rabson
241ae771770SStanislav Sedov krb5_auth_con_getremoteseqnumber (context,
242c19800e8SDoug Rabson ctx->auth_context,
243c19800e8SDoug Rabson &seq_number);
244c19800e8SDoug Rabson
245ae771770SStanislav Sedov _gsskrb5i_is_cfx(context, ctx, 1);
246ae771770SStanislav Sedov is_cfx = (ctx->more_flags & IS_CFX);
247c19800e8SDoug Rabson
248c19800e8SDoug Rabson ret = _gssapi_msg_order_create(minor_status,
249c19800e8SDoug Rabson &ctx->order,
250c19800e8SDoug Rabson _gssapi_msg_order_f(ctx->flags),
251c19800e8SDoug Rabson seq_number, 0, is_cfx);
252c19800e8SDoug Rabson if (ret)
253c19800e8SDoug Rabson return ret;
254c19800e8SDoug Rabson
255c19800e8SDoug Rabson /*
256c19800e8SDoug Rabson * If requested, set local sequence num to remote sequence if this
257c19800e8SDoug Rabson * isn't a mutual authentication context
258c19800e8SDoug Rabson */
259c19800e8SDoug Rabson if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) {
260c19800e8SDoug Rabson krb5_auth_con_setlocalseqnumber(context,
261c19800e8SDoug Rabson ctx->auth_context,
262c19800e8SDoug Rabson seq_number);
263c19800e8SDoug Rabson }
264c19800e8SDoug Rabson
265c19800e8SDoug Rabson /*
266c19800e8SDoug Rabson * We should handle the delegation ticket, in case it's there
267c19800e8SDoug Rabson */
268c19800e8SDoug Rabson if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) {
269c19800e8SDoug Rabson ret = gsskrb5_accept_delegated_token(minor_status,
270c19800e8SDoug Rabson ctx,
271c19800e8SDoug Rabson context,
272c19800e8SDoug Rabson delegated_cred_handle);
273c19800e8SDoug Rabson if (ret)
274c19800e8SDoug Rabson return ret;
275c19800e8SDoug Rabson } else {
276c19800e8SDoug Rabson /* Well, looks like it wasn't there after all */
277c19800e8SDoug Rabson ctx->flags &= ~GSS_C_DELEG_FLAG;
278c19800e8SDoug Rabson }
279c19800e8SDoug Rabson
280c19800e8SDoug Rabson ctx->state = ACCEPTOR_READY;
281c19800e8SDoug Rabson ctx->more_flags |= OPEN;
282c19800e8SDoug Rabson
283c19800e8SDoug Rabson return GSS_S_COMPLETE;
284c19800e8SDoug Rabson }
285c19800e8SDoug Rabson
286c19800e8SDoug Rabson static OM_uint32
send_error_token(OM_uint32 * minor_status,krb5_context context,krb5_error_code kret,krb5_principal server,krb5_data * indata,gss_buffer_t output_token)287ae771770SStanislav Sedov send_error_token(OM_uint32 *minor_status,
288ae771770SStanislav Sedov krb5_context context,
289ae771770SStanislav Sedov krb5_error_code kret,
290ae771770SStanislav Sedov krb5_principal server,
291ae771770SStanislav Sedov krb5_data *indata,
292ae771770SStanislav Sedov gss_buffer_t output_token)
293ae771770SStanislav Sedov {
294ae771770SStanislav Sedov krb5_principal ap_req_server = NULL;
295ae771770SStanislav Sedov krb5_error_code ret;
296ae771770SStanislav Sedov krb5_data outbuf;
297ae771770SStanislav Sedov /* this e_data value encodes KERB_AP_ERR_TYPE_SKEW_RECOVERY which
298ae771770SStanislav Sedov tells windows to try again with the corrected timestamp. See
299ae771770SStanislav Sedov [MS-KILE] 2.2.1 KERB-ERROR-DATA */
300ae771770SStanislav Sedov krb5_data e_data = { 7, rk_UNCONST("\x30\x05\xa1\x03\x02\x01\x02") };
301ae771770SStanislav Sedov
302ae771770SStanislav Sedov /* build server from request if the acceptor had not selected one */
303ae771770SStanislav Sedov if (server == NULL) {
304ae771770SStanislav Sedov AP_REQ ap_req;
305ae771770SStanislav Sedov
306ae771770SStanislav Sedov ret = krb5_decode_ap_req(context, indata, &ap_req);
307ae771770SStanislav Sedov if (ret) {
308ae771770SStanislav Sedov *minor_status = ret;
309ae771770SStanislav Sedov return GSS_S_FAILURE;
310ae771770SStanislav Sedov }
311ae771770SStanislav Sedov ret = _krb5_principalname2krb5_principal(context,
312ae771770SStanislav Sedov &ap_req_server,
313ae771770SStanislav Sedov ap_req.ticket.sname,
314ae771770SStanislav Sedov ap_req.ticket.realm);
315ae771770SStanislav Sedov free_AP_REQ(&ap_req);
316ae771770SStanislav Sedov if (ret) {
317ae771770SStanislav Sedov *minor_status = ret;
318ae771770SStanislav Sedov return GSS_S_FAILURE;
319ae771770SStanislav Sedov }
320ae771770SStanislav Sedov server = ap_req_server;
321ae771770SStanislav Sedov }
322ae771770SStanislav Sedov
323ae771770SStanislav Sedov ret = krb5_mk_error(context, kret, NULL, &e_data, NULL,
324ae771770SStanislav Sedov server, NULL, NULL, &outbuf);
325ae771770SStanislav Sedov if (ap_req_server)
326ae771770SStanislav Sedov krb5_free_principal(context, ap_req_server);
327ae771770SStanislav Sedov if (ret) {
328ae771770SStanislav Sedov *minor_status = ret;
329ae771770SStanislav Sedov return GSS_S_FAILURE;
330ae771770SStanislav Sedov }
331ae771770SStanislav Sedov
332ae771770SStanislav Sedov ret = _gsskrb5_encapsulate(minor_status,
333ae771770SStanislav Sedov &outbuf,
334ae771770SStanislav Sedov output_token,
335ae771770SStanislav Sedov "\x03\x00",
336ae771770SStanislav Sedov GSS_KRB5_MECHANISM);
337ae771770SStanislav Sedov krb5_data_free (&outbuf);
338ae771770SStanislav Sedov if (ret)
339ae771770SStanislav Sedov return ret;
340ae771770SStanislav Sedov
341ae771770SStanislav Sedov *minor_status = 0;
342ae771770SStanislav Sedov return GSS_S_CONTINUE_NEEDED;
343ae771770SStanislav Sedov }
344ae771770SStanislav Sedov
345ae771770SStanislav Sedov
346ae771770SStanislav Sedov static OM_uint32
gsskrb5_acceptor_start(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,const gss_cred_id_t acceptor_cred_handle,const gss_buffer_t input_token_buffer,const gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle)347c19800e8SDoug Rabson gsskrb5_acceptor_start(OM_uint32 * minor_status,
348c19800e8SDoug Rabson gsskrb5_ctx ctx,
349c19800e8SDoug Rabson krb5_context context,
350c19800e8SDoug Rabson const gss_cred_id_t acceptor_cred_handle,
351c19800e8SDoug Rabson const gss_buffer_t input_token_buffer,
352c19800e8SDoug Rabson const gss_channel_bindings_t input_chan_bindings,
353c19800e8SDoug Rabson gss_name_t * src_name,
354c19800e8SDoug Rabson gss_OID * mech_type,
355c19800e8SDoug Rabson gss_buffer_t output_token,
356c19800e8SDoug Rabson OM_uint32 * ret_flags,
357c19800e8SDoug Rabson OM_uint32 * time_rec,
358c19800e8SDoug Rabson gss_cred_id_t * delegated_cred_handle)
359c19800e8SDoug Rabson {
360c19800e8SDoug Rabson krb5_error_code kret;
361c19800e8SDoug Rabson OM_uint32 ret = GSS_S_COMPLETE;
362c19800e8SDoug Rabson krb5_data indata;
363c19800e8SDoug Rabson krb5_flags ap_options;
364c19800e8SDoug Rabson krb5_keytab keytab = NULL;
365c19800e8SDoug Rabson int is_cfx = 0;
366c19800e8SDoug Rabson const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle;
367c19800e8SDoug Rabson
368c19800e8SDoug Rabson /*
369c19800e8SDoug Rabson * We may, or may not, have an escapsulation.
370c19800e8SDoug Rabson */
371c19800e8SDoug Rabson ret = _gsskrb5_decapsulate (minor_status,
372c19800e8SDoug Rabson input_token_buffer,
373c19800e8SDoug Rabson &indata,
374c19800e8SDoug Rabson "\x01\x00",
375c19800e8SDoug Rabson GSS_KRB5_MECHANISM);
376c19800e8SDoug Rabson
377c19800e8SDoug Rabson if (ret) {
378c19800e8SDoug Rabson /* Assume that there is no OID wrapping. */
379c19800e8SDoug Rabson indata.length = input_token_buffer->length;
380c19800e8SDoug Rabson indata.data = input_token_buffer->value;
381c19800e8SDoug Rabson }
382c19800e8SDoug Rabson
383c19800e8SDoug Rabson /*
384c19800e8SDoug Rabson * We need to get our keytab
385c19800e8SDoug Rabson */
386c19800e8SDoug Rabson if (acceptor_cred == NULL) {
387c19800e8SDoug Rabson if (_gsskrb5_keytab != NULL)
388c19800e8SDoug Rabson keytab = _gsskrb5_keytab;
389c19800e8SDoug Rabson } else if (acceptor_cred->keytab != NULL) {
390c19800e8SDoug Rabson keytab = acceptor_cred->keytab;
391c19800e8SDoug Rabson }
392c19800e8SDoug Rabson
393c19800e8SDoug Rabson /*
394c19800e8SDoug Rabson * We need to check the ticket and create the AP-REP packet
395c19800e8SDoug Rabson */
396c19800e8SDoug Rabson
397c19800e8SDoug Rabson {
398c19800e8SDoug Rabson krb5_rd_req_in_ctx in = NULL;
399c19800e8SDoug Rabson krb5_rd_req_out_ctx out = NULL;
400ae771770SStanislav Sedov krb5_principal server = NULL;
401ae771770SStanislav Sedov
402ae771770SStanislav Sedov if (acceptor_cred)
403ae771770SStanislav Sedov server = acceptor_cred->principal;
404c19800e8SDoug Rabson
405c19800e8SDoug Rabson kret = krb5_rd_req_in_ctx_alloc(context, &in);
406c19800e8SDoug Rabson if (kret == 0)
407c19800e8SDoug Rabson kret = krb5_rd_req_in_set_keytab(context, in, keytab);
408c19800e8SDoug Rabson if (kret) {
409c19800e8SDoug Rabson if (in)
410c19800e8SDoug Rabson krb5_rd_req_in_ctx_free(context, in);
411c19800e8SDoug Rabson *minor_status = kret;
412ae771770SStanislav Sedov return GSS_S_FAILURE;
413c19800e8SDoug Rabson }
414c19800e8SDoug Rabson
415c19800e8SDoug Rabson kret = krb5_rd_req_ctx(context,
416c19800e8SDoug Rabson &ctx->auth_context,
417c19800e8SDoug Rabson &indata,
418ae771770SStanislav Sedov server,
419c19800e8SDoug Rabson in, &out);
420c19800e8SDoug Rabson krb5_rd_req_in_ctx_free(context, in);
421ae771770SStanislav Sedov if (kret == KRB5KRB_AP_ERR_SKEW || kret == KRB5KRB_AP_ERR_TKT_NYV) {
422ae771770SStanislav Sedov /*
423ae771770SStanislav Sedov * No reply in non-MUTUAL mode, but we don't know that its
424ae771770SStanislav Sedov * non-MUTUAL mode yet, thats inside the 8003 checksum, so
425ae771770SStanislav Sedov * lets only send the error token on clock skew, that
426ae771770SStanislav Sedov * limit when send error token for non-MUTUAL.
427ae771770SStanislav Sedov */
428*ed549cb0SCy Schubert free_Authenticator(ctx->auth_context->authenticator);
429ae771770SStanislav Sedov return send_error_token(minor_status, context, kret,
430ae771770SStanislav Sedov server, &indata, output_token);
431ae771770SStanislav Sedov } else if (kret) {
432c19800e8SDoug Rabson *minor_status = kret;
433ae771770SStanislav Sedov return GSS_S_FAILURE;
434c19800e8SDoug Rabson }
435c19800e8SDoug Rabson
436c19800e8SDoug Rabson /*
437ae771770SStanislav Sedov * we need to remember some data on the context_handle.
438c19800e8SDoug Rabson */
439c19800e8SDoug Rabson kret = krb5_rd_req_out_get_ap_req_options(context, out,
440c19800e8SDoug Rabson &ap_options);
441c19800e8SDoug Rabson if (kret == 0)
442c19800e8SDoug Rabson kret = krb5_rd_req_out_get_ticket(context, out,
443c19800e8SDoug Rabson &ctx->ticket);
444c19800e8SDoug Rabson if (kret == 0)
445c19800e8SDoug Rabson kret = krb5_rd_req_out_get_keyblock(context, out,
446c19800e8SDoug Rabson &ctx->service_keyblock);
447c19800e8SDoug Rabson ctx->lifetime = ctx->ticket->ticket.endtime;
448c19800e8SDoug Rabson
449c19800e8SDoug Rabson krb5_rd_req_out_ctx_free(context, out);
450c19800e8SDoug Rabson if (kret) {
451c19800e8SDoug Rabson ret = GSS_S_FAILURE;
452c19800e8SDoug Rabson *minor_status = kret;
453c19800e8SDoug Rabson return ret;
454c19800e8SDoug Rabson }
455c19800e8SDoug Rabson }
456c19800e8SDoug Rabson
457c19800e8SDoug Rabson
458c19800e8SDoug Rabson /*
459c19800e8SDoug Rabson * We need to copy the principal names to the context and the
460c19800e8SDoug Rabson * calling layer.
461c19800e8SDoug Rabson */
462c19800e8SDoug Rabson kret = krb5_copy_principal(context,
463c19800e8SDoug Rabson ctx->ticket->client,
464c19800e8SDoug Rabson &ctx->source);
465c19800e8SDoug Rabson if (kret) {
466c19800e8SDoug Rabson ret = GSS_S_FAILURE;
467c19800e8SDoug Rabson *minor_status = kret;
468c19800e8SDoug Rabson }
469c19800e8SDoug Rabson
470c19800e8SDoug Rabson kret = krb5_copy_principal(context,
471c19800e8SDoug Rabson ctx->ticket->server,
472c19800e8SDoug Rabson &ctx->target);
473c19800e8SDoug Rabson if (kret) {
474c19800e8SDoug Rabson ret = GSS_S_FAILURE;
475c19800e8SDoug Rabson *minor_status = kret;
476c19800e8SDoug Rabson return ret;
477c19800e8SDoug Rabson }
478c19800e8SDoug Rabson
479c19800e8SDoug Rabson /*
480c19800e8SDoug Rabson * We need to setup some compat stuff, this assumes that
481c19800e8SDoug Rabson * context_handle->target is already set.
482c19800e8SDoug Rabson */
483c19800e8SDoug Rabson ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
484c19800e8SDoug Rabson if (ret)
485c19800e8SDoug Rabson return ret;
486c19800e8SDoug Rabson
487c19800e8SDoug Rabson if (src_name != NULL) {
488c19800e8SDoug Rabson kret = krb5_copy_principal (context,
489c19800e8SDoug Rabson ctx->ticket->client,
490c19800e8SDoug Rabson (gsskrb5_name*)src_name);
491c19800e8SDoug Rabson if (kret) {
492c19800e8SDoug Rabson ret = GSS_S_FAILURE;
493c19800e8SDoug Rabson *minor_status = kret;
494c19800e8SDoug Rabson return ret;
495c19800e8SDoug Rabson }
496c19800e8SDoug Rabson }
497c19800e8SDoug Rabson
498c19800e8SDoug Rabson /*
499c19800e8SDoug Rabson * We need to get the flags out of the 8003 checksum.
500c19800e8SDoug Rabson */
501ae771770SStanislav Sedov
502c19800e8SDoug Rabson {
503c19800e8SDoug Rabson krb5_authenticator authenticator;
504c19800e8SDoug Rabson
505c19800e8SDoug Rabson kret = krb5_auth_con_getauthenticator(context,
506c19800e8SDoug Rabson ctx->auth_context,
507c19800e8SDoug Rabson &authenticator);
508c19800e8SDoug Rabson if(kret) {
509c19800e8SDoug Rabson ret = GSS_S_FAILURE;
510c19800e8SDoug Rabson *minor_status = kret;
511c19800e8SDoug Rabson return ret;
512c19800e8SDoug Rabson }
513c19800e8SDoug Rabson
514ae771770SStanislav Sedov if (authenticator->cksum == NULL) {
515ae771770SStanislav Sedov krb5_free_authenticator(context, &authenticator);
516ae771770SStanislav Sedov *minor_status = 0;
517ae771770SStanislav Sedov return GSS_S_BAD_BINDINGS;
518ae771770SStanislav Sedov }
519ae771770SStanislav Sedov
520c19800e8SDoug Rabson if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {
521c19800e8SDoug Rabson ret = _gsskrb5_verify_8003_checksum(minor_status,
522c19800e8SDoug Rabson input_chan_bindings,
523c19800e8SDoug Rabson authenticator->cksum,
524c19800e8SDoug Rabson &ctx->flags,
525c19800e8SDoug Rabson &ctx->fwd_data);
526c19800e8SDoug Rabson
527c19800e8SDoug Rabson krb5_free_authenticator(context, &authenticator);
528c19800e8SDoug Rabson if (ret) {
529c19800e8SDoug Rabson return ret;
530c19800e8SDoug Rabson }
531c19800e8SDoug Rabson } else {
532c19800e8SDoug Rabson krb5_crypto crypto;
533c19800e8SDoug Rabson
534c19800e8SDoug Rabson kret = krb5_crypto_init(context,
535c19800e8SDoug Rabson ctx->auth_context->keyblock,
536c19800e8SDoug Rabson 0, &crypto);
537c19800e8SDoug Rabson if(kret) {
538c19800e8SDoug Rabson krb5_free_authenticator(context, &authenticator);
539c19800e8SDoug Rabson
540c19800e8SDoug Rabson ret = GSS_S_FAILURE;
541c19800e8SDoug Rabson *minor_status = kret;
542c19800e8SDoug Rabson return ret;
543c19800e8SDoug Rabson }
544c19800e8SDoug Rabson
545c19800e8SDoug Rabson /*
546c19800e8SDoug Rabson * Windows accepts Samba3's use of a kerberos, rather than
547c19800e8SDoug Rabson * GSSAPI checksum here
548c19800e8SDoug Rabson */
549c19800e8SDoug Rabson
550c19800e8SDoug Rabson kret = krb5_verify_checksum(context,
551c19800e8SDoug Rabson crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
552c19800e8SDoug Rabson authenticator->cksum);
553c19800e8SDoug Rabson krb5_free_authenticator(context, &authenticator);
554c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto);
555c19800e8SDoug Rabson
556c19800e8SDoug Rabson if(kret) {
557c19800e8SDoug Rabson ret = GSS_S_BAD_SIG;
558c19800e8SDoug Rabson *minor_status = kret;
559c19800e8SDoug Rabson return ret;
560c19800e8SDoug Rabson }
561c19800e8SDoug Rabson
562c19800e8SDoug Rabson /*
563ae771770SStanislav Sedov * Samba style get some flags (but not DCE-STYLE), use
564ae771770SStanislav Sedov * ap_options to guess the mutual flag.
565c19800e8SDoug Rabson */
566ae771770SStanislav Sedov ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
567ae771770SStanislav Sedov if (ap_options & AP_OPTS_MUTUAL_REQUIRED)
568ae771770SStanislav Sedov ctx->flags |= GSS_C_MUTUAL_FLAG;
569c19800e8SDoug Rabson }
570c19800e8SDoug Rabson }
571c19800e8SDoug Rabson
572c19800e8SDoug Rabson if(ctx->flags & GSS_C_MUTUAL_FLAG) {
573c19800e8SDoug Rabson krb5_data outbuf;
574ae771770SStanislav Sedov int use_subkey = 0;
575c19800e8SDoug Rabson
576ae771770SStanislav Sedov _gsskrb5i_is_cfx(context, ctx, 1);
577ae771770SStanislav Sedov is_cfx = (ctx->more_flags & IS_CFX);
578c19800e8SDoug Rabson
579ae771770SStanislav Sedov if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
580ae771770SStanislav Sedov use_subkey = 1;
581ae771770SStanislav Sedov } else {
582ae771770SStanislav Sedov krb5_keyblock *rkey;
583ae771770SStanislav Sedov
584ae771770SStanislav Sedov /*
585ae771770SStanislav Sedov * If there is a initiator subkey, copy that to acceptor
586ae771770SStanislav Sedov * subkey to match Windows behavior
587ae771770SStanislav Sedov */
588ae771770SStanislav Sedov kret = krb5_auth_con_getremotesubkey(context,
589c19800e8SDoug Rabson ctx->auth_context,
590ae771770SStanislav Sedov &rkey);
591ae771770SStanislav Sedov if (kret == 0) {
592ae771770SStanislav Sedov kret = krb5_auth_con_setlocalsubkey(context,
593ae771770SStanislav Sedov ctx->auth_context,
594ae771770SStanislav Sedov rkey);
595ae771770SStanislav Sedov if (kret == 0)
596ae771770SStanislav Sedov use_subkey = 1;
597ae771770SStanislav Sedov krb5_free_keyblock(context, rkey);
598ae771770SStanislav Sedov }
599ae771770SStanislav Sedov }
600ae771770SStanislav Sedov if (use_subkey) {
601ae771770SStanislav Sedov ctx->more_flags |= ACCEPTOR_SUBKEY;
602ae771770SStanislav Sedov krb5_auth_con_addflags(context, ctx->auth_context,
603c19800e8SDoug Rabson KRB5_AUTH_CONTEXT_USE_SUBKEY,
604c19800e8SDoug Rabson NULL);
605c19800e8SDoug Rabson }
606c19800e8SDoug Rabson
607c19800e8SDoug Rabson kret = krb5_mk_rep(context,
608c19800e8SDoug Rabson ctx->auth_context,
609c19800e8SDoug Rabson &outbuf);
610c19800e8SDoug Rabson if (kret) {
611c19800e8SDoug Rabson *minor_status = kret;
612c19800e8SDoug Rabson return GSS_S_FAILURE;
613c19800e8SDoug Rabson }
614c19800e8SDoug Rabson
615c19800e8SDoug Rabson if (IS_DCE_STYLE(ctx)) {
616c19800e8SDoug Rabson output_token->length = outbuf.length;
617c19800e8SDoug Rabson output_token->value = outbuf.data;
618c19800e8SDoug Rabson } else {
619c19800e8SDoug Rabson ret = _gsskrb5_encapsulate(minor_status,
620c19800e8SDoug Rabson &outbuf,
621c19800e8SDoug Rabson output_token,
622c19800e8SDoug Rabson "\x02\x00",
623c19800e8SDoug Rabson GSS_KRB5_MECHANISM);
624c19800e8SDoug Rabson krb5_data_free (&outbuf);
625c19800e8SDoug Rabson if (ret)
626c19800e8SDoug Rabson return ret;
627c19800e8SDoug Rabson }
628c19800e8SDoug Rabson }
629c19800e8SDoug Rabson
630c19800e8SDoug Rabson ctx->flags |= GSS_C_TRANS_FLAG;
631c19800e8SDoug Rabson
632c19800e8SDoug Rabson /* Remember the flags */
633c19800e8SDoug Rabson
634c19800e8SDoug Rabson ctx->lifetime = ctx->ticket->ticket.endtime;
635c19800e8SDoug Rabson ctx->more_flags |= OPEN;
636c19800e8SDoug Rabson
637c19800e8SDoug Rabson if (mech_type)
638c19800e8SDoug Rabson *mech_type = GSS_KRB5_MECHANISM;
639c19800e8SDoug Rabson
640c19800e8SDoug Rabson if (time_rec) {
641c19800e8SDoug Rabson ret = _gsskrb5_lifetime_left(minor_status,
642c19800e8SDoug Rabson context,
643c19800e8SDoug Rabson ctx->lifetime,
644c19800e8SDoug Rabson time_rec);
645c19800e8SDoug Rabson if (ret) {
646c19800e8SDoug Rabson return ret;
647c19800e8SDoug Rabson }
648c19800e8SDoug Rabson }
649c19800e8SDoug Rabson
650c19800e8SDoug Rabson /*
651c19800e8SDoug Rabson * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from
652c19800e8SDoug Rabson * the client.
653c19800e8SDoug Rabson */
654c19800e8SDoug Rabson if (IS_DCE_STYLE(ctx)) {
655c19800e8SDoug Rabson /*
656c19800e8SDoug Rabson * Return flags to caller, but we haven't processed
657c19800e8SDoug Rabson * delgations yet
658c19800e8SDoug Rabson */
659c19800e8SDoug Rabson if (ret_flags)
660c19800e8SDoug Rabson *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG);
661c19800e8SDoug Rabson
662c19800e8SDoug Rabson ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
663c19800e8SDoug Rabson return GSS_S_CONTINUE_NEEDED;
664c19800e8SDoug Rabson }
665c19800e8SDoug Rabson
666c19800e8SDoug Rabson ret = gsskrb5_acceptor_ready(minor_status, ctx, context,
667c19800e8SDoug Rabson delegated_cred_handle);
668c19800e8SDoug Rabson
669c19800e8SDoug Rabson if (ret_flags)
670c19800e8SDoug Rabson *ret_flags = ctx->flags;
671c19800e8SDoug Rabson
672c19800e8SDoug Rabson return ret;
673c19800e8SDoug Rabson }
674c19800e8SDoug Rabson
675c19800e8SDoug Rabson static OM_uint32
acceptor_wait_for_dcestyle(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,const gss_cred_id_t acceptor_cred_handle,const gss_buffer_t input_token_buffer,const gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle)676c19800e8SDoug Rabson acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
677c19800e8SDoug Rabson gsskrb5_ctx ctx,
678c19800e8SDoug Rabson krb5_context context,
679c19800e8SDoug Rabson const gss_cred_id_t acceptor_cred_handle,
680c19800e8SDoug Rabson const gss_buffer_t input_token_buffer,
681c19800e8SDoug Rabson const gss_channel_bindings_t input_chan_bindings,
682c19800e8SDoug Rabson gss_name_t * src_name,
683c19800e8SDoug Rabson gss_OID * mech_type,
684c19800e8SDoug Rabson gss_buffer_t output_token,
685c19800e8SDoug Rabson OM_uint32 * ret_flags,
686c19800e8SDoug Rabson OM_uint32 * time_rec,
687c19800e8SDoug Rabson gss_cred_id_t * delegated_cred_handle)
688c19800e8SDoug Rabson {
689c19800e8SDoug Rabson OM_uint32 ret;
690c19800e8SDoug Rabson krb5_error_code kret;
691c19800e8SDoug Rabson krb5_data inbuf;
692c19800e8SDoug Rabson int32_t r_seq_number, l_seq_number;
693c19800e8SDoug Rabson
694c19800e8SDoug Rabson /*
695c19800e8SDoug Rabson * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP
696c19800e8SDoug Rabson */
697c19800e8SDoug Rabson
698c19800e8SDoug Rabson inbuf.length = input_token_buffer->length;
699c19800e8SDoug Rabson inbuf.data = input_token_buffer->value;
700c19800e8SDoug Rabson
701c19800e8SDoug Rabson /*
702c19800e8SDoug Rabson * We need to remeber the old remote seq_number, then check if the
703c19800e8SDoug Rabson * client has replied with our local seq_number, and then reset
704c19800e8SDoug Rabson * the remote seq_number to the old value
705c19800e8SDoug Rabson */
706c19800e8SDoug Rabson {
707c19800e8SDoug Rabson kret = krb5_auth_con_getlocalseqnumber(context,
708c19800e8SDoug Rabson ctx->auth_context,
709c19800e8SDoug Rabson &l_seq_number);
710c19800e8SDoug Rabson if (kret) {
711c19800e8SDoug Rabson *minor_status = kret;
712c19800e8SDoug Rabson return GSS_S_FAILURE;
713c19800e8SDoug Rabson }
714c19800e8SDoug Rabson
715ae771770SStanislav Sedov kret = krb5_auth_con_getremoteseqnumber(context,
716c19800e8SDoug Rabson ctx->auth_context,
717c19800e8SDoug Rabson &r_seq_number);
718c19800e8SDoug Rabson if (kret) {
719c19800e8SDoug Rabson *minor_status = kret;
720c19800e8SDoug Rabson return GSS_S_FAILURE;
721c19800e8SDoug Rabson }
722c19800e8SDoug Rabson
723c19800e8SDoug Rabson kret = krb5_auth_con_setremoteseqnumber(context,
724c19800e8SDoug Rabson ctx->auth_context,
725c19800e8SDoug Rabson l_seq_number);
726c19800e8SDoug Rabson if (kret) {
727c19800e8SDoug Rabson *minor_status = kret;
728c19800e8SDoug Rabson return GSS_S_FAILURE;
729c19800e8SDoug Rabson }
730c19800e8SDoug Rabson }
731c19800e8SDoug Rabson
732c19800e8SDoug Rabson /*
733c19800e8SDoug Rabson * We need to verify the AP_REP, but we need to flag that this is
734c19800e8SDoug Rabson * DCE_STYLE, so don't check the timestamps this time, but put the
735c19800e8SDoug Rabson * flag DO_TIME back afterward.
736c19800e8SDoug Rabson */
737c19800e8SDoug Rabson {
738c19800e8SDoug Rabson krb5_ap_rep_enc_part *repl;
739c19800e8SDoug Rabson int32_t auth_flags;
740c19800e8SDoug Rabson
741c19800e8SDoug Rabson krb5_auth_con_removeflags(context,
742c19800e8SDoug Rabson ctx->auth_context,
743c19800e8SDoug Rabson KRB5_AUTH_CONTEXT_DO_TIME,
744c19800e8SDoug Rabson &auth_flags);
745c19800e8SDoug Rabson
746c19800e8SDoug Rabson kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl);
747c19800e8SDoug Rabson if (kret) {
748c19800e8SDoug Rabson *minor_status = kret;
749c19800e8SDoug Rabson return GSS_S_FAILURE;
750c19800e8SDoug Rabson }
751c19800e8SDoug Rabson krb5_free_ap_rep_enc_part(context, repl);
752c19800e8SDoug Rabson krb5_auth_con_setflags(context, ctx->auth_context, auth_flags);
753c19800e8SDoug Rabson }
754c19800e8SDoug Rabson
755c19800e8SDoug Rabson /* We need to check the liftime */
756c19800e8SDoug Rabson {
757c19800e8SDoug Rabson OM_uint32 lifetime_rec;
758c19800e8SDoug Rabson
759c19800e8SDoug Rabson ret = _gsskrb5_lifetime_left(minor_status,
760c19800e8SDoug Rabson context,
761c19800e8SDoug Rabson ctx->lifetime,
762c19800e8SDoug Rabson &lifetime_rec);
763c19800e8SDoug Rabson if (ret) {
764c19800e8SDoug Rabson return ret;
765c19800e8SDoug Rabson }
766c19800e8SDoug Rabson if (lifetime_rec == 0) {
767c19800e8SDoug Rabson return GSS_S_CONTEXT_EXPIRED;
768c19800e8SDoug Rabson }
769c19800e8SDoug Rabson
770c19800e8SDoug Rabson if (time_rec) *time_rec = lifetime_rec;
771c19800e8SDoug Rabson }
772c19800e8SDoug Rabson
773c19800e8SDoug Rabson /* We need to give the caller the flags which are in use */
774c19800e8SDoug Rabson if (ret_flags) *ret_flags = ctx->flags;
775c19800e8SDoug Rabson
776c19800e8SDoug Rabson if (src_name) {
777c19800e8SDoug Rabson kret = krb5_copy_principal(context,
778c19800e8SDoug Rabson ctx->source,
779c19800e8SDoug Rabson (gsskrb5_name*)src_name);
780c19800e8SDoug Rabson if (kret) {
781c19800e8SDoug Rabson *minor_status = kret;
782c19800e8SDoug Rabson return GSS_S_FAILURE;
783c19800e8SDoug Rabson }
784c19800e8SDoug Rabson }
785c19800e8SDoug Rabson
786c19800e8SDoug Rabson /*
787c19800e8SDoug Rabson * After the krb5_rd_rep() the remote and local seq_number should
788c19800e8SDoug Rabson * be the same, because the client just replies the seq_number
789c19800e8SDoug Rabson * from our AP-REP in its AP-REP, but then the client uses the
790c19800e8SDoug Rabson * seq_number from its AP-REQ for GSS_wrap()
791c19800e8SDoug Rabson */
792c19800e8SDoug Rabson {
793c19800e8SDoug Rabson int32_t tmp_r_seq_number, tmp_l_seq_number;
794c19800e8SDoug Rabson
795ae771770SStanislav Sedov kret = krb5_auth_con_getremoteseqnumber(context,
796c19800e8SDoug Rabson ctx->auth_context,
797c19800e8SDoug Rabson &tmp_r_seq_number);
798c19800e8SDoug Rabson if (kret) {
799c19800e8SDoug Rabson *minor_status = kret;
800c19800e8SDoug Rabson return GSS_S_FAILURE;
801c19800e8SDoug Rabson }
802c19800e8SDoug Rabson
803c19800e8SDoug Rabson kret = krb5_auth_con_getlocalseqnumber(context,
804c19800e8SDoug Rabson ctx->auth_context,
805c19800e8SDoug Rabson &tmp_l_seq_number);
806c19800e8SDoug Rabson if (kret) {
807c19800e8SDoug Rabson
808c19800e8SDoug Rabson *minor_status = kret;
809c19800e8SDoug Rabson return GSS_S_FAILURE;
810c19800e8SDoug Rabson }
811c19800e8SDoug Rabson
812c19800e8SDoug Rabson /*
813c19800e8SDoug Rabson * Here we check if the client has responsed with our local seq_number,
814c19800e8SDoug Rabson */
815c19800e8SDoug Rabson if (tmp_r_seq_number != tmp_l_seq_number) {
816c19800e8SDoug Rabson return GSS_S_UNSEQ_TOKEN;
817c19800e8SDoug Rabson }
818c19800e8SDoug Rabson }
819c19800e8SDoug Rabson
820c19800e8SDoug Rabson /*
821c19800e8SDoug Rabson * We need to reset the remote seq_number, because the client will use,
822c19800e8SDoug Rabson * the old one for the GSS_wrap() calls
823c19800e8SDoug Rabson */
824c19800e8SDoug Rabson {
825c19800e8SDoug Rabson kret = krb5_auth_con_setremoteseqnumber(context,
826c19800e8SDoug Rabson ctx->auth_context,
827c19800e8SDoug Rabson r_seq_number);
828c19800e8SDoug Rabson if (kret) {
829c19800e8SDoug Rabson *minor_status = kret;
830c19800e8SDoug Rabson return GSS_S_FAILURE;
831c19800e8SDoug Rabson }
832c19800e8SDoug Rabson }
833c19800e8SDoug Rabson
834c19800e8SDoug Rabson return gsskrb5_acceptor_ready(minor_status, ctx, context,
835c19800e8SDoug Rabson delegated_cred_handle);
836c19800e8SDoug Rabson }
837c19800e8SDoug Rabson
838c19800e8SDoug Rabson
839ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gsskrb5_accept_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,const gss_cred_id_t acceptor_cred_handle,const gss_buffer_t input_token_buffer,const gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle)840c19800e8SDoug Rabson _gsskrb5_accept_sec_context(OM_uint32 * minor_status,
841c19800e8SDoug Rabson gss_ctx_id_t * context_handle,
842c19800e8SDoug Rabson const gss_cred_id_t acceptor_cred_handle,
843c19800e8SDoug Rabson const gss_buffer_t input_token_buffer,
844c19800e8SDoug Rabson const gss_channel_bindings_t input_chan_bindings,
845c19800e8SDoug Rabson gss_name_t * src_name,
846c19800e8SDoug Rabson gss_OID * mech_type,
847c19800e8SDoug Rabson gss_buffer_t output_token,
848c19800e8SDoug Rabson OM_uint32 * ret_flags,
849c19800e8SDoug Rabson OM_uint32 * time_rec,
850c19800e8SDoug Rabson gss_cred_id_t * delegated_cred_handle)
851c19800e8SDoug Rabson {
852c19800e8SDoug Rabson krb5_context context;
853c19800e8SDoug Rabson OM_uint32 ret;
854c19800e8SDoug Rabson gsskrb5_ctx ctx;
855c19800e8SDoug Rabson
856c19800e8SDoug Rabson GSSAPI_KRB5_INIT(&context);
857c19800e8SDoug Rabson
858c19800e8SDoug Rabson output_token->length = 0;
859c19800e8SDoug Rabson output_token->value = NULL;
860c19800e8SDoug Rabson
861c19800e8SDoug Rabson if (src_name != NULL)
862c19800e8SDoug Rabson *src_name = NULL;
863c19800e8SDoug Rabson if (mech_type)
864c19800e8SDoug Rabson *mech_type = GSS_KRB5_MECHANISM;
865c19800e8SDoug Rabson
866c19800e8SDoug Rabson if (*context_handle == GSS_C_NO_CONTEXT) {
867c19800e8SDoug Rabson ret = _gsskrb5_create_ctx(minor_status,
868c19800e8SDoug Rabson context_handle,
869c19800e8SDoug Rabson context,
870c19800e8SDoug Rabson input_chan_bindings,
871c19800e8SDoug Rabson ACCEPTOR_START);
872c19800e8SDoug Rabson if (ret)
873c19800e8SDoug Rabson return ret;
874c19800e8SDoug Rabson }
875c19800e8SDoug Rabson
876c19800e8SDoug Rabson ctx = (gsskrb5_ctx)*context_handle;
877c19800e8SDoug Rabson
878c19800e8SDoug Rabson
879c19800e8SDoug Rabson /*
880c19800e8SDoug Rabson * TODO: check the channel_bindings
881c19800e8SDoug Rabson * (above just sets them to krb5 layer)
882c19800e8SDoug Rabson */
883c19800e8SDoug Rabson
884c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
885c19800e8SDoug Rabson
886c19800e8SDoug Rabson switch (ctx->state) {
887c19800e8SDoug Rabson case ACCEPTOR_START:
888c19800e8SDoug Rabson ret = gsskrb5_acceptor_start(minor_status,
889c19800e8SDoug Rabson ctx,
890c19800e8SDoug Rabson context,
891c19800e8SDoug Rabson acceptor_cred_handle,
892c19800e8SDoug Rabson input_token_buffer,
893c19800e8SDoug Rabson input_chan_bindings,
894c19800e8SDoug Rabson src_name,
895c19800e8SDoug Rabson mech_type,
896c19800e8SDoug Rabson output_token,
897c19800e8SDoug Rabson ret_flags,
898c19800e8SDoug Rabson time_rec,
899c19800e8SDoug Rabson delegated_cred_handle);
900c19800e8SDoug Rabson break;
901c19800e8SDoug Rabson case ACCEPTOR_WAIT_FOR_DCESTYLE:
902c19800e8SDoug Rabson ret = acceptor_wait_for_dcestyle(minor_status,
903c19800e8SDoug Rabson ctx,
904c19800e8SDoug Rabson context,
905c19800e8SDoug Rabson acceptor_cred_handle,
906c19800e8SDoug Rabson input_token_buffer,
907c19800e8SDoug Rabson input_chan_bindings,
908c19800e8SDoug Rabson src_name,
909c19800e8SDoug Rabson mech_type,
910c19800e8SDoug Rabson output_token,
911c19800e8SDoug Rabson ret_flags,
912c19800e8SDoug Rabson time_rec,
913c19800e8SDoug Rabson delegated_cred_handle);
914c19800e8SDoug Rabson break;
915c19800e8SDoug Rabson case ACCEPTOR_READY:
916c19800e8SDoug Rabson /*
917c19800e8SDoug Rabson * If we get there, the caller have called
918c19800e8SDoug Rabson * gss_accept_sec_context() one time too many.
919c19800e8SDoug Rabson */
920c19800e8SDoug Rabson ret = GSS_S_BAD_STATUS;
921c19800e8SDoug Rabson break;
922c19800e8SDoug Rabson default:
923c19800e8SDoug Rabson /* TODO: is this correct here? --metze */
924c19800e8SDoug Rabson ret = GSS_S_BAD_STATUS;
925c19800e8SDoug Rabson break;
926c19800e8SDoug Rabson }
927c19800e8SDoug Rabson
928c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
929c19800e8SDoug Rabson
930c19800e8SDoug Rabson if (GSS_ERROR(ret)) {
931c19800e8SDoug Rabson OM_uint32 min2;
932c19800e8SDoug Rabson _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
933c19800e8SDoug Rabson }
934c19800e8SDoug Rabson
935c19800e8SDoug Rabson return ret;
936c19800e8SDoug Rabson }
937