]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - crypto/heimdal/lib/gssapi/accept_sec_context.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / crypto / heimdal / lib / gssapi / accept_sec_context.c
1 /*
2  * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #include "gssapi_locl.h"
35
36 RCSID("$Id: accept_sec_context.c,v 1.33.2.2 2003/12/19 00:37:06 lha Exp $");
37
38 krb5_keytab gssapi_krb5_keytab;
39
40 OM_uint32
41 gsskrb5_register_acceptor_identity (const char *identity)
42 {
43     krb5_error_code ret;
44     char *p;
45
46     ret = gssapi_krb5_init();
47     if(ret)
48         return GSS_S_FAILURE;
49     
50     if(gssapi_krb5_keytab != NULL) {
51         krb5_kt_close(gssapi_krb5_context, gssapi_krb5_keytab);
52         gssapi_krb5_keytab = NULL;
53     }
54     asprintf(&p, "FILE:%s", identity);
55     if(p == NULL)
56         return GSS_S_FAILURE;
57     ret = krb5_kt_resolve(gssapi_krb5_context, p, &gssapi_krb5_keytab);
58     free(p);
59     if(ret)
60         return GSS_S_FAILURE;
61     return GSS_S_COMPLETE;
62 }
63
64 OM_uint32
65 gss_accept_sec_context
66            (OM_uint32 * minor_status,
67             gss_ctx_id_t * context_handle,
68             const gss_cred_id_t acceptor_cred_handle,
69             const gss_buffer_t input_token_buffer,
70             const gss_channel_bindings_t input_chan_bindings,
71             gss_name_t * src_name,
72             gss_OID * mech_type,
73             gss_buffer_t output_token,
74             OM_uint32 * ret_flags,
75             OM_uint32 * time_rec,
76             gss_cred_id_t * delegated_cred_handle
77            )
78 {
79     krb5_error_code kret;
80     OM_uint32 ret = GSS_S_COMPLETE;
81     krb5_data indata;
82     krb5_flags ap_options;
83     OM_uint32 flags;
84     krb5_ticket *ticket = NULL;
85     krb5_keytab keytab = NULL;
86     krb5_data fwd_data;
87     OM_uint32 minor;
88
89     GSSAPI_KRB5_INIT();
90
91     krb5_data_zero (&fwd_data);
92     output_token->length = 0;
93     output_token->value   = NULL;
94
95     if (src_name != NULL)
96         *src_name = NULL;
97     if (mech_type)
98         *mech_type = GSS_KRB5_MECHANISM;
99
100     if (*context_handle == GSS_C_NO_CONTEXT) {
101         *context_handle = malloc(sizeof(**context_handle));
102         if (*context_handle == GSS_C_NO_CONTEXT) {
103             *minor_status = ENOMEM;
104             return GSS_S_FAILURE;
105         }
106     }
107
108     (*context_handle)->auth_context =  NULL;
109     (*context_handle)->source = NULL;
110     (*context_handle)->target = NULL;
111     (*context_handle)->flags = 0;
112     (*context_handle)->more_flags = 0;
113     (*context_handle)->ticket = NULL;
114     (*context_handle)->lifetime = GSS_C_INDEFINITE;
115
116     kret = krb5_auth_con_init (gssapi_krb5_context,
117                                &(*context_handle)->auth_context);
118     if (kret) {
119         ret = GSS_S_FAILURE;
120         *minor_status = kret;
121         gssapi_krb5_set_error_string ();
122         goto failure;
123     }
124
125     if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS
126         && input_chan_bindings->application_data.length ==
127         2 * sizeof((*context_handle)->auth_context->local_port)
128         ) {
129      
130         /* Port numbers are expected to be in application_data.value,
131          * initator's port first */
132      
133         krb5_address initiator_addr, acceptor_addr;
134      
135         memset(&initiator_addr, 0, sizeof(initiator_addr));
136         memset(&acceptor_addr, 0, sizeof(acceptor_addr));
137
138         (*context_handle)->auth_context->remote_port = 
139             *(int16_t *) input_chan_bindings->application_data.value; 
140      
141         (*context_handle)->auth_context->local_port =
142             *((int16_t *) input_chan_bindings->application_data.value + 1);
143
144      
145         kret = gss_address_to_krb5addr(input_chan_bindings->acceptor_addrtype,
146                                        &input_chan_bindings->acceptor_address,
147                                        (*context_handle)->auth_context->local_port,
148                                        &acceptor_addr); 
149         if (kret) {
150             gssapi_krb5_set_error_string ();
151             ret = GSS_S_BAD_BINDINGS;
152             *minor_status = kret;
153             goto failure;
154         }
155                              
156         kret = gss_address_to_krb5addr(input_chan_bindings->initiator_addrtype,
157                                        &input_chan_bindings->initiator_address, 
158                                        (*context_handle)->auth_context->remote_port,
159                                        &initiator_addr); 
160         if (kret) {
161             krb5_free_address (gssapi_krb5_context, &acceptor_addr);
162             gssapi_krb5_set_error_string ();
163             ret = GSS_S_BAD_BINDINGS;
164             *minor_status = kret;
165             goto failure;
166         }
167      
168         kret = krb5_auth_con_setaddrs(gssapi_krb5_context,
169                                       (*context_handle)->auth_context,
170                                       &acceptor_addr,    /* local address */
171                                       &initiator_addr);  /* remote address */
172      
173         krb5_free_address (gssapi_krb5_context, &initiator_addr);
174         krb5_free_address (gssapi_krb5_context, &acceptor_addr);
175      
176 #if 0
177         free(input_chan_bindings->application_data.value);
178         input_chan_bindings->application_data.value = NULL;
179         input_chan_bindings->application_data.length = 0;
180 #endif
181      
182         if (kret) {
183             gssapi_krb5_set_error_string ();
184             ret = GSS_S_BAD_BINDINGS;
185             *minor_status = kret;
186             goto failure;
187         }
188     }
189   
190
191
192     {
193         int32_t tmp;
194
195         krb5_auth_con_getflags(gssapi_krb5_context,
196                                (*context_handle)->auth_context,
197                                &tmp);
198         tmp |= KRB5_AUTH_CONTEXT_DO_SEQUENCE;
199         krb5_auth_con_setflags(gssapi_krb5_context,
200                                (*context_handle)->auth_context,
201                                tmp);
202     }
203
204     ret = gssapi_krb5_decapsulate (minor_status,
205                                    input_token_buffer,
206                                    &indata,
207                                    "\x01\x00");
208     if (ret)
209         goto failure;
210
211     if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) {
212         if (gssapi_krb5_keytab != NULL) {
213             keytab = gssapi_krb5_keytab;
214         }
215     } else if (acceptor_cred_handle->keytab != NULL) {
216         keytab = acceptor_cred_handle->keytab;
217     }
218
219     kret = krb5_rd_req (gssapi_krb5_context,
220                         &(*context_handle)->auth_context,
221                         &indata,
222                         (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL 
223                         : acceptor_cred_handle->principal,
224                         keytab,
225                         &ap_options,
226                         &ticket);
227     if (kret) {
228         ret = GSS_S_FAILURE;
229         *minor_status = kret;
230         gssapi_krb5_set_error_string ();
231         goto failure;
232     }
233
234     kret = krb5_copy_principal (gssapi_krb5_context,
235                                 ticket->client,
236                                 &(*context_handle)->source);
237     if (kret) {
238         ret = GSS_S_FAILURE;
239         *minor_status = kret;
240         gssapi_krb5_set_error_string ();
241         goto failure;
242     }
243
244     kret = krb5_copy_principal (gssapi_krb5_context,
245                                 ticket->server,
246                                 &(*context_handle)->target);
247     if (kret) {
248         ret = GSS_S_FAILURE;
249         *minor_status = kret;
250         gssapi_krb5_set_error_string ();
251         goto failure;
252     }
253
254     ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
255     if (ret)
256         goto failure;
257
258     if (src_name != NULL) {
259         kret = krb5_copy_principal (gssapi_krb5_context,
260                                     ticket->client,
261                                     src_name);
262         if (kret) {
263             ret = GSS_S_FAILURE;
264             *minor_status = kret;
265             gssapi_krb5_set_error_string ();
266             goto failure;
267         }
268     }
269
270     {
271         krb5_authenticator authenticator;
272       
273         kret = krb5_auth_con_getauthenticator(gssapi_krb5_context,
274                                               (*context_handle)->auth_context,
275                                               &authenticator);
276         if(kret) {
277             ret = GSS_S_FAILURE;
278             *minor_status = kret;
279             gssapi_krb5_set_error_string ();
280             goto failure;
281         }
282
283         ret = gssapi_krb5_verify_8003_checksum(minor_status,
284                                                input_chan_bindings,
285                                                authenticator->cksum,
286                                                &flags,
287                                                &fwd_data);
288         krb5_free_authenticator(gssapi_krb5_context, &authenticator);
289         if (ret)
290             goto failure;
291     }
292
293     if (fwd_data.length > 0 && (flags & GSS_C_DELEG_FLAG)) {
294         krb5_ccache ccache;
295         int32_t ac_flags;
296       
297         if (delegated_cred_handle == NULL)
298             /* XXX Create a new delegated_cred_handle? */
299             kret = krb5_cc_default (gssapi_krb5_context, &ccache);
300         else if (*delegated_cred_handle == NULL) {
301             if ((*delegated_cred_handle =
302                  calloc(1, sizeof(**delegated_cred_handle))) == NULL) {
303                 ret = GSS_S_FAILURE;
304                 *minor_status = ENOMEM;
305                 krb5_set_error_string(gssapi_krb5_context, "out of memory");
306                 gssapi_krb5_set_error_string();
307                 goto failure;
308             }
309             if ((ret = gss_duplicate_name(minor_status, ticket->client,
310                                           &(*delegated_cred_handle)->principal)) != 0) {
311                 flags &= ~GSS_C_DELEG_FLAG;
312                 free(*delegated_cred_handle);
313                 *delegated_cred_handle = NULL;
314                 goto end_fwd;
315             }
316         }
317         if (delegated_cred_handle != NULL &&
318             (*delegated_cred_handle)->ccache == NULL) {
319             kret = krb5_cc_gen_new (gssapi_krb5_context,
320                                     &krb5_mcc_ops,
321                                     &(*delegated_cred_handle)->ccache);
322             ccache = (*delegated_cred_handle)->ccache;
323         }
324         if (delegated_cred_handle != NULL &&
325             (*delegated_cred_handle)->mechanisms == NULL) {
326             ret = gss_create_empty_oid_set(minor_status, 
327                                            &(*delegated_cred_handle)->mechanisms);
328             if (ret)
329                 goto failure;
330             ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
331                                          &(*delegated_cred_handle)->mechanisms);
332             if (ret)
333                 goto failure;
334         }
335
336         if (kret) {
337             flags &= ~GSS_C_DELEG_FLAG;
338             goto end_fwd;
339         }
340       
341         kret = krb5_cc_initialize(gssapi_krb5_context,
342                                   ccache,
343                                   *src_name);
344         if (kret) {
345             flags &= ~GSS_C_DELEG_FLAG;
346             goto end_fwd;
347         }
348       
349         krb5_auth_con_getflags(gssapi_krb5_context,
350                                (*context_handle)->auth_context,
351                                &ac_flags);
352         krb5_auth_con_setflags(gssapi_krb5_context,
353                                (*context_handle)->auth_context,
354                                ac_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
355         kret = krb5_rd_cred2(gssapi_krb5_context,
356                              (*context_handle)->auth_context,
357                              ccache,
358                              &fwd_data);
359         krb5_auth_con_setflags(gssapi_krb5_context,
360                                (*context_handle)->auth_context,
361                                ac_flags);
362         if (kret) {
363             flags &= ~GSS_C_DELEG_FLAG;
364             goto end_fwd;
365         }
366
367       end_fwd:
368         free(fwd_data.data);
369     }
370          
371
372     flags |= GSS_C_TRANS_FLAG;
373
374     if (ret_flags)
375         *ret_flags = flags;
376     (*context_handle)->lifetime = ticket->ticket.endtime;
377     (*context_handle)->flags = flags;
378     (*context_handle)->more_flags |= OPEN;
379
380     if (mech_type)
381         *mech_type = GSS_KRB5_MECHANISM;
382
383     if (time_rec) {
384         ret = gssapi_lifetime_left(minor_status,
385                                    (*context_handle)->lifetime,
386                                    time_rec);
387         if (ret)
388             goto failure;
389     }
390
391     if(flags & GSS_C_MUTUAL_FLAG) {
392         krb5_data outbuf;
393
394         kret = krb5_mk_rep (gssapi_krb5_context,
395                             (*context_handle)->auth_context,
396                             &outbuf);
397         if (kret) {
398             ret = GSS_S_FAILURE;
399             *minor_status = kret;
400             gssapi_krb5_set_error_string ();
401             goto failure;
402         }
403         ret = gssapi_krb5_encapsulate (minor_status,
404                                        &outbuf,
405                                        output_token,
406                                        "\x02\x00");
407         krb5_data_free (&outbuf);
408         if (ret)
409             goto failure;
410     } else {
411         output_token->length = 0;
412         output_token->value = NULL;
413     }
414
415     (*context_handle)->ticket = ticket;
416     ticket = NULL;
417
418 #if 0
419     krb5_free_ticket (context, ticket);
420 #endif
421
422     *minor_status = 0;
423     return GSS_S_COMPLETE;
424
425   failure:
426     if (fwd_data.length > 0)
427         free(fwd_data.data);
428     if (ticket != NULL)
429         krb5_free_ticket (gssapi_krb5_context, ticket);
430     krb5_auth_con_free (gssapi_krb5_context,
431                         (*context_handle)->auth_context);
432     if((*context_handle)->source)
433         krb5_free_principal (gssapi_krb5_context,
434                              (*context_handle)->source);
435     if((*context_handle)->target)
436         krb5_free_principal (gssapi_krb5_context,
437                              (*context_handle)->target);
438     free (*context_handle);
439     if (src_name != NULL) {
440         gss_release_name (&minor, src_name);
441         *src_name = NULL;
442     }
443     *context_handle = GSS_C_NO_CONTEXT;
444     return ret;
445 }