]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/heimdal/lib/gssapi/init_sec_context.c
import of heimdal 0.3f
[FreeBSD/FreeBSD.git] / crypto / heimdal / lib / gssapi / init_sec_context.c
1 /*
2  * Copyright (c) 1997 - 2001 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: init_sec_context.c,v 1.27 2001/05/11 09:16:46 assar Exp $");
37
38 /*
39  * copy the addresses from `input_chan_bindings' (if any) to
40  * the auth context `ac'
41  */
42
43 static OM_uint32
44 set_addresses (krb5_auth_context ac,
45                const gss_channel_bindings_t input_chan_bindings)               
46 {
47     /* Port numbers are expected to be in application_data.value, 
48      * initator's port first */ 
49
50     krb5_address initiator_addr, acceptor_addr;
51     krb5_error_code kret;
52        
53     if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS
54         || input_chan_bindings->application_data.length !=
55         2 * sizeof(ac->local_port))
56         return 0;
57
58     memset(&initiator_addr, 0, sizeof(initiator_addr));
59     memset(&acceptor_addr, 0, sizeof(acceptor_addr));
60        
61     ac->local_port =
62         *(int16_t *) input_chan_bindings->application_data.value;
63        
64     ac->remote_port =
65         *((int16_t *) input_chan_bindings->application_data.value + 1);
66        
67     kret = gss_address_to_krb5addr(input_chan_bindings->acceptor_addrtype,
68                                    &input_chan_bindings->acceptor_address,
69                                    ac->remote_port,
70                                    &acceptor_addr);
71     if (kret)
72         return kret;
73            
74     kret = gss_address_to_krb5addr(input_chan_bindings->initiator_addrtype,
75                                    &input_chan_bindings->initiator_address,
76                                    ac->local_port,
77                                    &initiator_addr);
78     if (kret) {
79         krb5_free_address (gssapi_krb5_context, &acceptor_addr);
80         return kret;
81     }
82        
83     kret = krb5_auth_con_setaddrs(gssapi_krb5_context,
84                                   ac,
85                                   &initiator_addr,  /* local address */
86                                   &acceptor_addr);  /* remote address */
87        
88     krb5_free_address (gssapi_krb5_context, &initiator_addr);
89     krb5_free_address (gssapi_krb5_context, &acceptor_addr);
90        
91 #if 0
92     free(input_chan_bindings->application_data.value);
93     input_chan_bindings->application_data.value = NULL;
94     input_chan_bindings->application_data.length = 0;
95 #endif
96
97     return kret;
98 }
99
100 /*
101  * handle delegated creds in init-sec-context
102  */
103
104 static void
105 do_delegation (krb5_auth_context ac,
106                krb5_ccache ccache,
107                krb5_creds *cred,
108                const gss_name_t target_name,
109                krb5_data *fwd_data,
110                int *flags)
111 {
112     krb5_creds creds;
113     krb5_kdc_flags fwd_flags;
114     krb5_keyblock *subkey;
115     krb5_error_code kret;
116        
117     memset (&creds, 0, sizeof(creds));
118     krb5_data_zero (fwd_data);
119        
120     kret = krb5_generate_subkey (gssapi_krb5_context, &cred->session, &subkey);
121     if (kret)
122         goto out;
123        
124     kret = krb5_auth_con_setlocalsubkey(gssapi_krb5_context, ac, subkey);
125     krb5_free_keyblock (gssapi_krb5_context, subkey);
126     if (kret)
127         goto out;
128        
129     kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, &creds.client);
130     if (kret) 
131         goto out;
132        
133     kret = krb5_build_principal(gssapi_krb5_context,
134                                 &creds.server,
135                                 strlen(creds.client->realm),
136                                 creds.client->realm,
137                                 KRB5_TGS_NAME,
138                                 creds.client->realm,
139                                 NULL);
140     if (kret)
141         goto out; 
142        
143     creds.times.endtime = 0;
144        
145     fwd_flags.i = 0;
146     fwd_flags.b.forwarded = 1;
147     fwd_flags.b.forwardable = 1;
148        
149     if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
150         target_name->name.name_string.len < 2) 
151         goto out;
152        
153     kret = krb5_get_forwarded_creds(gssapi_krb5_context,
154                                     ac,
155                                     ccache,
156                                     fwd_flags.i,
157                                     target_name->name.name_string.val[1],
158                                     &creds,
159                                     fwd_data);
160        
161  out:
162     if (kret)
163         *flags &= ~GSS_C_DELEG_FLAG;
164     else
165         *flags |= GSS_C_DELEG_FLAG;
166        
167     if (creds.client)
168         krb5_free_principal(gssapi_krb5_context, creds.client);
169     if (creds.server)
170         krb5_free_principal(gssapi_krb5_context, creds.server);
171 }
172
173 /*
174  * first stage of init-sec-context
175  */
176
177 static OM_uint32
178 init_auth
179 (OM_uint32 * minor_status,
180  const gss_cred_id_t initiator_cred_handle,
181  gss_ctx_id_t * context_handle,
182  const gss_name_t target_name,
183  const gss_OID mech_type,
184  OM_uint32 req_flags,
185  OM_uint32 time_req,
186  const gss_channel_bindings_t input_chan_bindings,
187  const gss_buffer_t input_token,
188  gss_OID * actual_mech_type,
189  gss_buffer_t output_token,
190  OM_uint32 * ret_flags,
191  OM_uint32 * time_rec
192     )
193 {
194     OM_uint32 ret = GSS_S_FAILURE;
195     krb5_error_code kret;
196     krb5_flags ap_options;
197     krb5_creds this_cred, *cred;
198     krb5_data outbuf;
199     krb5_ccache ccache;
200     u_int32_t flags;
201     Authenticator *auth;
202     krb5_data authenticator;
203     Checksum cksum;
204     krb5_enctype enctype;
205     krb5_data fwd_data;
206
207     output_token->length = 0;
208     output_token->value  = NULL;
209
210     krb5_data_zero(&outbuf);
211     krb5_data_zero(&fwd_data);
212
213     *minor_status = 0;
214
215     *context_handle = malloc(sizeof(**context_handle));
216     if (*context_handle == NULL) {
217         *minor_status = ENOMEM;
218         return GSS_S_FAILURE;
219     }
220
221     (*context_handle)->auth_context = NULL;
222     (*context_handle)->source       = NULL;
223     (*context_handle)->target       = NULL;
224     (*context_handle)->flags        = 0;
225     (*context_handle)->more_flags   = 0;
226     (*context_handle)->ticket       = NULL;
227
228     kret = krb5_auth_con_init (gssapi_krb5_context,
229                                &(*context_handle)->auth_context);
230     if (kret) {
231         gssapi_krb5_set_error_string ();
232         *minor_status = kret;
233         ret = GSS_S_FAILURE;
234         goto failure;
235     }
236
237     kret = set_addresses ((*context_handle)->auth_context,
238                           input_chan_bindings);
239     if (kret) {
240         *minor_status = kret;
241         ret = GSS_S_BAD_BINDINGS;
242         goto failure;
243     }
244        
245     {
246         int32_t tmp;
247
248         krb5_auth_con_getflags(gssapi_krb5_context,
249                                (*context_handle)->auth_context,
250                                &tmp);
251         tmp |= KRB5_AUTH_CONTEXT_DO_SEQUENCE;
252         krb5_auth_con_setflags(gssapi_krb5_context,
253                                (*context_handle)->auth_context,
254                                tmp);
255     }
256
257     if (actual_mech_type)
258         *actual_mech_type = GSS_KRB5_MECHANISM;
259
260     if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
261         kret = krb5_cc_default (gssapi_krb5_context, &ccache);
262         if (kret) {
263             gssapi_krb5_set_error_string ();
264             *minor_status = kret;
265             ret = GSS_S_FAILURE;
266             goto failure;
267         }
268     } else
269         ccache = initiator_cred_handle->ccache;
270
271     kret = krb5_cc_get_principal (gssapi_krb5_context,
272                                   ccache,
273                                   &(*context_handle)->source);
274     if (kret) {
275         gssapi_krb5_set_error_string ();
276         *minor_status = kret;
277         ret = GSS_S_FAILURE;
278         goto failure;
279     }
280
281     kret = krb5_copy_principal (gssapi_krb5_context,
282                                 target_name,
283                                 &(*context_handle)->target);
284     if (kret) {
285         gssapi_krb5_set_error_string ();
286         *minor_status = kret;
287         ret = GSS_S_FAILURE;
288         goto failure;
289     }
290
291     memset(&this_cred, 0, sizeof(this_cred));
292     this_cred.client          = (*context_handle)->source;
293     this_cred.server          = (*context_handle)->target;
294     if (time_req) {
295         krb5_timestamp ts;
296
297         krb5_timeofday (gssapi_krb5_context, &ts);
298         this_cred.times.endtime = ts + time_req;
299     } else
300         this_cred.times.endtime   = 0;
301     this_cred.session.keytype = 0;
302   
303     kret = krb5_get_credentials (gssapi_krb5_context,
304                                  KRB5_TC_MATCH_KEYTYPE,
305                                  ccache,
306                                  &this_cred,
307                                  &cred);
308
309     if (kret) {
310         gssapi_krb5_set_error_string ();
311         *minor_status = kret;
312         ret = GSS_S_FAILURE;
313         goto failure;
314     }
315
316     krb5_auth_con_setkey(gssapi_krb5_context, 
317                          (*context_handle)->auth_context, 
318                          &cred->session);
319   
320     flags = 0;
321     ap_options = 0;
322     if (req_flags & GSS_C_DELEG_FLAG)
323         do_delegation ((*context_handle)->auth_context,
324                        ccache, cred, target_name, &fwd_data, &flags);
325        
326     if (req_flags & GSS_C_MUTUAL_FLAG) {
327         flags |= GSS_C_MUTUAL_FLAG;
328         ap_options |= AP_OPTS_MUTUAL_REQUIRED;
329     }
330     
331     if (req_flags & GSS_C_REPLAY_FLAG)
332         ;                               /* XXX */
333     if (req_flags & GSS_C_SEQUENCE_FLAG)
334         ;                               /* XXX */
335     if (req_flags & GSS_C_ANON_FLAG)
336         ;                               /* XXX */
337     flags |= GSS_C_CONF_FLAG;
338     flags |= GSS_C_INTEG_FLAG;
339     flags |= GSS_C_SEQUENCE_FLAG;
340     flags |= GSS_C_TRANS_FLAG;
341     
342     if (ret_flags)
343         *ret_flags = flags;
344     (*context_handle)->flags = flags;
345     (*context_handle)->more_flags = LOCAL;
346     
347     kret = gssapi_krb5_create_8003_checksum (input_chan_bindings,
348                                              flags,
349                                              &fwd_data,
350                                              &cksum);
351     krb5_data_free (&fwd_data);
352     if (kret) {
353         gssapi_krb5_set_error_string ();
354         *minor_status = kret;
355         ret = GSS_S_FAILURE;
356         goto failure;
357     }
358
359 #if 1
360     enctype = (*context_handle)->auth_context->keyblock->keytype;
361 #else
362     if ((*context_handle)->auth_context->enctype)
363         enctype = (*context_handle)->auth_context->enctype;
364     else {
365         kret = krb5_keytype_to_enctype(gssapi_krb5_context,
366                                        (*context_handle)->auth_context->keyblock->keytype,
367                                        &enctype);
368         if (kret)
369             return kret;
370     }
371 #endif
372
373     kret = krb5_build_authenticator (gssapi_krb5_context,
374                                      (*context_handle)->auth_context,
375                                      enctype,
376                                      cred,
377                                      &cksum,
378                                      &auth,
379                                      &authenticator,
380                                      KRB5_KU_AP_REQ_AUTH);
381
382     if (kret) {
383         gssapi_krb5_set_error_string ();
384         *minor_status = kret;
385         ret = GSS_S_FAILURE;
386         goto failure;
387     }
388
389     kret = krb5_build_ap_req (gssapi_krb5_context,
390                               enctype,
391                               cred,
392                               ap_options,
393                               authenticator,
394                               &outbuf);
395
396     if (kret) {
397         gssapi_krb5_set_error_string ();
398         *minor_status = kret;
399         ret = GSS_S_FAILURE;
400         goto failure;
401     }
402
403     ret = gssapi_krb5_encapsulate (&outbuf, output_token, "\x01\x00");
404     if (ret) {
405         *minor_status = kret;
406         goto failure;
407     }
408
409     krb5_data_free (&outbuf);
410
411     if (flags & GSS_C_MUTUAL_FLAG) {
412         return GSS_S_CONTINUE_NEEDED;
413     } else {
414         (*context_handle)->more_flags |= OPEN;
415         return GSS_S_COMPLETE;
416     }
417
418  failure:
419     krb5_auth_con_free (gssapi_krb5_context,
420                         (*context_handle)->auth_context);
421     if((*context_handle)->source)
422         krb5_free_principal (gssapi_krb5_context,
423                              (*context_handle)->source);
424     if((*context_handle)->target)
425         krb5_free_principal (gssapi_krb5_context,
426                              (*context_handle)->target);
427     free (*context_handle);
428     krb5_data_free (&outbuf);
429     *context_handle = GSS_C_NO_CONTEXT;
430     return ret;
431 }
432
433 static OM_uint32
434 repl_mutual
435            (OM_uint32 * minor_status,
436             const gss_cred_id_t initiator_cred_handle,
437             gss_ctx_id_t * context_handle,
438             const gss_name_t target_name,
439             const gss_OID mech_type,
440             OM_uint32 req_flags,
441             OM_uint32 time_req,
442             const gss_channel_bindings_t input_chan_bindings,
443             const gss_buffer_t input_token,
444             gss_OID * actual_mech_type,
445             gss_buffer_t output_token,
446             OM_uint32 * ret_flags,
447             OM_uint32 * time_rec
448            )
449 {
450     OM_uint32 ret;
451     krb5_error_code kret;
452     krb5_data indata;
453     krb5_ap_rep_enc_part *repl;
454
455     ret = gssapi_krb5_decapsulate (input_token, &indata, "\x02\x00");
456     if (ret) {
457                                 /* XXX - Handle AP_ERROR */
458         *minor_status = 0;
459         return GSS_S_FAILURE;
460     }
461
462     kret = krb5_rd_rep (gssapi_krb5_context,
463                         (*context_handle)->auth_context,
464                         &indata,
465                         &repl);
466     if (kret) {
467         gssapi_krb5_set_error_string ();
468         *minor_status = kret;
469         return GSS_S_FAILURE;
470     }
471     krb5_free_ap_rep_enc_part (gssapi_krb5_context,
472                                repl);
473
474     output_token->length = 0;
475
476     (*context_handle)->more_flags |= OPEN;
477
478     return GSS_S_COMPLETE;
479 }
480
481 /*
482  * gss_init_sec_context
483  */
484
485 OM_uint32 gss_init_sec_context
486            (OM_uint32 * minor_status,
487             const gss_cred_id_t initiator_cred_handle,
488             gss_ctx_id_t * context_handle,
489             const gss_name_t target_name,
490             const gss_OID mech_type,
491             OM_uint32 req_flags,
492             OM_uint32 time_req,
493             const gss_channel_bindings_t input_chan_bindings,
494             const gss_buffer_t input_token,
495             gss_OID * actual_mech_type,
496             gss_buffer_t output_token,
497             OM_uint32 * ret_flags,
498             OM_uint32 * time_rec
499            )
500 {
501     gssapi_krb5_init ();
502
503     if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
504         return init_auth (minor_status,
505                           initiator_cred_handle,
506                           context_handle,
507                           target_name,
508                           mech_type,
509                           req_flags,
510                           time_req,
511                           input_chan_bindings,
512                           input_token,
513                           actual_mech_type,
514                           output_token,
515                           ret_flags,
516                           time_rec);
517     else
518         return repl_mutual(minor_status,
519                            initiator_cred_handle,
520                            context_handle,
521                            target_name,
522                            mech_type,
523                            req_flags,
524                            time_req,
525                            input_chan_bindings,
526                            input_token,
527                            actual_mech_type,
528                            output_token,
529                            ret_flags,
530                            time_rec);
531 }