~ubuntu-branches/ubuntu/vivid/globus-gss-assist/vivid

« back to all changes in this revision

Viewing changes to init.c

  • Committer: Bazaar Package Importer
  • Author(s): Mattias Ellert
  • Date: 2009-04-18 20:17:33 UTC
  • Revision ID: james.westby@ubuntu.com-20090418201733-xl4r26mgda1shx4q
Tags: upstream-4.0
ImportĀ upstreamĀ versionĀ 4.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 1999-2006 University of Chicago
 
3
 * 
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at
 
7
 * 
 
8
 * http://www.apache.org/licenses/LICENSE-2.0
 
9
 * 
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
#ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
 
18
/**
 
19
 * @file init.c
 
20
 * @author Sam Lang, Sam Meder
 
21
 *
 
22
 * $RCSfile: init.c,v $
 
23
 * $Revision: 1.15 $
 
24
 * $Date: 2007/08/09 14:24:23 $
 
25
 */
 
26
#endif
 
27
 
 
28
#include "globus_i_gss_assist.h"
 
29
#include "gssapi.h"
 
30
 
 
31
extern gss_OID gss_nt_service_name;
 
32
 
 
33
/**
 
34
 * @name Init Security Context
 
35
 */
 
36
/* @{ */
 
37
/**
 
38
 * @ingroup globus_gsi_gss_assist
 
39
 * Initialize a gssapi security connection. Used by the client.  
 
40
 * The context_handle is returned, and there is one for each
 
41
 * connection.  This routine will take cake of the looping
 
42
 * and token processing, using the supplied get_token and
 
43
 * send_token routines. 
 
44
 * 
 
45
 * @param minor_status
 
46
 *        GSSAPI return code.  The new minor_status is a globus_result_t
 
47
 *        cast to an OM_uint32.  If the call was successful, the minor
 
48
 *        status is equivalant to GLOBUS_SUCCESS.  Otherwise, it is a
 
49
 *        globus error object ID that can be passed to globus_error_get
 
50
 *        to get the error object.  The error object needs to be freed
 
51
 *        with globus_object_free.
 
52
 * @param initiator_cred_handle
 
53
 *        the cred handle obtained by acquire_cred.
 
54
 * @param context_handle
 
55
 *        pointer to returned context. 
 
56
 * @param target_name_char
 
57
 *        char string repersentation of the
 
58
 *        server to be contacted. 
 
59
 * @param req_flags
 
60
 *        request flags, such as GSS_C_DELEG_FLAG for delegation
 
61
 *        and the GSS_C_MUTUAL_FLAG for mutual authentication. 
 
62
 * @param ret_flags
 
63
 *        Pointer to which services are available after
 
64
 *        the connection is established. Maybe NULL if not wanted. 
 
65
 *
 
66
 * The Follwing are particular to this assist routine:
 
67
 *
 
68
 * @param token_status
 
69
 *        the assist routine's get/send token status 
 
70
 * @param gss_assist_get_token 
 
71
 *        function pointer for getting the token
 
72
 * @param gss_assist_get_context
 
73
 *        first argument passed to the 
 
74
 *        gss_assist_get_token function
 
75
 * @param gss_assist_set_token
 
76
 *        function pointer for setting the token
 
77
 * @param gss_assist_set_context
 
78
 *        first argument passed to the 
 
79
 *        gss_assist_set_token function pointer
 
80
 *
 
81
 * @return
 
82
 *        The major status
 
83
 */
 
84
OM_uint32
 
85
globus_gss_assist_init_sec_context(
 
86
    OM_uint32 *                         minor_status,
 
87
    const gss_cred_id_t                 cred_handle,
 
88
    gss_ctx_id_t *                      context_handle,
 
89
    char *                              target_name_char,
 
90
    OM_uint32                           req_flags,
 
91
    OM_uint32 *                         ret_flags,
 
92
    int *                               token_status,
 
93
    int                                 (*gss_assist_get_token)(void *, void **, size_t *), 
 
94
    void *                              gss_assist_get_context,
 
95
    int                                 (*gss_assist_send_token)(void *, void *, size_t),
 
96
    void *                              gss_assist_send_context)
 
97
{
 
98
    int                                 context_established = 0;
 
99
    OM_uint32                           major_status = GSS_S_COMPLETE;
 
100
    OM_uint32                           minor_status1 = 0;
 
101
    OM_uint32                           minor_status2 = 0;
 
102
    gss_buffer_desc                     input_token_desc = GSS_C_EMPTY_BUFFER;
 
103
    gss_buffer_t                        input_token = &input_token_desc;
 
104
    gss_buffer_desc                     output_token_desc = GSS_C_EMPTY_BUFFER;
 
105
    gss_buffer_t                        output_token = &output_token_desc;
 
106
    gss_name_t                          target_name = GSS_C_NO_NAME;
 
107
    gss_OID                             target_name_type = GSS_C_NO_OID;
 
108
    gss_OID                             mech_type = GSS_C_NO_OID;
 
109
    OM_uint32                           time_req = 0;
 
110
    OM_uint32                           time_rec = 0;
 
111
    gss_channel_bindings_t              input_chan_bindings = 
 
112
        GSS_C_NO_CHANNEL_BINDINGS;
 
113
    gss_OID *                           actual_mech_type = NULL;
 
114
    gss_buffer_desc                     tmp_buffer_desc = GSS_C_EMPTY_BUFFER;
 
115
    gss_buffer_t                        tmp_buffer = &tmp_buffer_desc;
 
116
    globus_result_t                     result = GLOBUS_SUCCESS;
 
117
    static char *                       _function_name_ =
 
118
        "globus_gss_assist_init_sec_context";
 
119
    GLOBUS_I_GSI_GSS_ASSIST_DEBUG_ENTER;
 
120
    
 
121
    /*
 
122
     * should not set context_handle to NULL since it may have been
 
123
     * allocated by a call to set_sec_context_option
 
124
     */
 
125
    
 
126
    /*    *context_handle = GSS_C_NO_CONTEXT; */
 
127
    if(ret_flags)
 
128
    {
 
129
        *ret_flags = 0;
 
130
    }
 
131
 
 
132
    /* supply the service name to the gss-api
 
133
     * If NULL, then we want user_to_user
 
134
     * so get it from the cred
 
135
     */
 
136
 
 
137
    if (target_name_char)
 
138
    {
 
139
        if(!strncmp("GSI-NO-TARGET", target_name_char, 13))
 
140
        {
 
141
            target_name = GSS_C_NO_NAME;
 
142
        }
 
143
        else
 
144
        {
 
145
            tmp_buffer->value = target_name_char;
 
146
            tmp_buffer->length = strlen(target_name_char);
 
147
          
 
148
            /* 
 
149
             * A gss_nt_service_name is of the form service@FQDN
 
150
             * At least the Globus gssapi, and the Kerberos gssapi 
 
151
             * use the same form. We will check for 
 
152
             * two special forms here: host@FQDN and ftp@FQDN
 
153
             * This could be another parameter to the gss_assist
 
154
             * instead. 
 
155
             */
 
156
 
 
157
            if (strchr(target_name_char,'@') && 
 
158
                !strstr(target_name_char,"CN="))
 
159
            { 
 
160
                target_name_type = gss_nt_service_name;
 
161
            }
 
162
 
 
163
            major_status = gss_import_name(&minor_status1,
 
164
                                           tmp_buffer,
 
165
                                           target_name_type,
 
166
                                           &target_name);
 
167
        }        
 
168
    }
 
169
    else
 
170
    {
 
171
        major_status = gss_inquire_cred(&minor_status1,
 
172
                                        cred_handle,
 
173
                                        &target_name,
 
174
                                        NULL,
 
175
                                        NULL,
 
176
                                        NULL);
 
177
    }
 
178
 
 
179
    if (major_status == GSS_S_COMPLETE)
 
180
    {
 
181
        while (!context_established)
 
182
        {
 
183
            GLOBUS_I_GSI_GSS_ASSIST_DEBUG_FPRINTF(
 
184
                4, (globus_i_gsi_gss_assist_debug_fstream,
 
185
                    _GASL("req_flags: %8.8x  input_token length: %u\n"),
 
186
                    (unsigned int) req_flags, 
 
187
                    input_token->length));
 
188
            
 
189
            major_status = gss_init_sec_context(&minor_status1,
 
190
                                                cred_handle,
 
191
                                                context_handle,
 
192
                                                target_name,
 
193
                                                mech_type,
 
194
                                                req_flags,
 
195
                                                time_req,
 
196
                                                input_chan_bindings,
 
197
                                                input_token,
 
198
                                                actual_mech_type,
 
199
                                                output_token,
 
200
                                                ret_flags,
 
201
                                                &time_rec);
 
202
 
 
203
            GLOBUS_I_GSI_GSS_ASSIST_DEBUG_FPRINTF(
 
204
                4, (globus_i_gsi_gss_assist_debug_fstream,
 
205
                    _GASL("major:%8.8x  minor:%8.8x  ret_flags: %8.8x\n "
 
206
                    "output_token length: %u  context_handle: %p\n"),
 
207
                    (unsigned int) major_status, 
 
208
                    (unsigned int) minor_status1, 
 
209
                    (unsigned int) ((ret_flags) ? *ret_flags : -1),
 
210
                    output_token->length,
 
211
                    *context_handle));
 
212
 
 
213
            if (input_token->length > 0)
 
214
            {
 
215
                free(input_token->value);
 
216
                input_token->length = 0;
 
217
            }
 
218
 
 
219
            if (output_token->length != 0)
 
220
            {
 
221
                if ((*token_status = gss_assist_send_token(
 
222
                         gss_assist_send_context, 
 
223
                         output_token->value,
 
224
                         output_token->length)) != 0)
 
225
                {
 
226
                    major_status = 
 
227
                        GSS_S_DEFECTIVE_TOKEN | GSS_S_CALL_INACCESSIBLE_WRITE;
 
228
                }
 
229
 
 
230
                gss_release_buffer(&minor_status2,
 
231
                                   output_token);
 
232
            }
 
233
 
 
234
            if (GSS_ERROR(major_status))
 
235
            {
 
236
                if (*context_handle != GSS_C_NO_CONTEXT)
 
237
                {
 
238
                    gss_delete_sec_context(&minor_status2,
 
239
                                           context_handle,
 
240
                                           GSS_C_NO_BUFFER);
 
241
                }
 
242
                break;
 
243
            }
 
244
            
 
245
            if (major_status & GSS_S_CONTINUE_NEEDED)
 
246
            {
 
247
                if ((*token_status =  gss_assist_get_token(
 
248
                         gss_assist_get_context,
 
249
                         &input_token->value,
 
250
                         &input_token->length)) != 0)
 
251
                {
 
252
                    major_status = 
 
253
                        GSS_S_DEFECTIVE_TOKEN | GSS_S_CALL_INACCESSIBLE_READ;
 
254
                    break;
 
255
                }
 
256
 
 
257
            }
 
258
            else
 
259
            {
 
260
                context_established = 1;
 
261
            }
 
262
        } /* end of GSS loop */
 
263
    }
 
264
 
 
265
    if (input_token->length > 0)
 
266
    {
 
267
        free(input_token->value); /* alloc done by g_get_token */
 
268
        input_token->value = NULL;
 
269
        input_token->length = 0;
 
270
    }
 
271
 
 
272
    if (target_name != GSS_C_NO_NAME)
 
273
    {
 
274
        gss_release_name(&minor_status2,&target_name);
 
275
    }
 
276
 
 
277
    result = (globus_result_t) minor_status1;
 
278
    if(result != GLOBUS_SUCCESS)
 
279
    {
 
280
        GLOBUS_GSI_GSS_ASSIST_ERROR_CHAIN_RESULT(
 
281
            result,
 
282
            GLOBUS_GSI_GSS_ASSIST_ERROR_WITH_INIT);
 
283
    }
 
284
    *minor_status = (OM_uint32) result;
 
285
 
 
286
    GLOBUS_I_GSI_GSS_ASSIST_DEBUG_EXIT;
 
287
    return major_status;
 
288
}
 
289
/* @} */
 
290
 
 
291
/**
 
292
 * @name Init Security Context Async
 
293
 */
 
294
/* @{ */
 
295
/**
 
296
 * @ingroup globus_gsi_gss_assist
 
297
 * This is a asynchronous version of the
 
298
 * globus_gss_assist_init_sec_context() function. Instead of looping
 
299
 * itself it passes in and out the read and written buffers and
 
300
 * the calling application is responsible for doing the I/O directly.
 
301
 *
 
302
 * @param minor_status
 
303
 *        GSSAPI return code.  The new minor status is a globus_result_t
 
304
 *        cast to a OM_uint32.  If an error occurred (GSS_ERROR(major_status))
 
305
 *        the minor_status is a globus error object id.  The error object
 
306
 *        can be obtained via globus_error_get and should be destroyed
 
307
 *        with globus_object_free when no longer needed.  If no error
 
308
 *        occurred, the minor status is equal to GLOBUS_SUCCESS.
 
309
 * @param initiator_cred_handle
 
310
 *        the cred handle obtained by acquire_cred.
 
311
 * @param context_handle
 
312
 *        pointer to returned context. 
 
313
 * @param target_name_char
 
314
 *        char string repersentation of the
 
315
 *        server to be contacted. 
 
316
 * @param req_flags
 
317
 *        request flags, such as GSS_C_DELEG_FLAG for delegation
 
318
 *        and the GSS_C_MUTUAL_FLAG for mutual authentication. 
 
319
 * @param ret_flags
 
320
 *        Pointer to which services are available after
 
321
 *        the connection is established. Maybe NULL if not wanted. 
 
322
 * @param input_buffer
 
323
 *        pointer to a buffer received from peer. Should
 
324
 *        be NULL on first call.
 
325
 * @param input_buffer_len
 
326
 *        length of the buffer input_buffer. Should
 
327
 *        be zero on first call.
 
328
 * @param output_bufferp
 
329
 *        pointer to a pointer which will be filled in
 
330
 *        with a pointer to a allocated block of memory. If
 
331
 *        non-NULL the contents of this block should be written
 
332
 *        to the peer where they will be fed into the
 
333
 *        gss_assist_init_sec_context_async() function.
 
334
 * @param output_buffer_lenp
 
335
 *        pointer to an integer which will be filled
 
336
 *        in with the length of the allocated output buffer
 
337
 *        pointed to by *output_bufferp.
 
338
 * @return
 
339
 *        GSS_S_COMPLETE on successful completion when this function does not
 
340
 *        need to be called again.
 
341
 *
 
342
 *        GSS_S_CONTINUE_NEEDED when *output_bufferp should be sent to the
 
343
 *        peer and a new input_buffer read and this function called again.
 
344
 *     
 
345
 *        Other gss errors on failure.
 
346
 */
 
347
OM_uint32
 
348
globus_gss_assist_init_sec_context_async(
 
349
    OM_uint32 *                         minor_status,
 
350
    const gss_cred_id_t                 cred_handle,
 
351
    gss_ctx_id_t *                      context_handle,
 
352
    char *                              target_name_char,
 
353
    OM_uint32                           req_flags,
 
354
    OM_uint32 *                         ret_flags,
 
355
    void *                              input_buffer,
 
356
    size_t                              input_buffer_len,
 
357
    void **                             output_bufferp,
 
358
    size_t *                            output_buffer_lenp)
 
359
{
 
360
    OM_uint32                           major_status = GSS_S_COMPLETE;
 
361
    OM_uint32                           minor_status1 = 0;
 
362
    OM_uint32                           minor_status2 = 0;
 
363
    gss_buffer_desc                     input_token_desc = GSS_C_EMPTY_BUFFER;
 
364
    gss_buffer_t                        input_token = &input_token_desc;
 
365
    gss_buffer_desc                     output_token_desc = GSS_C_EMPTY_BUFFER;
 
366
    gss_buffer_t                        output_token = &output_token_desc;
 
367
    gss_name_t                          target_name = GSS_C_NO_NAME;
 
368
    gss_OID                             target_name_type = GSS_C_NO_OID;
 
369
    gss_OID                             mech_type = GSS_C_NO_OID;
 
370
    OM_uint32                           time_req = 0;
 
371
    OM_uint32                           time_rec = 0;
 
372
    gss_channel_bindings_t              input_chan_bindings = 
 
373
        GSS_C_NO_CHANNEL_BINDINGS;
 
374
    gss_OID *                           actual_mech_type = NULL;
 
375
    gss_buffer_desc                     tmp_buffer_desc = GSS_C_EMPTY_BUFFER;
 
376
    gss_buffer_t                        tmp_buffer      = &tmp_buffer_desc;
 
377
    globus_result_t                     result = GLOBUS_SUCCESS;
 
378
    static char *                       _function_name_ =
 
379
        "globus_gss_assist_init_sec_context_async";
 
380
    GLOBUS_I_GSI_GSS_ASSIST_DEBUG_ENTER;
 
381
 
 
382
    /* Set up our input token from passed buffer */
 
383
    if ((input_buffer != NULL) && (input_buffer_len != 0))
 
384
    {
 
385
        input_token_desc.length = input_buffer_len;
 
386
        input_token_desc.value = input_buffer;
 
387
    }
 
388
 
 
389
    /* Do initialization first time through the loop */
 
390
 
 
391
    /* This will not work if the context handle has been initialized
 
392
       before the first call. Don't know how to fix it since I can't
 
393
       access fields in the handle outside the GSS API. - Sam
 
394
    */
 
395
    if (*context_handle == GSS_C_NO_CONTEXT)
 
396
    {
 
397
        if(ret_flags)
 
398
        {
 
399
            *ret_flags = 0;
 
400
        }
 
401
    }
 
402
 
 
403
    /* supply the service name to the gss-api
 
404
     * If NULL, then we want user_to_user
 
405
     * so get it from the cred
 
406
     */
 
407
 
 
408
    if (target_name_char)
 
409
    {
 
410
        if(!strncmp("GSI-NO-TARGET",target_name_char,13))
 
411
        {
 
412
            target_name = GSS_C_NO_NAME;
 
413
        }
 
414
        else
 
415
        {
 
416
            tmp_buffer->value = target_name_char;
 
417
            tmp_buffer->length = strlen(target_name_char);
 
418
 
 
419
            /* 
 
420
             * A gss_nt_service_name is of the form service@FQDN
 
421
             * At least the Globus gssapi, and the Kerberos gssapi 
 
422
             * use the same form. We will check for 
 
423
             * two special forms here: host@FQDN and ftp@FQDN
 
424
             * This could be another parameter to the gss_assist
 
425
             * instead. 
 
426
             */
 
427
          
 
428
            if (strchr(target_name_char, '@') &&
 
429
                !strstr(target_name_char, "CN="))
 
430
            { 
 
431
                target_name_type = gss_nt_service_name;
 
432
            }
 
433
          
 
434
            major_status = gss_import_name(&minor_status1,
 
435
                                           tmp_buffer,
 
436
                                           target_name_type,
 
437
                                           &target_name);
 
438
        }
 
439
    }
 
440
    else
 
441
    {
 
442
 
 
443
        major_status = gss_inquire_cred(&minor_status1,
 
444
                                        cred_handle,
 
445
                                        &target_name,
 
446
                                        NULL,
 
447
                                        NULL,
 
448
                                        NULL);
 
449
    }
 
450
 
 
451
    if (major_status == GSS_S_COMPLETE)
 
452
    {
 
453
        GLOBUS_I_GSI_GSS_ASSIST_DEBUG_FPRINTF(
 
454
            4, (globus_i_gsi_gss_assist_debug_fstream,
 
455
                _GASL("req_flags: %8.8x  input_token length: %u\n"),
 
456
                (unsigned int) req_flags,
 
457
                input_token->length));
 
458
 
 
459
        major_status = gss_init_sec_context(&minor_status1,
 
460
                                            cred_handle,
 
461
                                            context_handle,
 
462
                                            target_name,
 
463
                                            mech_type,
 
464
                                            req_flags,
 
465
                                            time_req,
 
466
                                            input_chan_bindings,
 
467
                                            input_token,
 
468
                                            actual_mech_type,
 
469
                                            output_token,
 
470
                                            ret_flags,
 
471
                                            &time_rec);
 
472
        GLOBUS_I_GSI_GSS_ASSIST_DEBUG_FPRINTF(
 
473
            4, (globus_i_gsi_gss_assist_debug_fstream,
 
474
                _GASL("major: %8.8x minor: %8.8x ret_flags: %8.8x\n"
 
475
                "output_token length: %u context_handle: %p\n"),
 
476
                (unsigned int) major_status, 
 
477
                (unsigned int) minor_status1, 
 
478
                (unsigned int) ((ret_flags) ? *ret_flags : -1),
 
479
                output_token->length, 
 
480
                *context_handle));
 
481
 
 
482
        if (output_token->length != 0)
 
483
        {
 
484
            *output_bufferp = output_token->value;
 
485
            *output_buffer_lenp = output_token->length;
 
486
            /* These will now be freed by the caller */
 
487
        }
 
488
        else
 
489
        {    
 
490
            *output_bufferp = NULL;
 
491
            *output_buffer_lenp = 0;
 
492
        }
 
493
 
 
494
        if (GSS_ERROR(major_status))
 
495
        {
 
496
            if (*context_handle != GSS_C_NO_CONTEXT)
 
497
                gss_delete_sec_context(&minor_status2,
 
498
                                       context_handle,
 
499
                                       GSS_C_NO_BUFFER);
 
500
        }
 
501
 
 
502
    }
 
503
 
 
504
    if (target_name != GSS_C_NO_NAME)
 
505
    {
 
506
        gss_release_name(&minor_status2,&target_name);
 
507
    }
 
508
 
 
509
 
 
510
    result = (globus_result_t) minor_status1;
 
511
    if(result != GLOBUS_SUCCESS)
 
512
    {
 
513
        GLOBUS_GSI_GSS_ASSIST_ERROR_CHAIN_RESULT(
 
514
            result,
 
515
            GLOBUS_GSI_GSS_ASSIST_ERROR_WITH_INIT);
 
516
    }
 
517
    *minor_status = (OM_uint32) result;
 
518
 
 
519
    GLOBUS_I_GSI_GSS_ASSIST_DEBUG_EXIT;
 
520
    return major_status;
 
521
}
 
522
/* @} */