Add heimdal-0.6.3
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / gssapi / init_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: init_sec_context.c,v 1.36.2.1 2003/08/15 14:21:18 lha 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_error_code kret;
115        
116     memset (&creds, 0, sizeof(creds));
117     krb5_data_zero (fwd_data);
118        
119     kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, &creds.client);
120     if (kret) 
121         goto out;
122        
123     kret = krb5_build_principal(gssapi_krb5_context,
124                                 &creds.server,
125                                 strlen(creds.client->realm),
126                                 creds.client->realm,
127                                 KRB5_TGS_NAME,
128                                 creds.client->realm,
129                                 NULL);
130     if (kret)
131         goto out; 
132        
133     creds.times.endtime = 0;
134        
135     fwd_flags.i = 0;
136     fwd_flags.b.forwarded = 1;
137     fwd_flags.b.forwardable = 1;
138        
139     if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
140         target_name->name.name_string.len < 2) 
141         goto out;
142        
143     kret = krb5_get_forwarded_creds(gssapi_krb5_context,
144                                     ac,
145                                     ccache,
146                                     fwd_flags.i,
147                                     target_name->name.name_string.val[1],
148                                     &creds,
149                                     fwd_data);
150        
151  out:
152     if (kret)
153         *flags &= ~GSS_C_DELEG_FLAG;
154     else
155         *flags |= GSS_C_DELEG_FLAG;
156        
157     if (creds.client)
158         krb5_free_principal(gssapi_krb5_context, creds.client);
159     if (creds.server)
160         krb5_free_principal(gssapi_krb5_context, creds.server);
161 }
162
163 /*
164  * first stage of init-sec-context
165  */
166
167 static OM_uint32
168 init_auth
169 (OM_uint32 * minor_status,
170  const gss_cred_id_t initiator_cred_handle,
171  gss_ctx_id_t * context_handle,
172  const gss_name_t target_name,
173  const gss_OID mech_type,
174  OM_uint32 req_flags,
175  OM_uint32 time_req,
176  const gss_channel_bindings_t input_chan_bindings,
177  const gss_buffer_t input_token,
178  gss_OID * actual_mech_type,
179  gss_buffer_t output_token,
180  OM_uint32 * ret_flags,
181  OM_uint32 * time_rec
182     )
183 {
184     OM_uint32 ret = GSS_S_FAILURE;
185     krb5_error_code kret;
186     krb5_flags ap_options;
187     krb5_creds this_cred, *cred;
188     krb5_data outbuf;
189     krb5_ccache ccache;
190     u_int32_t flags;
191     Authenticator *auth;
192     krb5_data authenticator;
193     Checksum cksum;
194     krb5_enctype enctype;
195     krb5_data fwd_data;
196     OM_uint32 lifetime_rec;
197
198     krb5_data_zero(&outbuf);
199     krb5_data_zero(&fwd_data);
200
201     *minor_status = 0;
202
203     *context_handle = malloc(sizeof(**context_handle));
204     if (*context_handle == NULL) {
205         *minor_status = ENOMEM;
206         return GSS_S_FAILURE;
207     }
208
209     (*context_handle)->auth_context = NULL;
210     (*context_handle)->source       = NULL;
211     (*context_handle)->target       = NULL;
212     (*context_handle)->flags        = 0;
213     (*context_handle)->more_flags   = 0;
214     (*context_handle)->ticket       = NULL;
215     (*context_handle)->lifetime     = GSS_C_INDEFINITE;
216
217     kret = krb5_auth_con_init (gssapi_krb5_context,
218                                &(*context_handle)->auth_context);
219     if (kret) {
220         gssapi_krb5_set_error_string ();
221         *minor_status = kret;
222         ret = GSS_S_FAILURE;
223         goto failure;
224     }
225
226     kret = set_addresses ((*context_handle)->auth_context,
227                           input_chan_bindings);
228     if (kret) {
229         *minor_status = kret;
230         ret = GSS_S_BAD_BINDINGS;
231         goto failure;
232     }
233        
234     {
235         int32_t tmp;
236
237         krb5_auth_con_getflags(gssapi_krb5_context,
238                                (*context_handle)->auth_context,
239                                &tmp);
240         tmp |= KRB5_AUTH_CONTEXT_DO_SEQUENCE;
241         krb5_auth_con_setflags(gssapi_krb5_context,
242                                (*context_handle)->auth_context,
243                                tmp);
244     }
245
246     if (actual_mech_type)
247         *actual_mech_type = GSS_KRB5_MECHANISM;
248
249     if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
250         kret = krb5_cc_default (gssapi_krb5_context, &ccache);
251         if (kret) {
252             gssapi_krb5_set_error_string ();
253             *minor_status = kret;
254             ret = GSS_S_FAILURE;
255             goto failure;
256         }
257     } else
258         ccache = initiator_cred_handle->ccache;
259
260     kret = krb5_cc_get_principal (gssapi_krb5_context,
261                                   ccache,
262                                   &(*context_handle)->source);
263     if (kret) {
264         gssapi_krb5_set_error_string ();
265         *minor_status = kret;
266         ret = GSS_S_FAILURE;
267         goto failure;
268     }
269
270     kret = krb5_copy_principal (gssapi_krb5_context,
271                                 target_name,
272                                 &(*context_handle)->target);
273     if (kret) {
274         gssapi_krb5_set_error_string ();
275         *minor_status = kret;
276         ret = GSS_S_FAILURE;
277         goto failure;
278     }
279
280     ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
281     if (ret)
282         goto failure;
283
284
285     memset(&this_cred, 0, sizeof(this_cred));
286     this_cred.client          = (*context_handle)->source;
287     this_cred.server          = (*context_handle)->target;
288     if (time_req && time_req != GSS_C_INDEFINITE) {
289         krb5_timestamp ts;
290
291         krb5_timeofday (gssapi_krb5_context, &ts);
292         this_cred.times.endtime = ts + time_req;
293     } else
294         this_cred.times.endtime   = 0;
295     this_cred.session.keytype = 0;
296
297     kret = krb5_get_credentials (gssapi_krb5_context,
298                                  KRB5_TC_MATCH_KEYTYPE,
299                                  ccache,
300                                  &this_cred,
301                                  &cred);
302
303     if (kret) {
304         gssapi_krb5_set_error_string ();
305         *minor_status = kret;
306         ret = GSS_S_FAILURE;
307         goto failure;
308     }
309
310     (*context_handle)->lifetime = cred->times.endtime;
311
312     ret = gssapi_lifetime_left(minor_status,
313                                (*context_handle)->lifetime,
314                                &lifetime_rec);
315     if (ret) {
316         goto failure;
317     }
318
319     if (lifetime_rec == 0) {
320         *minor_status = 0;
321         ret = GSS_S_CONTEXT_EXPIRED;
322         goto failure;
323     }
324
325     krb5_auth_con_setkey(gssapi_krb5_context, 
326                          (*context_handle)->auth_context, 
327                          &cred->session);
328
329     kret = krb5_auth_con_generatelocalsubkey(gssapi_krb5_context, 
330                                              (*context_handle)->auth_context,
331                                              &cred->session);
332     if(kret) {
333         gssapi_krb5_set_error_string ();
334         *minor_status = kret;
335         ret = GSS_S_FAILURE;
336         goto failure;
337     }
338     
339     flags = 0;
340     ap_options = 0;
341     if (req_flags & GSS_C_DELEG_FLAG)
342         do_delegation ((*context_handle)->auth_context,
343                        ccache, cred, target_name, &fwd_data, &flags);
344     
345     if (req_flags & GSS_C_MUTUAL_FLAG) {
346         flags |= GSS_C_MUTUAL_FLAG;
347         ap_options |= AP_OPTS_MUTUAL_REQUIRED;
348     }
349     
350     if (req_flags & GSS_C_REPLAY_FLAG)
351         ;                               /* XXX */
352     if (req_flags & GSS_C_SEQUENCE_FLAG)
353         ;                               /* XXX */
354     if (req_flags & GSS_C_ANON_FLAG)
355         ;                               /* XXX */
356     flags |= GSS_C_CONF_FLAG;
357     flags |= GSS_C_INTEG_FLAG;
358     flags |= GSS_C_SEQUENCE_FLAG;
359     flags |= GSS_C_TRANS_FLAG;
360     
361     if (ret_flags)
362         *ret_flags = flags;
363     (*context_handle)->flags = flags;
364     (*context_handle)->more_flags |= LOCAL;
365     
366     ret = gssapi_krb5_create_8003_checksum (minor_status,
367                                             input_chan_bindings,
368                                             flags,
369                                             &fwd_data,
370                                             &cksum);
371     krb5_data_free (&fwd_data);
372     if (ret)
373         goto failure;
374
375 #if 1
376     enctype = (*context_handle)->auth_context->keyblock->keytype;
377 #else
378     if ((*context_handle)->auth_context->enctype)
379         enctype = (*context_handle)->auth_context->enctype;
380     else {
381         kret = krb5_keytype_to_enctype(gssapi_krb5_context,
382                                        (*context_handle)->auth_context->keyblock->keytype,
383                                        &enctype);
384         if (kret)
385             return kret;
386     }
387 #endif
388
389     kret = krb5_build_authenticator (gssapi_krb5_context,
390                                      (*context_handle)->auth_context,
391                                      enctype,
392                                      cred,
393                                      &cksum,
394                                      &auth,
395                                      &authenticator,
396                                      KRB5_KU_AP_REQ_AUTH);
397
398     if (kret) {
399         gssapi_krb5_set_error_string ();
400         *minor_status = kret;
401         ret = GSS_S_FAILURE;
402         goto failure;
403     }
404
405     kret = krb5_build_ap_req (gssapi_krb5_context,
406                               enctype,
407                               cred,
408                               ap_options,
409                               authenticator,
410                               &outbuf);
411
412     if (kret) {
413         gssapi_krb5_set_error_string ();
414         *minor_status = kret;
415         ret = GSS_S_FAILURE;
416         goto failure;
417     }
418
419     ret = gssapi_krb5_encapsulate (minor_status, &outbuf, output_token,
420                                    "\x01\x00");
421     if (ret)
422         goto failure;
423
424     krb5_data_free (&outbuf);
425
426     if (flags & GSS_C_MUTUAL_FLAG) {
427         return GSS_S_CONTINUE_NEEDED;
428     } else {
429         if (time_rec)
430             *time_rec = lifetime_rec;
431
432         (*context_handle)->more_flags |= OPEN;
433         return GSS_S_COMPLETE;
434     }
435
436  failure:
437     krb5_auth_con_free (gssapi_krb5_context,
438                         (*context_handle)->auth_context);
439     if((*context_handle)->source)
440         krb5_free_principal (gssapi_krb5_context,
441                              (*context_handle)->source);
442     if((*context_handle)->target)
443         krb5_free_principal (gssapi_krb5_context,
444                              (*context_handle)->target);
445     free (*context_handle);
446     krb5_data_free (&outbuf);
447     *context_handle = GSS_C_NO_CONTEXT;
448     return ret;
449 }
450
451 static OM_uint32
452 repl_mutual
453            (OM_uint32 * minor_status,
454             const gss_cred_id_t initiator_cred_handle,
455             gss_ctx_id_t * context_handle,
456             const gss_name_t target_name,
457             const gss_OID mech_type,
458             OM_uint32 req_flags,
459             OM_uint32 time_req,
460             const gss_channel_bindings_t input_chan_bindings,
461             const gss_buffer_t input_token,
462             gss_OID * actual_mech_type,
463             gss_buffer_t output_token,
464             OM_uint32 * ret_flags,
465             OM_uint32 * time_rec
466            )
467 {
468     OM_uint32 ret;
469     krb5_error_code kret;
470     krb5_data indata;
471     krb5_ap_rep_enc_part *repl;
472
473     output_token->length = 0;
474     output_token->value = NULL;
475
476     if (actual_mech_type)
477         *actual_mech_type = GSS_KRB5_MECHANISM;
478
479     ret = gssapi_krb5_decapsulate (minor_status, input_token, &indata,
480                                    "\x02\x00");
481     if (ret)
482                                 /* XXX - Handle AP_ERROR */
483         return ret;
484
485     kret = krb5_rd_rep (gssapi_krb5_context,
486                         (*context_handle)->auth_context,
487                         &indata,
488                         &repl);
489     if (kret) {
490         gssapi_krb5_set_error_string ();
491         *minor_status = kret;
492         return GSS_S_FAILURE;
493     }
494     krb5_free_ap_rep_enc_part (gssapi_krb5_context,
495                                repl);
496     
497     (*context_handle)->more_flags |= OPEN;
498
499     *minor_status = 0;
500     if (time_rec) {
501         ret = gssapi_lifetime_left(minor_status,
502                                    (*context_handle)->lifetime,
503                                    time_rec);
504     } else {
505         ret = GSS_S_COMPLETE;
506     }
507     if (ret_flags)
508         *ret_flags = (*context_handle)->flags;
509
510     return ret;
511 }
512
513 /*
514  * gss_init_sec_context
515  */
516
517 OM_uint32 gss_init_sec_context
518            (OM_uint32 * minor_status,
519             const gss_cred_id_t initiator_cred_handle,
520             gss_ctx_id_t * context_handle,
521             const gss_name_t target_name,
522             const gss_OID mech_type,
523             OM_uint32 req_flags,
524             OM_uint32 time_req,
525             const gss_channel_bindings_t input_chan_bindings,
526             const gss_buffer_t input_token,
527             gss_OID * actual_mech_type,
528             gss_buffer_t output_token,
529             OM_uint32 * ret_flags,
530             OM_uint32 * time_rec
531            )
532 {
533     GSSAPI_KRB5_INIT ();
534
535     output_token->length = 0;
536     output_token->value  = NULL;
537
538     if (ret_flags)
539         *ret_flags = 0;
540     if (time_rec)
541         *time_rec = 0;
542
543     if (target_name == GSS_C_NO_NAME) {
544         if (actual_mech_type)
545             *actual_mech_type = GSS_C_NO_OID;
546         *minor_status = 0;
547         return GSS_S_BAD_NAME;
548     }
549
550     if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
551         return init_auth (minor_status,
552                           initiator_cred_handle,
553                           context_handle,
554                           target_name,
555                           mech_type,
556                           req_flags,
557                           time_req,
558                           input_chan_bindings,
559                           input_token,
560                           actual_mech_type,
561                           output_token,
562                           ret_flags,
563                           time_rec);
564     else
565         return repl_mutual(minor_status,
566                            initiator_cred_handle,
567                            context_handle,
568                            target_name,
569                            mech_type,
570                            req_flags,
571                            time_req,
572                            input_chan_bindings,
573                            input_token,
574                            actual_mech_type,
575                            output_token,
576                            ret_flags,
577                            time_rec);
578 }