~ubuntu-branches/ubuntu/maverick/krb5/maverick

« back to all changes in this revision

Viewing changes to src/lib/krb5/krb/preauth2.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman, Russ Allbery, Sam Hartman
  • Date: 2008-08-21 10:41:41 UTC
  • mfrom: (11.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080821104141-a0f9c4o4cpo8xd0o
Tags: 1.6.dfsg.4~beta1-4
[ Russ Allbery ]
* Translation updates:
  - Swedish, thanks Martin Bagge.  (Closes: #487669, #491774)
  - Italian, thanks Luca Monducci.  (Closes: #493962)

[ Sam Hartman ]
* Translation Updates:
    - Dutch, Thanks Vincent Zweije, Closes: #495733

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
 */
31
31
 
32
32
#include "k5-int.h"
 
33
#include "osconf.h"
 
34
#include <krb5/preauth_plugin.h>
 
35
#include "int-proto.h"
 
36
 
 
37
#if !defined(_WIN32)
 
38
#include <unistd.h>
 
39
#endif
 
40
 
 
41
#if TARGET_OS_MAC
 
42
static const char *objdirs[] = { KRB5_PLUGIN_BUNDLE_DIR, LIBDIR "/krb5/plugins/preauth", NULL }; /* should be a list */
 
43
#else
 
44
static const char *objdirs[] = { LIBDIR "/krb5/plugins/preauth", NULL };
 
45
#endif
33
46
 
34
47
typedef krb5_error_code (*pa_function)(krb5_context,
35
48
                                       krb5_kdc_req *request,
49
62
    int flags;
50
63
} pa_types_t;
51
64
 
52
 
#define PA_REAL 0x0001
53
 
#define PA_INFO 0x0002
 
65
/* Create the per-krb5_context context. This means loading the modules
 
66
 * if we haven't done that yet (applications which never obtain initial
 
67
 * credentials should never hit this routine), breaking up the module's
 
68
 * list of support pa_types so that we can iterate over the modules more
 
69
 * easily, and copying over the relevant parts of the module's table. */
 
70
void KRB5_CALLCONV
 
71
krb5_init_preauth_context(krb5_context kcontext)
 
72
{
 
73
    int n_modules, n_tables, i, j, k;
 
74
    void **tables;
 
75
    struct krb5plugin_preauth_client_ftable_v1 *table;
 
76
    krb5_preauth_context *context = NULL;
 
77
    void *plugin_context;
 
78
    krb5_preauthtype pa_type;
 
79
    void **rcpp;
 
80
 
 
81
    /* Only do this once for each krb5_context */
 
82
    if (kcontext->preauth_context != NULL)
 
83
        return;
 
84
 
 
85
    /* load the plugins for the current context */
 
86
    if (PLUGIN_DIR_OPEN(&kcontext->preauth_plugins) == 0) {
 
87
        if (krb5int_open_plugin_dirs(objdirs, NULL,
 
88
                                     &kcontext->preauth_plugins,
 
89
                                     &kcontext->err) != 0) {
 
90
                return;
 
91
        }
 
92
    }
 
93
 
 
94
    /* pull out the module function tables for all of the modules */
 
95
    tables = NULL;
 
96
    if (krb5int_get_plugin_dir_data(&kcontext->preauth_plugins,
 
97
                                    "preauthentication_client_1",
 
98
                                    &tables,
 
99
                                    &kcontext->err) != 0) {
 
100
        return;
 
101
    }
 
102
    if (tables == NULL) {
 
103
        return;
 
104
    }
 
105
 
 
106
    /* count how many modules we ended up loading, and how many preauth
 
107
     * types we may claim to support as a result */
 
108
    n_modules = 0;
 
109
    for (n_tables = 0;
 
110
         (tables != NULL) && (tables[n_tables] != NULL);
 
111
         n_tables++) {
 
112
        table = tables[n_tables];
 
113
        if ((table->pa_type_list != NULL) && (table->process != NULL)) {
 
114
            for (j = 0; table->pa_type_list[j] > 0; j++) {
 
115
                n_modules++;
 
116
            }
 
117
        }
 
118
    }
 
119
 
 
120
    /* allocate the space we need */
 
121
    context = malloc(sizeof(*context));
 
122
    if (context == NULL) {
 
123
        krb5int_free_plugin_dir_data(tables);
 
124
        return;
 
125
    }
 
126
    context->modules = malloc(sizeof(context->modules[0]) * n_modules);
 
127
    if (context->modules == NULL) {
 
128
        krb5int_free_plugin_dir_data(tables);
 
129
        free(context);
 
130
        return;
 
131
    }
 
132
    memset(context->modules, 0, sizeof(context->modules[0]) * n_modules);
 
133
    context->n_modules = n_modules;
 
134
 
 
135
    /* fill in the structure */
 
136
    k = 0;
 
137
    for (i = 0; i < n_tables; i++) {
 
138
        table = tables[i];
 
139
        if ((table->pa_type_list != NULL) && (table->process != NULL)) {
 
140
            plugin_context = NULL;
 
141
            if ((table->init != NULL) &&
 
142
                ((*table->init)(kcontext, &plugin_context) != 0)) {
 
143
#ifdef DEBUG
 
144
                    fprintf (stderr, "init err, skipping module \"%s\"\n",
 
145
                             table->name);
 
146
#endif
 
147
                    continue;
 
148
            }
 
149
 
 
150
            rcpp = NULL;
 
151
            for (j = 0; table->pa_type_list[j] > 0; j++) {
 
152
                pa_type = table->pa_type_list[j];
 
153
                context->modules[k].pa_type = pa_type;
 
154
                context->modules[k].enctypes = table->enctype_list;
 
155
                context->modules[k].plugin_context = plugin_context;
 
156
                /* Only call client_fini once per plugin */
 
157
                if (j == 0)
 
158
                    context->modules[k].client_fini = table->fini;
 
159
                else
 
160
                    context->modules[k].client_fini = NULL;
 
161
                context->modules[k].ftable = table;
 
162
                context->modules[k].name = table->name;
 
163
                context->modules[k].flags = (*table->flags)(kcontext, pa_type);
 
164
                context->modules[k].use_count = 0;
 
165
                context->modules[k].client_process = table->process;
 
166
                context->modules[k].client_tryagain = table->tryagain;
 
167
                if (j == 0)
 
168
                    context->modules[k].client_supply_gic_opts = table->gic_opts;
 
169
                else
 
170
                    context->modules[k].client_supply_gic_opts = NULL;
 
171
                context->modules[k].request_context = NULL;
 
172
                /*
 
173
                 * Only call request_init and request_fini once per plugin.
 
174
                 * Only the first module within each plugin will ever
 
175
                 * have request_context filled in.  Every module within
 
176
                 * the plugin will have its request_context_pp pointing
 
177
                 * to that entry's request_context.  That way all the
 
178
                 * modules within the plugin share the same request_context
 
179
                 */
 
180
                if (j == 0) {
 
181
                    context->modules[k].client_req_init = table->request_init;
 
182
                    context->modules[k].client_req_fini = table->request_fini;
 
183
                    rcpp = &context->modules[k].request_context;
 
184
                } else {
 
185
                    context->modules[k].client_req_init = NULL;
 
186
                    context->modules[k].client_req_fini = NULL;
 
187
                }
 
188
                context->modules[k].request_context_pp = rcpp;
 
189
#ifdef DEBUG
 
190
                fprintf (stderr, "init module \"%s\", pa_type %d, flag %d\n",
 
191
                         context->modules[k].name,
 
192
                         context->modules[k].pa_type,
 
193
                         context->modules[k].flags);
 
194
#endif
 
195
                k++;
 
196
            }
 
197
        }
 
198
    }
 
199
    krb5int_free_plugin_dir_data(tables);
 
200
 
 
201
    /* return the result */
 
202
    kcontext->preauth_context = context;
 
203
}
 
204
 
 
205
/* Zero the use counts for the modules herein.  Usually used before we
 
206
 * start processing any data from the server, at which point every module
 
207
 * will again be able to take a crack at whatever the server sent. */
 
208
void KRB5_CALLCONV
 
209
krb5_clear_preauth_context_use_counts(krb5_context context)
 
210
{
 
211
    int i;
 
212
    if (context->preauth_context != NULL) {
 
213
        for (i = 0; i < context->preauth_context->n_modules; i++) {
 
214
            context->preauth_context->modules[i].use_count = 0;
 
215
        }
 
216
    }
 
217
}
 
218
 
 
219
/*
 
220
 * Give all the preauth plugins a look at the preauth option which
 
221
 * has just been set
 
222
 */
 
223
krb5_error_code
 
224
krb5_preauth_supply_preauth_data(krb5_context context,
 
225
                                 krb5_gic_opt_ext *opte,
 
226
                                 const char *attr,
 
227
                                 const char *value)
 
228
{
 
229
    krb5_error_code retval;
 
230
    int i;
 
231
    void *pctx;
 
232
    const char *emsg = NULL;
 
233
 
 
234
    if (context->preauth_context == NULL)
 
235
        krb5_init_preauth_context(context);
 
236
    if (context->preauth_context == NULL) {
 
237
        retval = EINVAL;
 
238
        krb5int_set_error(&context->err, retval,
 
239
                "krb5_preauth_supply_preauth_data: "
 
240
                "Unable to initialize preauth context");
 
241
        return retval;
 
242
    }
 
243
 
 
244
    /*
 
245
     * Go down the list of preauth modules, and supply them with the
 
246
     * attribute/value pair.
 
247
     */
 
248
    for (i = 0; i < context->preauth_context->n_modules; i++) {
 
249
        if (context->preauth_context->modules[i].client_supply_gic_opts == NULL)
 
250
            continue;
 
251
        pctx = context->preauth_context->modules[i].plugin_context;
 
252
        retval = (*context->preauth_context->modules[i].client_supply_gic_opts)
 
253
                                (context, pctx,
 
254
                                 (krb5_get_init_creds_opt *)opte, attr, value); 
 
255
        if (retval) {
 
256
            emsg = krb5_get_error_message(context, retval);
 
257
            krb5int_set_error(&context->err, retval, "Preauth plugin %s: %s",
 
258
                              context->preauth_context->modules[i].name, emsg);
 
259
            break;
 
260
        }
 
261
    }
 
262
    return retval;
 
263
}
 
264
 
 
265
/* Free the per-krb5_context preauth_context. This means clearing any
 
266
 * plugin-specific context which may have been created, and then
 
267
 * freeing the context itself. */
 
268
void KRB5_CALLCONV
 
269
krb5_free_preauth_context(krb5_context context)
 
270
{
 
271
    int i;
 
272
    void *pctx;
 
273
    if (context->preauth_context != NULL) {
 
274
        for (i = 0; i < context->preauth_context->n_modules; i++) {
 
275
            pctx = context->preauth_context->modules[i].plugin_context;
 
276
            if (context->preauth_context->modules[i].client_fini != NULL) {
 
277
                (*context->preauth_context->modules[i].client_fini)(context, pctx);
 
278
            }
 
279
            memset(&context->preauth_context->modules[i], 0,
 
280
                   sizeof(context->preauth_context->modules[i]));
 
281
        }
 
282
        if (context->preauth_context->modules != NULL) {
 
283
            free(context->preauth_context->modules);
 
284
            context->preauth_context->modules = NULL;
 
285
        }
 
286
        free(context->preauth_context);
 
287
        context->preauth_context = NULL;
 
288
    }
 
289
}
 
290
 
 
291
/* Initialize the per-AS-REQ context. This means calling the client_req_init
 
292
 * function to give the plugin a chance to allocate a per-request context. */
 
293
void KRB5_CALLCONV
 
294
krb5_preauth_request_context_init(krb5_context context)
 
295
{
 
296
    int i;
 
297
    void *rctx, *pctx;
 
298
 
 
299
    /* Limit this to only one attempt per context? */
 
300
    if (context->preauth_context == NULL)
 
301
        krb5_init_preauth_context(context);
 
302
    if (context->preauth_context != NULL) {
 
303
        for (i = 0; i < context->preauth_context->n_modules; i++) {
 
304
            pctx = context->preauth_context->modules[i].plugin_context;
 
305
            if (context->preauth_context->modules[i].client_req_init != NULL) {
 
306
                rctx = context->preauth_context->modules[i].request_context_pp;
 
307
                (*context->preauth_context->modules[i].client_req_init) (context, pctx, rctx);
 
308
            }
 
309
        }
 
310
    }
 
311
}
 
312
 
 
313
/* Free the per-AS-REQ context. This means clearing any request-specific
 
314
 * context which the plugin may have created. */
 
315
void KRB5_CALLCONV
 
316
krb5_preauth_request_context_fini(krb5_context context)
 
317
{
 
318
    int i;
 
319
    void *rctx, *pctx;
 
320
    if (context->preauth_context != NULL) {
 
321
        for (i = 0; i < context->preauth_context->n_modules; i++) {
 
322
            pctx = context->preauth_context->modules[i].plugin_context;
 
323
            rctx = context->preauth_context->modules[i].request_context;
 
324
            if (rctx != NULL) {
 
325
                if (context->preauth_context->modules[i].client_req_fini != NULL) {
 
326
                    (*context->preauth_context->modules[i].client_req_fini)(context, pctx, rctx);
 
327
                }
 
328
                context->preauth_context->modules[i].request_context = NULL;
 
329
            }
 
330
        }
 
331
    }
 
332
}
 
333
 
 
334
/* Add the named encryption type to the existing list of ktypes. */
 
335
static void
 
336
grow_ktypes(krb5_enctype **out_ktypes, int *out_nktypes, krb5_enctype ktype)
 
337
{
 
338
    int i;
 
339
    krb5_enctype *ktypes;
 
340
    for (i = 0; i < *out_nktypes; i++) {
 
341
        if ((*out_ktypes)[i] == ktype)
 
342
            return;
 
343
    }
 
344
    ktypes = malloc((*out_nktypes + 2) * sizeof(ktype));
 
345
    if (ktypes) {
 
346
        for (i = 0; i < *out_nktypes; i++)
 
347
            ktypes[i] = (*out_ktypes)[i];
 
348
        ktypes[i++] = ktype;
 
349
        ktypes[i] = 0;
 
350
        free(*out_ktypes);
 
351
        *out_ktypes = ktypes;
 
352
        *out_nktypes = i;
 
353
    }
 
354
}
 
355
 
 
356
/*
 
357
 * Add the given list of pa_data items to the existing list of items.
 
358
 * Factored out here to make reading the do_preauth logic easier to read.
 
359
 */
 
360
static int
 
361
grow_pa_list(krb5_pa_data ***out_pa_list, int *out_pa_list_size,
 
362
             krb5_pa_data **addition, int num_addition)
 
363
{
 
364
    krb5_pa_data **pa_list;
 
365
    int i, j;
 
366
 
 
367
    if (out_pa_list == NULL || addition == NULL) {
 
368
        return EINVAL;
 
369
    }
 
370
 
 
371
    if (*out_pa_list == NULL) {
 
372
        /* Allocate room for the new additions and a NULL terminator. */
 
373
        pa_list = malloc((num_addition + 1) * sizeof(krb5_pa_data *));
 
374
        if (pa_list == NULL)
 
375
            return ENOMEM;
 
376
        for (i = 0; i < num_addition; i++)
 
377
            pa_list[i] = addition[i];
 
378
        pa_list[i] = NULL;
 
379
        *out_pa_list = pa_list;
 
380
        *out_pa_list_size = num_addition;
 
381
    } else {
 
382
        /*
 
383
         * Allocate room for the existing entries plus
 
384
         * the new additions and a NULL terminator.
 
385
         */
 
386
        pa_list = malloc((*out_pa_list_size + num_addition + 1)
 
387
                                                * sizeof(krb5_pa_data *));
 
388
        if (pa_list == NULL)
 
389
            return ENOMEM;
 
390
        for (i = 0; i < *out_pa_list_size; i++)
 
391
            pa_list[i] = (*out_pa_list)[i];
 
392
        for (j = 0; j < num_addition;)
 
393
            pa_list[i++] = addition[j++];
 
394
        pa_list[i] = NULL;
 
395
        free(*out_pa_list);
 
396
        *out_pa_list = pa_list;
 
397
        *out_pa_list_size = i;
 
398
    }
 
399
    return 0;
 
400
}
 
401
 
 
402
/*
 
403
 * Retrieve a specific piece of information required by the plugin and
 
404
 * return it in a new krb5_data item.  There are separate request_types
 
405
 * to obtain the data and free it.
 
406
 *
 
407
 * This may require massaging data into a contrived format, but it will
 
408
 * hopefully keep us from having to reveal library-internal functions
 
409
 * or data to the plugin modules.
 
410
 */
 
411
 
 
412
static krb5_error_code
 
413
client_data_proc(krb5_context kcontext,
 
414
                 krb5_preauth_client_rock *rock,
 
415
                 krb5_int32 request_type,
 
416
                 krb5_data **retdata)
 
417
{
 
418
    krb5_data *ret;
 
419
    char *data;
 
420
 
 
421
    if (rock->magic != CLIENT_ROCK_MAGIC)
 
422
        return EINVAL;
 
423
    if (retdata == NULL)
 
424
        return EINVAL;
 
425
 
 
426
    switch (request_type) {
 
427
    case krb5plugin_preauth_client_get_etype:
 
428
        {
 
429
            krb5_enctype *eptr;
 
430
            if (rock->as_reply == NULL)
 
431
                return ENOENT;
 
432
            ret = malloc(sizeof(krb5_data));
 
433
            if (ret == NULL)
 
434
                return ENOMEM;
 
435
            data = malloc(sizeof(krb5_enctype));
 
436
            if (data == NULL) {
 
437
                free(ret);
 
438
                return ENOMEM;
 
439
            }
 
440
            ret->data = data;
 
441
            ret->length = sizeof(krb5_enctype);
 
442
            eptr = (krb5_enctype *)data;
 
443
            *eptr = rock->as_reply->enc_part.enctype;
 
444
            *retdata = ret;
 
445
            return 0;
 
446
        }
 
447
        break;
 
448
    case krb5plugin_preauth_client_free_etype:
 
449
        ret = *retdata;
 
450
        if (ret == NULL)
 
451
            return 0;
 
452
        if (ret->data)
 
453
            free(ret->data);
 
454
        free(ret);
 
455
        return 0;
 
456
        break;
 
457
    default:
 
458
        return EINVAL;
 
459
    }
 
460
}
 
461
 
 
462
/* Tweak the request body, for now adding any enctypes which the module claims
 
463
 * to add support for to the list, but in the future perhaps doing more
 
464
 * involved things. */
 
465
void KRB5_CALLCONV
 
466
krb5_preauth_prepare_request(krb5_context kcontext,
 
467
                             krb5_gic_opt_ext *opte,
 
468
                             krb5_kdc_req *request)
 
469
{
 
470
    int i, j;
 
471
 
 
472
    if (kcontext->preauth_context == NULL) {
 
473
        return;
 
474
    }
 
475
    /* Add the module-specific enctype list to the request, but only if
 
476
     * it's something we can safely modify. */
 
477
    if (!(opte && (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))) {
 
478
        for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
 
479
            if (kcontext->preauth_context->modules[i].enctypes == NULL)
 
480
                continue;
 
481
            for (j = 0; kcontext->preauth_context->modules[i].enctypes[j] != 0; j++) {
 
482
                grow_ktypes(&request->ktype, &request->nktypes,
 
483
                            kcontext->preauth_context->modules[i].enctypes[j]);
 
484
            }
 
485
        }
 
486
    }
 
487
}
 
488
 
 
489
/* Find the first module which provides for the named preauth type which also
 
490
 * hasn't had a chance to run yet (INFO modules don't count, because as a rule
 
491
 * they don't generate preauth data), and run it. */
 
492
static krb5_error_code
 
493
krb5_run_preauth_plugins(krb5_context kcontext,
 
494
                         int module_required_flags,
 
495
                         krb5_kdc_req *request,
 
496
                         krb5_data *encoded_request_body,
 
497
                         krb5_data *encoded_previous_request,
 
498
                         krb5_pa_data *in_padata,
 
499
                         krb5_prompter_fct prompter,
 
500
                         void *prompter_data,
 
501
                         preauth_get_as_key_proc gak_fct,
 
502
                         krb5_data *salt,
 
503
                         krb5_data *s2kparams,
 
504
                         void *gak_data,
 
505
                         krb5_preauth_client_rock *get_data_rock,
 
506
                         krb5_keyblock *as_key,
 
507
                         krb5_pa_data ***out_pa_list,
 
508
                         int *out_pa_list_size,
 
509
                         int *module_ret,
 
510
                         int *module_flags,
 
511
                         krb5_gic_opt_ext *opte)
 
512
{
 
513
    int i;
 
514
    krb5_pa_data **out_pa_data;
 
515
    krb5_error_code ret;
 
516
    struct _krb5_preauth_context_module *module;
 
517
 
 
518
    if (kcontext->preauth_context == NULL) {
 
519
        return ENOENT;
 
520
    }
 
521
    /* iterate over all loaded modules */
 
522
    for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
 
523
        module = &kcontext->preauth_context->modules[i];
 
524
        /* skip over those which don't match the preauth type */
 
525
        if (module->pa_type != in_padata->pa_type)
 
526
            continue;
 
527
        /* skip over those which don't match the flags (INFO vs REAL, mainly) */
 
528
        if ((module->flags & module_required_flags) == 0)
 
529
            continue;
 
530
        /* if it's a REAL module, try to call it only once per library call */
 
531
        if (module_required_flags & PA_REAL) {
 
532
            if (module->use_count > 0) {
 
533
#ifdef DEBUG
 
534
                fprintf(stderr, "skipping already-used module \"%s\"(%d)\n",
 
535
                        module->name, module->pa_type);
 
536
#endif
 
537
                continue;
 
538
            }
 
539
            module->use_count++;
 
540
        }
 
541
        /* run the module's callback function */
 
542
        out_pa_data = NULL;
 
543
#ifdef DEBUG
 
544
        fprintf(stderr, "using module \"%s\" (%d), flags = %d\n",
 
545
                module->name, module->pa_type, module->flags);
 
546
#endif
 
547
        ret = module->client_process(kcontext,
 
548
                                     module->plugin_context,
 
549
                                     *module->request_context_pp,
 
550
                                     (krb5_get_init_creds_opt *)opte,
 
551
                                     client_data_proc,
 
552
                                     get_data_rock,
 
553
                                     request,
 
554
                                     encoded_request_body,
 
555
                                     encoded_previous_request,
 
556
                                     in_padata,
 
557
                                     prompter, prompter_data,
 
558
                                     gak_fct, gak_data, salt, s2kparams,
 
559
                                     as_key,
 
560
                                     &out_pa_data);
 
561
        /* Make note of the module's flags and status. */
 
562
        *module_flags = module->flags;
 
563
        *module_ret = ret;
 
564
        /* Save the new preauth data item. */
 
565
        if (out_pa_data != NULL) {
 
566
            int j;
 
567
            for (j = 0; out_pa_data[j] != NULL; j++);
 
568
            ret = grow_pa_list(out_pa_list, out_pa_list_size, out_pa_data, j);
 
569
            free(out_pa_data);
 
570
            if (ret != 0)
 
571
                return ret;
 
572
        }
 
573
        break;
 
574
    }
 
575
    if (i >= kcontext->preauth_context->n_modules) {
 
576
        return ENOENT;
 
577
    }
 
578
    return 0;
 
579
}
54
580
 
55
581
static
56
582
krb5_error_code pa_salt(krb5_context context,
101
627
#ifdef DEBUG
102
628
        fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__,
103
629
                 salt->length);
104
 
        if (salt->length > 0)
105
 
            fprintf (stderr, " '%*s'", salt->length, salt->data);
 
630
        if ((int) salt->length > 0)
 
631
            fprintf (stderr, " '%.*s'", salt->length, salt->data);
106
632
        fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n",
107
633
                 *etype, request->ktype[0]);
108
634
#endif
819
1345
    },
820
1346
};
821
1347
 
822
 
krb5_error_code
 
1348
/*
 
1349
 * If one of the modules can adjust its AS_REQ data using the contents of the
 
1350
 * err_reply, return 0.  If it's the sort of correction which requires that we
 
1351
 * ask the user another question, we let the calling application deal with it.
 
1352
 */
 
1353
krb5_error_code KRB5_CALLCONV
 
1354
krb5_do_preauth_tryagain(krb5_context kcontext,
 
1355
                         krb5_kdc_req *request,
 
1356
                         krb5_data *encoded_request_body,
 
1357
                         krb5_data *encoded_previous_request,
 
1358
                         krb5_pa_data **padata,
 
1359
                         krb5_pa_data ***return_padata,
 
1360
                         krb5_error *err_reply,
 
1361
                         krb5_data *salt, krb5_data *s2kparams,
 
1362
                         krb5_enctype *etype,
 
1363
                         krb5_keyblock *as_key,
 
1364
                         krb5_prompter_fct prompter, void *prompter_data,
 
1365
                         krb5_gic_get_as_key_fct gak_fct, void *gak_data,
 
1366
                         krb5_preauth_client_rock *get_data_rock,
 
1367
                         krb5_gic_opt_ext *opte)
 
1368
{
 
1369
    krb5_error_code ret;
 
1370
    krb5_pa_data **out_padata;
 
1371
    krb5_preauth_context *context;
 
1372
    struct _krb5_preauth_context_module *module;
 
1373
    int i, j;
 
1374
    int out_pa_list_size = 0;
 
1375
 
 
1376
    ret = KRB5KRB_ERR_GENERIC;
 
1377
    if (kcontext->preauth_context == NULL) {
 
1378
       return KRB5KRB_ERR_GENERIC;
 
1379
    }
 
1380
    context = kcontext->preauth_context;
 
1381
    if (context == NULL) {
 
1382
       return KRB5KRB_ERR_GENERIC;
 
1383
    }
 
1384
 
 
1385
    for (i = 0; padata[i] != NULL && padata[i]->pa_type != 0; i++) {
 
1386
        out_padata = NULL;
 
1387
        for (j = 0; j < context->n_modules; j++) {
 
1388
            module = &context->modules[j];
 
1389
            if (module->pa_type != padata[i]->pa_type) {
 
1390
                continue;
 
1391
            }
 
1392
            if (module->client_tryagain == NULL) {
 
1393
                continue;
 
1394
            }
 
1395
            if ((*module->client_tryagain)(kcontext,
 
1396
                                           module->plugin_context,
 
1397
                                           *module->request_context_pp,
 
1398
                                           (krb5_get_init_creds_opt *)opte,
 
1399
                                           client_data_proc,
 
1400
                                           get_data_rock,
 
1401
                                           request,
 
1402
                                           encoded_request_body,
 
1403
                                           encoded_previous_request,
 
1404
                                           padata[i],
 
1405
                                           err_reply,
 
1406
                                           prompter, prompter_data,
 
1407
                                           gak_fct, gak_data, salt, s2kparams,
 
1408
                                           as_key,
 
1409
                                           &out_padata) == 0) {
 
1410
                if (out_padata != NULL) {
 
1411
                    int k;
 
1412
                    for (k = 0; out_padata[k] != NULL; k++);
 
1413
                    grow_pa_list(return_padata, &out_pa_list_size,
 
1414
                                 out_padata, k);
 
1415
                    free(out_padata);
 
1416
                    return 0;
 
1417
                }
 
1418
            }
 
1419
        }
 
1420
    }
 
1421
    return ret;
 
1422
}
 
1423
 
 
1424
krb5_error_code KRB5_CALLCONV
823
1425
krb5_do_preauth(krb5_context context,
824
1426
                krb5_kdc_req *request,
 
1427
                krb5_data *encoded_request_body,
 
1428
                krb5_data *encoded_previous_request,
825
1429
                krb5_pa_data **in_padata, krb5_pa_data ***out_padata,
826
1430
                krb5_data *salt, krb5_data *s2kparams,
827
1431
                krb5_enctype *etype,
828
1432
                krb5_keyblock *as_key,
829
1433
                krb5_prompter_fct prompter, void *prompter_data,
830
 
                krb5_gic_get_as_key_fct gak_fct, void *gak_data)
 
1434
                krb5_gic_get_as_key_fct gak_fct, void *gak_data,
 
1435
                krb5_preauth_client_rock *get_data_rock,
 
1436
                krb5_gic_opt_ext *opte)
831
1437
{
832
1438
    int h, i, j, out_pa_list_size;
833
1439
    int seen_etype_info2 = 0;
844
1450
    }
845
1451
 
846
1452
#ifdef DEBUG
847
 
    fprintf (stderr, "salt len=%d", salt->length);
848
 
    if (salt->length > 0)
849
 
        fprintf (stderr, " '%*s'", salt->length, salt->data);
 
1453
    fprintf (stderr, "salt len=%d", (int) salt->length);
 
1454
    if ((int) salt->length > 0)
 
1455
        fprintf (stderr, " '%.*s'", salt->length, salt->data);
850
1456
    fprintf (stderr, "; preauth data types:");
851
1457
    for (i = 0; in_padata[i]; i++) {
852
1458
        fprintf (stderr, " %d", in_padata[i]->pa_type);
865
1471
            int k, l, etype_found, valid_etype_found;
866
1472
            /*
867
1473
             * This is really gross, but is necessary to prevent
868
 
             * lossge when talking to a 1.0.x KDC, which returns an
 
1474
             * lossage when talking to a 1.0.x KDC, which returns an
869
1475
             * erroneous PA-PW-SALT when it returns a KRB-ERROR
870
1476
             * requiring additional preauth.
871
1477
             */
892
1498
                else ret = decode_krb5_etype_info(&scratch, &etype_info);
893
1499
                if (ret) {
894
1500
                    ret = 0; /*Ignore error and etype_info element*/
895
 
                    krb5_free_etype_info( context, etype_info);
 
1501
                    if (etype_info) 
 
1502
                      krb5_free_etype_info( context, etype_info);
896
1503
                    etype_info = NULL;
897
1504
                    continue;
898
1505
                }
952
1559
                    fprintf (stderr, "etype info %d: etype %d salt len=%d",
953
1560
                             j, e->etype, e->length);
954
1561
                    if (e->length > 0 && e->length != KRB5_ETYPE_NO_SALT)
955
 
                        fprintf (stderr, " '%*s'", e->length, e->salt);
 
1562
                        fprintf (stderr, " '%.*s'", e->length, e->salt);
956
1563
                    fprintf (stderr, "\n");
957
1564
                }
958
1565
#endif
966
1573
            default:
967
1574
                ;
968
1575
            }
969
 
            for (j=0; pa_types[j].type >= 0; j++) {
 
1576
            /* Try the internally-provided preauth type list. */
 
1577
            if (!realdone) for (j=0; pa_types[j].type >= 0; j++) {
970
1578
                if ((in_padata[i]->pa_type == pa_types[j].type) &&
971
1579
                    (pa_types[j].flags & paorder[h])) {
 
1580
#ifdef DEBUG
 
1581
                    fprintf (stderr, "calling internal function for pa_type "
 
1582
                             "%d, flag %d\n", pa_types[j].type, paorder[h]);
 
1583
#endif
972
1584
                    out_pa = NULL;
973
1585
 
974
1586
                    if ((ret = ((*pa_types[j].fct)(context, request,
979
1591
                      goto cleanup;
980
1592
                    }
981
1593
 
982
 
                    if (out_pa) {
983
 
                        if (out_pa_list == NULL) {
984
 
                            if ((out_pa_list =
985
 
                                 (krb5_pa_data **)
986
 
                                 malloc(2*sizeof(krb5_pa_data *)))
987
 
                                == NULL) {
988
 
                              ret = ENOMEM;
989
 
                              goto cleanup;
990
 
                            }
991
 
                        } else {
992
 
                            if ((out_pa_list =
993
 
                                 (krb5_pa_data **)
994
 
                                 realloc(out_pa_list,
995
 
                                         (out_pa_list_size+2)*
996
 
                                         sizeof(krb5_pa_data *)))
997
 
                                == NULL) {
998
 
                              /* XXX this will leak the pointers which
999
 
                                   have already been allocated.  oh well. */
1000
 
                              ret = ENOMEM;
1001
 
                              goto cleanup;
1002
 
                            }
1003
 
                        }
1004
 
                        
1005
 
                        out_pa_list[out_pa_list_size++] = out_pa;
 
1594
                    ret = grow_pa_list(&out_pa_list, &out_pa_list_size,
 
1595
                                       &out_pa, 1);
 
1596
                    if (ret != 0) {
 
1597
                            goto cleanup;
1006
1598
                    }
1007
1599
                    if (paorder[h] == PA_REAL)
1008
1600
                        realdone = 1;
1009
1601
                }
1010
1602
            }
 
1603
 
 
1604
            /* Try to use plugins now. */
 
1605
            if (!realdone) {
 
1606
                krb5_init_preauth_context(context);
 
1607
                if (context->preauth_context != NULL) {
 
1608
                    int module_ret, module_flags;
 
1609
#ifdef DEBUG
 
1610
                    fprintf (stderr, "trying modules for pa_type %d, flag %d\n",
 
1611
                             in_padata[i]->pa_type, paorder[h]);
 
1612
#endif
 
1613
                    ret = krb5_run_preauth_plugins(context,
 
1614
                                                   paorder[h],
 
1615
                                                   request,
 
1616
                                                   encoded_request_body,
 
1617
                                                   encoded_previous_request,
 
1618
                                                   in_padata[i],
 
1619
                                                   prompter,
 
1620
                                                   prompter_data,
 
1621
                                                   gak_fct,
 
1622
                                                   salt, s2kparams,
 
1623
                                                   gak_data,
 
1624
                                                   get_data_rock,
 
1625
                                                   as_key,
 
1626
                                                   &out_pa_list,
 
1627
                                                   &out_pa_list_size,
 
1628
                                                   &module_ret,
 
1629
                                                   &module_flags,
 
1630
                                                   opte);
 
1631
                    if (ret == 0) {
 
1632
                        if (module_ret == 0) {
 
1633
                            if (paorder[h] == PA_REAL) {
 
1634
                                realdone = 1;
 
1635
                            }
 
1636
                        }
 
1637
                    }
 
1638
                }
 
1639
            }
1011
1640
        }
1012
1641
    }
1013
1642
 
1014
 
    if (out_pa_list)
1015
 
        out_pa_list[out_pa_list_size++] = NULL;
1016
 
 
1017
1643
    *out_padata = out_pa_list;
1018
1644
    if (etype_info)
1019
1645
      krb5_free_etype_info(context, etype_info);