Initial import from FreeBSD RELENG_4:
[dragonfly.git] / crypto / heimdal / lib / gssapi / init_sec_context.c
1 /*
2  * Copyright (c) 1997 - 2002 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.31 2002/09/02 17:16:12 joda 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     ret = gssapi_krb5_create_8003_checksum (minor_status,
348                                             input_chan_bindings,
349                                             flags,
350                                             &fwd_data,
351                                             &cksum);
352     krb5_data_free (&fwd_data);
353     if (ret)
354         goto failure;
355
356 #if 1
357     enctype = (*context_handle)->auth_context->keyblock->keytype;
358 #else
359     if ((*context_handle)->auth_context->enctype)
360         enctype = (*context_handle)->auth_context->enctype;
361     else {
362         kret = krb5_keytype_to_enctype(gssapi_krb5_context,
363                                        (*context_handle)->auth_context->keyblock->keytype,
364                                        &enctype);
365         if (kret)
366             return kret;
367     }
368 #endif
369
370     kret = krb5_auth_con_generatelocalsubkey(gssapi_krb5_context, 
371                                              (*context_handle)->auth_context,
372                                              &cred->session);
373     if(kret) {
374         gssapi_krb5_set_error_string ();
375         *minor_status = kret;
376         ret = GSS_S_FAILURE;
377         goto failure;
378     }
379
380     kret = krb5_build_authenticator (gssapi_krb5_context,
381                                      (*context_handle)->auth_context,
382                                      enctype,
383                                      cred,
384                                      &cksum,
385                                      &auth,
386                                      &authenticator,
387                                      KRB5_KU_AP_REQ_AUTH);
388
389     if (kret) {
390         gssapi_krb5_set_error_string ();
391         *minor_status = kret;
392         ret = GSS_S_FAILURE;
393         goto failure;
394     }
395
396     kret = krb5_build_ap_req (gssapi_krb5_context,
397                               enctype,
398                               cred,
399                               ap_options,
400                               authenticator,
401                               &outbuf);
402
403     if (kret) {
404         gssapi_krb5_set_error_string ();
405         *minor_status = kret;
406         ret = GSS_S_FAILURE;
407         goto failure;
408     }
409
410     ret = gssapi_krb5_encapsulate (minor_status, &outbuf, output_token,
411                                    "\x01\x00");
412     if (ret)
413         goto failure;
414
415     krb5_data_free (&outbuf);
416
417     if (flags & GSS_C_MUTUAL_FLAG) {
418         return GSS_S_CONTINUE_NEEDED;
419     } else {
420         (*context_handle)->more_flags |= OPEN;
421         return GSS_S_COMPLETE;
422     }
423
424  failure:
425     krb5_auth_con_free (gssapi_krb5_context,
426                         (*context_handle)->auth_context);
427     if((*context_handle)->source)
428         krb5_free_principal (gssapi_krb5_context,
429                              (*context_handle)->source);
430     if((*context_handle)->target)
431         krb5_free_principal (gssapi_krb5_context,
432                              (*context_handle)->target);
433     free (*context_handle);
434     krb5_data_free (&outbuf);
435     *context_handle = GSS_C_NO_CONTEXT;
436     return ret;
437 }
438
439 static OM_uint32
440 repl_mutual
441            (OM_uint32 * minor_status,
442             const gss_cred_id_t initiator_cred_handle,
443             gss_ctx_id_t * context_handle,
444             const gss_name_t target_name,
445             const gss_OID mech_type,
446             OM_uint32 req_flags,
447             OM_uint32 time_req,
448             const gss_channel_bindings_t input_chan_bindings,
449             const gss_buffer_t input_token,
450             gss_OID * actual_mech_type,
451             gss_buffer_t output_token,
452             OM_uint32 * ret_flags,
453             OM_uint32 * time_rec
454            )
455 {
456     OM_uint32 ret;
457     krb5_error_code kret;
458     krb5_data indata;
459     krb5_ap_rep_enc_part *repl;
460
461     ret = gssapi_krb5_decapsulate (minor_status, input_token, &indata,
462                                    "\x02\x00");
463     if (ret)
464                                 /* XXX - Handle AP_ERROR */
465         return ret;
466
467     kret = krb5_rd_rep (gssapi_krb5_context,
468                         (*context_handle)->auth_context,
469                         &indata,
470                         &repl);
471     if (kret) {
472         gssapi_krb5_set_error_string ();
473         *minor_status = kret;
474         return GSS_S_FAILURE;
475     }
476     krb5_free_ap_rep_enc_part (gssapi_krb5_context,
477                                repl);
478
479     output_token->length = 0;
480
481     (*context_handle)->more_flags |= OPEN;
482
483     return GSS_S_COMPLETE;
484 }
485
486 /*
487  * gss_init_sec_context
488  */
489
490 OM_uint32 gss_init_sec_context
491            (OM_uint32 * minor_status,
492             const gss_cred_id_t initiator_cred_handle,
493             gss_ctx_id_t * context_handle,
494             const gss_name_t target_name,
495             const gss_OID mech_type,
496             OM_uint32 req_flags,
497             OM_uint32 time_req,
498             const gss_channel_bindings_t input_chan_bindings,
499             const gss_buffer_t input_token,
500             gss_OID * actual_mech_type,
501             gss_buffer_t output_token,
502             OM_uint32 * ret_flags,
503             OM_uint32 * time_rec
504            )
505 {
506     gssapi_krb5_init ();
507
508     if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
509         return init_auth (minor_status,
510                           initiator_cred_handle,
511                           context_handle,
512                           target_name,
513                           mech_type,
514                           req_flags,
515                           time_req,
516                           input_chan_bindings,
517                           input_token,
518                           actual_mech_type,
519                           output_token,
520                           ret_flags,
521                           time_rec);
522     else
523         return repl_mutual(minor_status,
524                            initiator_cred_handle,
525                            context_handle,
526                            target_name,
527                            mech_type,
528                            req_flags,
529                            time_req,
530                            input_chan_bindings,
531                            input_token,
532                            actual_mech_type,
533                            output_token,
534                            ret_flags,
535                            time_rec);
536 }