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

« back to all changes in this revision

Viewing changes to src/clients/kinit/kinit.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2009-05-07 16:16:34 UTC
  • mfrom: (13.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20090507161634-xqyk0s9na0le4flj
Tags: 1.7dfsg~beta1-4
When  decrypting the TGS response fails with the subkey, try with the
session key to work around Heimdal bug, Closes: #527353 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * clients/kinit/kinit.c
3
3
 *
4
 
 * Copyright 1990 by the Massachusetts Institute of Technology.
 
4
 * Copyright 1990, 2008 by the Massachusetts Institute of Technology.
5
5
 * All Rights Reserved.
6
6
 *
7
7
 * Export of this software from the United States of America may
28
28
 */
29
29
 
30
30
#include "autoconf.h"
 
31
#include "k5-platform.h"        /* for asprintf */
31
32
#include <krb5.h>
32
 
#ifdef KRB5_KRB4_COMPAT
33
 
#include <kerberosIV/krb.h>
34
 
#define HAVE_KRB524
35
 
#else
36
 
#undef HAVE_KRB524
37
 
#endif
38
33
#include <string.h>
39
34
#include <stdio.h>
40
35
#include <time.h>
97
92
#endif /* _WIN32 */
98
93
#endif /* HAVE_PWD_H */
99
94
 
100
 
static char* progname_v5 = 0;
101
 
#ifdef KRB5_KRB4_COMPAT
102
 
static char* progname_v4 = 0;
103
 
static char* progname_v524 = 0;
104
 
#endif
105
 
 
106
 
static int got_k5 = 0;
107
 
static int got_k4 = 0;
108
 
 
109
 
static int default_k5 = 1;
110
 
#if defined(KRB5_KRB4_COMPAT) && defined(KINIT_DEFAULT_BOTH)
111
 
static int default_k4 = 1;
112
 
#else
113
 
static int default_k4 = 0;
114
 
#endif
115
 
 
116
 
static int authed_k5 = 0;
117
 
static int authed_k4 = 0;
118
 
 
119
 
#define KRB4_BACKUP_DEFAULT_LIFE_SECS 24*60*60 /* 1 day */
 
95
static char *progname;
120
96
 
121
97
typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;
122
98
 
141
117
    char* service_name;
142
118
    char* keytab_name;
143
119
    char* k5_cache_name;
144
 
    char* k4_cache_name;
 
120
    char *armor_ccache;
145
121
 
146
122
    action_type action;
147
123
 
148
124
    int num_pa_opts;
149
125
    krb5_gic_opt_pa_data *pa_opts;
 
126
 
 
127
    int canonicalize;
 
128
    int enterprise;
150
129
};
151
130
 
152
131
struct k5_data
157
136
    char* name;
158
137
};
159
138
 
160
 
struct k4_data
161
 
{
162
 
    krb5_deltat lifetime;
163
 
#ifdef KRB5_KRB4_COMPAT
164
 
    char aname[ANAME_SZ + 1];
165
 
    char inst[INST_SZ + 1];
166
 
    char realm[REALM_SZ + 1];
167
 
    char name[ANAME_SZ + 1 + INST_SZ + 1 + REALM_SZ + 1];
168
 
#endif
169
 
};
170
 
 
171
139
#ifdef GETOPT_LONG
172
140
/* if struct[2] == NULL, then long_getopt acts as if the short flag
173
141
   struct[3] was specified.  If struct[2] != NULL, then struct[3] is
181
149
    { "forwardable", 0, NULL, 'f' },
182
150
    { "proxiable", 0, NULL, 'p' },
183
151
    { "noaddresses", 0, NULL, 'A' },
 
152
    { "canonicalize", 0, NULL, 'C' },
 
153
    { "enterprise", 0, NULL, 'E' },
184
154
    { NULL, 0, NULL, 0 }
185
155
};
186
156
 
190
160
#endif
191
161
 
192
162
static void
193
 
usage(progname)
194
 
     char *progname;
 
163
usage()
195
164
{
196
165
#define USAGE_BREAK "\n\t"
197
166
 
198
167
#ifdef GETOPT_LONG
199
 
#define USAGE_LONG_FORWARDABLE " | --forwardable | --noforwardable"
200
 
#define USAGE_LONG_PROXIABLE   " | --proxiable | --noproxiable"
201
 
#define USAGE_LONG_ADDRESSES   " | --addresses | --noaddresses"
 
168
#define USAGE_LONG_FORWARDABLE  " | --forwardable | --noforwardable"
 
169
#define USAGE_LONG_PROXIABLE    " | --proxiable | --noproxiable"
 
170
#define USAGE_LONG_ADDRESSES    " | --addresses | --noaddresses"
 
171
#define USAGE_LONG_CANONICALIZE " | --canonicalize"
 
172
#define USAGE_LONG_ENTERPRISE   " | --enterprise"
202
173
#define USAGE_BREAK_LONG       USAGE_BREAK
203
174
#else
204
 
#define USAGE_LONG_FORWARDABLE ""
205
 
#define USAGE_LONG_PROXIABLE   ""
206
 
#define USAGE_LONG_ADDRESSES   ""
207
 
#define USAGE_BREAK_LONG       ""
 
175
#define USAGE_LONG_FORWARDABLE  ""
 
176
#define USAGE_LONG_PROXIABLE    ""
 
177
#define USAGE_LONG_ADDRESSES    ""
 
178
#define USAGE_LONG_CANONICALIZE ""
 
179
#define USAGE_LONG_ENTERPRISE   ""
 
180
#define USAGE_BREAK_LONG        ""
208
181
#endif
209
182
 
210
 
    fprintf(stderr, "Usage: %s [-5] [-4] [-V] "
 
183
    fprintf(stderr, "Usage: %s [-V] "
211
184
            "[-l lifetime] [-s start_time] "
212
185
            USAGE_BREAK
213
186
            "[-r renewable_life] "
216
189
            "[-p | -P" USAGE_LONG_PROXIABLE "] "
217
190
            USAGE_BREAK_LONG
218
191
            "[-a | -A" USAGE_LONG_ADDRESSES "] "
 
192
            USAGE_BREAK_LONG
 
193
            "[-C" USAGE_LONG_CANONICALIZE "] "
 
194
            USAGE_BREAK
 
195
            "[-E" USAGE_LONG_ENTERPRISE "] "
219
196
            USAGE_BREAK
220
197
            "[-v] [-R] "
221
198
            "[-k [-t keytab_file]] "
222
 
            "[-c cachename] "
223
 
            USAGE_BREAK
224
 
            "[-S service_name]"
 
199
            "[-c cachename] " 
 
200
            USAGE_BREAK
 
201
            "[-S service_name]""-T ticket_armor_cache"
 
202
            USAGE_BREAK
225
203
            "[-X <attribute>[=<value>]] [principal]"
226
204
            "\n\n", 
227
205
            progname);
228
206
 
229
 
#define KRB_AVAIL_STRING(x) ((x)?"available":"not available")
230
 
 
231
 
#define OPTTYPE_KRB5   "5"
232
 
#define OPTTYPE_KRB4   "4"
233
 
#define OPTTYPE_EITHER "Either 4 or 5"
234
 
#ifdef HAVE_KRB524
235
 
#define OPTTYPE_BOTH "5, or both 5 and 4"
236
 
#else
237
 
#define OPTTYPE_BOTH "5"
238
 
#endif
239
 
 
240
 
#ifdef KRB5_KRB4_COMPAT
241
 
#define USAGE_OPT_FMT "%s%-50s%s\n"
242
 
#define ULINE(indent, col1, col2) \
243
 
fprintf(stderr, USAGE_OPT_FMT, indent, col1, col2)
244
 
#else
245
 
#define USAGE_OPT_FMT "%s%s\n"
246
 
#define ULINE(indent, col1, col2) \
247
 
fprintf(stderr, USAGE_OPT_FMT, indent, col1)
248
 
#endif
249
 
 
250
 
    ULINE("    ", "options:", "valid with Kerberos:");
251
 
    fprintf(stderr, "\t-5 Kerberos 5 (%s)\n", KRB_AVAIL_STRING(got_k5));
252
 
    fprintf(stderr, "\t-4 Kerberos 4 (%s)\n", KRB_AVAIL_STRING(got_k4));
253
 
    fprintf(stderr, "\t   (Default behavior is to try %s%s%s%s)\n",
254
 
            default_k5?"Kerberos 5":"",
255
 
            (default_k5 && default_k4)?" and ":"",
256
 
            default_k4?"Kerberos 4":"",
257
 
            (!default_k5 && !default_k4)?"neither":"");
258
 
    ULINE("\t", "-V verbose",                   OPTTYPE_EITHER);
259
 
    ULINE("\t", "-l lifetime",                  OPTTYPE_EITHER);
260
 
    ULINE("\t", "-s start time",                OPTTYPE_KRB5);
261
 
    ULINE("\t", "-r renewable lifetime",        OPTTYPE_KRB5);
262
 
    ULINE("\t", "-f forwardable",               OPTTYPE_KRB5);
263
 
    ULINE("\t", "-F not forwardable",           OPTTYPE_KRB5);
264
 
    ULINE("\t", "-p proxiable",                 OPTTYPE_KRB5);
265
 
    ULINE("\t", "-P not proxiable",             OPTTYPE_KRB5);
266
 
    ULINE("\t", "-a include addresses",         OPTTYPE_KRB5);
267
 
    ULINE("\t", "-A do not include addresses",  OPTTYPE_KRB5);
268
 
    ULINE("\t", "-v validate",                  OPTTYPE_KRB5);
269
 
    ULINE("\t", "-R renew",                     OPTTYPE_BOTH);
270
 
    ULINE("\t", "-k use keytab",                OPTTYPE_BOTH);
271
 
    ULINE("\t", "-t filename of keytab to use", OPTTYPE_BOTH);
272
 
    ULINE("\t", "-c Kerberos 5 cache name",     OPTTYPE_KRB5);
273
 
    /* This options is not yet available: */
274
 
    /* ULINE("\t", "-C Kerberos 4 cache name",     OPTTYPE_KRB4); */
275
 
    ULINE("\t", "-S service",                   OPTTYPE_BOTH);
276
 
    ULINE("\t", "-X <attribute>[=<value>]",     OPTTYPE_KRB5);
 
207
    fprintf(stderr, "    options:");
 
208
    fprintf(stderr, "\t-V verbose\n");
 
209
    fprintf(stderr, "\t-l lifetime\n");
 
210
    fprintf(stderr, "\t-s start time\n");
 
211
    fprintf(stderr, "\t-r renewable lifetime\n");
 
212
    fprintf(stderr, "\t-f forwardable\n");
 
213
    fprintf(stderr, "\t-F not forwardable\n");
 
214
    fprintf(stderr, "\t-p proxiable\n");
 
215
    fprintf(stderr, "\t-P not proxiable\n");
 
216
    fprintf(stderr, "\t-a include addresses\n");
 
217
    fprintf(stderr, "\t-A do not include addresses\n");
 
218
    fprintf(stderr, "\t-v validate\n");
 
219
    fprintf(stderr, "\t-R renew\n");
 
220
    fprintf(stderr, "\t-C canonicalize\n");
 
221
    fprintf(stderr, "\t-E client is enterprise principal name\n");
 
222
    fprintf(stderr, "\t-k use keytab\n");
 
223
    fprintf(stderr, "\t-t filename of keytab to use\n");
 
224
    fprintf(stderr, "\t-c Kerberos 5 cache name\n");
 
225
    fprintf(stderr, "\t-S service\n");
 
226
    fprintf(stderr, "\t-X <attribute>[=<value>]\n");
277
227
    exit(2);
278
228
}
279
229
 
321
271
}
322
272
 
323
273
static char *
324
 
parse_options(argc, argv, opts, progname)
 
274
parse_options(argc, argv, opts)
325
275
    int argc;
326
276
    char **argv;
327
277
    struct k_opts* opts;
328
 
    char *progname;
329
278
{
330
279
    krb5_error_code code;
331
280
    int errflg = 0;
332
 
    int use_k4 = 0;
333
 
    int use_k5 = 0;
334
281
    int i;
335
282
 
336
 
    while ((i = GETOPT(argc, argv, "r:fpFP54aAVl:s:c:kt:RS:vX:"))
 
283
    while ((i = GETOPT(argc, argv, "r:fpFP54aAVl:s:c:kt:T:RS:vX:CE"))
337
284
           != -1) {
338
285
        switch (i) {
339
286
        case 'V':
402
349
                opts->keytab_name = optarg;
403
350
            }
404
351
            break;
 
352
        case 'T':
 
353
            if (opts->armor_ccache) {
 
354
                fprintf(stderr, "Only one armor_ccache\n");
 
355
                errflg++;
 
356
            } else opts->armor_ccache = optarg;
 
357
            break;
405
358
        case 'R':
406
359
            opts->action = RENEW;
407
360
            break;
425
378
                errflg++;
426
379
            }
427
380
            break;
428
 
#if 0
429
 
            /*
430
 
              A little more work is needed before we can enable this
431
 
              option.
432
 
            */
433
381
        case 'C':
434
 
            if (opts->k4_cache_name)
435
 
            {
436
 
                fprintf(stderr, "Only one -C option allowed\n");
437
 
                errflg++;
438
 
            } else {
439
 
                opts->k4_cache_name = optarg;
440
 
            }
441
 
            break;
442
 
#endif
 
382
            opts->canonicalize = 1;
 
383
            break;
 
384
        case 'E':
 
385
            opts->enterprise = 1;
 
386
            break;
443
387
        case '4':
444
 
            if (!got_k4)
445
 
            {
446
 
#ifdef KRB5_KRB4_COMPAT
447
 
                fprintf(stderr, "Kerberos 4 support could not be loaded\n");
448
 
#else
449
 
                fprintf(stderr, "This was not built with Kerberos 4 support\n");
450
 
#endif
451
 
                exit(3);
452
 
            }
453
 
            use_k4 = 1;
 
388
            fprintf(stderr, "Kerberos 4 is no longer supported\n");
 
389
            exit(3);
454
390
            break;
455
391
        case '5':
456
 
            if (!got_k5)
457
 
            {
458
 
                fprintf(stderr, "Kerberos 5 support could not be loaded\n");
459
 
                exit(3);
460
 
            }
461
 
            use_k5 = 1;
462
392
            break;
463
393
        default:
464
394
            errflg++;
488
418
        errflg++;
489
419
    }
490
420
 
491
 
    /* At this point, if errorless, we know we only have one option
492
 
       selection */
493
 
    if (!use_k5 && !use_k4) {
494
 
        use_k5 = default_k5;
495
 
        use_k4 = default_k4;
496
 
    }
497
 
 
498
 
    /* Now, we encode the OPTTYPE stuff here... */
499
 
    if (!use_k5 &&
500
 
        (opts->starttime || opts->rlife || opts->forwardable || 
501
 
         opts->proxiable || opts->addresses || opts->not_forwardable || 
502
 
         opts->not_proxiable || opts->no_addresses || 
503
 
         (opts->action == VALIDATE) || opts->k5_cache_name))
504
 
    {
505
 
        fprintf(stderr, "Specified option that requires Kerberos 5\n");
506
 
        errflg++;
507
 
    }
508
 
    if (!use_k4 &&
509
 
        opts->k4_cache_name)
510
 
    {
511
 
        fprintf(stderr, "Specified option that require Kerberos 4\n");
512
 
        errflg++;
513
 
    }
514
 
    if (
515
 
#ifdef HAVE_KRB524
516
 
        !use_k5
517
 
#else
518
 
        use_k4
519
 
#endif
520
 
        && (opts->service_name || opts->keytab_name || 
521
 
            (opts->action == INIT_KT) || (opts->action == RENEW))
522
 
        )
523
 
    {
524
 
        fprintf(stderr, "Specified option that requires Kerberos 5\n");
525
 
        errflg++;
526
 
    }
527
 
 
528
421
    if (errflg) {
529
 
        usage(progname);
 
422
        usage();
530
423
    }
531
424
 
532
 
    got_k5 = got_k5 && use_k5;
533
 
    got_k4 = got_k4 && use_k4;
534
 
 
535
425
    opts->principal_name = (optind == argc-1) ? argv[optind] : 0;
536
426
    return opts->principal_name;
537
427
}
538
428
 
539
429
static int
540
 
k5_begin(opts, k5, k4)
 
430
k5_begin(opts, k5)
541
431
    struct k_opts* opts;
542
 
struct k5_data* k5;
543
 
struct k4_data* k4;
 
432
    struct k5_data* k5;
544
433
{
545
 
    char* progname = progname_v5;
546
434
    krb5_error_code code = 0;
547
 
 
548
 
    if (!got_k5)
549
 
        return 0;
 
435
    int flags = opts->enterprise ? KRB5_PRINCIPAL_PARSE_ENTERPRISE : 0;
550
436
 
551
437
    code = krb5_init_context(&k5->ctx);
552
438
    if (code) {
574
460
    if (opts->principal_name)
575
461
    {
576
462
        /* Use specified name */
577
 
        if ((code = krb5_parse_name(k5->ctx, opts->principal_name, 
578
 
                                    &k5->me))) {
 
463
        if ((code = krb5_parse_name_flags(k5->ctx, opts->principal_name, 
 
464
                                          flags, &k5->me))) {
579
465
            com_err(progname, code, "when parsing name %s", 
580
466
                    opts->principal_name);
581
467
            return 0;
605
491
                  fprintf(stderr, "Unable to identify user\n");
606
492
                  return 0;
607
493
                }
608
 
              if ((code = krb5_parse_name(k5->ctx, name, 
609
 
                                          &k5->me)))
 
494
              if ((code = krb5_parse_name_flags(k5->ctx, name, 
 
495
                                                flags, &k5->me)))
610
496
                {
611
497
                  com_err(progname, code, "when parsing name %s", 
612
498
                          name);
623
509
    }
624
510
    opts->principal_name = k5->name;
625
511
 
626
 
#ifdef KRB5_KRB4_COMPAT
627
 
    if (got_k4)
628
 
    {
629
 
        /* Translate to a Kerberos 4 principal */
630
 
        code = krb5_524_conv_principal(k5->ctx, k5->me,
631
 
                                       k4->aname, k4->inst, k4->realm);
632
 
        if (code) {
633
 
            k4->aname[0] = 0;
634
 
            k4->inst[0] = 0;
635
 
            k4->realm[0] = 0;
636
 
        }
637
 
    }
638
 
#endif
639
512
    return 1;
640
513
}
641
514
 
655
528
    memset(k5, 0, sizeof(*k5));
656
529
}
657
530
 
658
 
static int
659
 
k4_begin(opts, k4)
660
 
    struct k_opts* opts;
661
 
    struct k4_data* k4;
662
 
{
663
 
#ifdef KRB5_KRB4_COMPAT
664
 
    char* progname = progname_v4;
665
 
    int k_errno = 0;
666
 
#endif
667
 
 
668
 
    if (!got_k4)
669
 
        return 0;
670
 
 
671
 
#ifdef KRB5_KRB4_COMPAT
672
 
    if (k4->aname[0])
673
 
        goto skip;
674
 
 
675
 
    if (opts->principal_name)
676
 
    {
677
 
        /* Use specified name */
678
 
        k_errno = kname_parse(k4->aname, k4->inst, k4->realm, 
679
 
                              opts->principal_name);
680
 
        if (k_errno)
681
 
        {
682
 
            fprintf(stderr, "%s: %s\n", progname, 
683
 
                    krb_get_err_text(k_errno));
684
 
            return 0;
685
 
        }
686
 
    } else {
687
 
        /* No principal name specified */
688
 
        if (opts->action == INIT_KT) {
689
 
            /* Use the default host/service name */
690
 
            /* XXX - need to add this functionality */
691
 
            fprintf(stderr, "%s: Kerberos 4 srvtab support is not "
692
 
                    "implemented\n", progname);
693
 
            return 0;
694
 
        } else {
695
 
            /* Get default principal from cache if one exists */
696
 
            k_errno = krb_get_tf_fullname(tkt_string(), k4->aname, 
697
 
                                          k4->inst, k4->realm);
698
 
            if (k_errno)
699
 
            {
700
 
                char *name = get_name_from_os();
701
 
                if (!name)
702
 
                {
703
 
                    fprintf(stderr, "Unable to identify user\n");
704
 
                    return 0;
705
 
                }
706
 
                k_errno = kname_parse(k4->aname, k4->inst, k4->realm,
707
 
                                      name);
708
 
                if (k_errno)
709
 
                {
710
 
                    fprintf(stderr, "%s: %s\n", progname, 
711
 
                            krb_get_err_text(k_errno));
712
 
                    return 0;
713
 
                }
714
 
            }
715
 
        }
716
 
    }
717
 
 
718
 
    if (!k4->realm[0])
719
 
        krb_get_lrealm(k4->realm, 1);
720
 
 
721
 
    if (k4->inst[0])
722
 
        sprintf(k4->name, "%s.%s@%s", k4->aname, k4->inst, k4->realm);
723
 
    else
724
 
        sprintf(k4->name, "%s@%s", k4->aname, k4->realm);
725
 
    opts->principal_name = k4->name;
726
 
 
727
 
 skip:
728
 
    if (k4->aname[0] && !k_isname(k4->aname))
729
 
    {
730
 
        fprintf(stderr, "%s: bad Kerberos 4 name format\n", progname);
731
 
        return 0;
732
 
    }
733
 
 
734
 
    if (k4->inst[0] && !k_isinst(k4->inst))
735
 
    {
736
 
        fprintf(stderr, "%s: bad Kerberos 4 instance format\n", progname);
737
 
        return 0;
738
 
    }
739
 
 
740
 
    if (k4->realm[0] && !k_isrealm(k4->realm))
741
 
    {
742
 
        fprintf(stderr, "%s: bad Kerberos 4 realm format\n", progname);
743
 
        return 0;
744
 
    }
745
 
#endif /* KRB5_KRB4_COMPAT */
746
 
    return 1;
747
 
}
748
 
 
749
 
static void
750
 
k4_end(k4)
751
 
    struct k4_data* k4;
752
 
{
753
 
    memset(k4, 0, sizeof(*k4));
754
 
}
755
 
 
756
 
#ifdef KRB5_KRB4_COMPAT
757
 
static char stash_password[1024];
758
 
static int got_password = 0;
759
 
#endif /* KRB5_KRB4_COMPAT */
760
 
 
761
531
static krb5_error_code
762
532
KRB5_CALLCONV
763
533
kinit_prompter(
769
539
    krb5_prompt prompts[]
770
540
    )
771
541
{
772
 
    int i;
773
 
    krb5_prompt_type *types;
774
542
    krb5_error_code rc =
775
543
        krb5_prompter_posix(ctx, data, name, banner, num_prompts, prompts);
776
 
    if (!rc && (types = krb5_get_prompt_types(ctx)))
777
 
        for (i = 0; i < num_prompts; i++)
778
 
            if ((types[i] == KRB5_PROMPT_TYPE_PASSWORD) ||
779
 
                (types[i] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN))
780
 
            {
781
 
#ifdef KRB5_KRB4_COMPAT
782
 
                strncpy(stash_password, prompts[i].reply->data,
783
 
                        sizeof(stash_password));
784
 
                got_password = 1;
785
 
#endif
786
 
            }
787
544
    return rc;
788
545
}
789
546
 
792
549
    struct k_opts* opts;
793
550
    struct k5_data* k5;
794
551
{
795
 
    char* progname = progname_v5;
796
552
    int notix = 1;
797
553
    krb5_keytab keytab = 0;
798
554
    krb5_creds my_creds;
800
556
    krb5_get_init_creds_opt *options = NULL;
801
557
    int i;
802
558
 
803
 
    if (!got_k5)
804
 
        return 0;
 
559
    memset(&my_creds, 0, sizeof(my_creds));
805
560
 
806
561
    code = krb5_get_init_creds_opt_alloc(k5->ctx, &options);
807
562
    if (code)
808
563
        goto cleanup;
809
 
    memset(&my_creds, 0, sizeof(my_creds));
810
564
 
811
565
    /*
812
566
      From this point on, we can goto cleanup because my_creds is
825
579
        krb5_get_init_creds_opt_set_proxiable(options, 1);
826
580
    if (opts->not_proxiable)
827
581
        krb5_get_init_creds_opt_set_proxiable(options, 0);
 
582
    if (opts->canonicalize)
 
583
        krb5_get_init_creds_opt_set_canonicalize(options, 1);
828
584
    if (opts->addresses)
829
585
    {
830
586
        krb5_address **addresses = NULL;
837
593
    }
838
594
    if (opts->no_addresses)
839
595
        krb5_get_init_creds_opt_set_address_list(options, NULL);
 
596
    if (opts->armor_ccache)
 
597
    krb5_get_init_creds_opt_set_fast_ccache_name(k5->ctx, options, opts->armor_ccache);
 
598
                                                 
840
599
 
841
600
    if ((opts->action == INIT_KT) && opts->keytab_name)
842
601
    {
899
658
            break;
900
659
        }
901
660
 
902
 
        /* If got code == KRB5_AP_ERR_V4_REPLY && got_k4, we should
903
 
           let the user know that maybe he/she wants -4. */
904
 
        if (code == KRB5KRB_AP_ERR_V4_REPLY && got_k4)
905
 
            com_err(progname, code, "while %s\n"
906
 
                    "The KDC doesn't support v5.  "
907
 
                    "You may want the -4 option in the future",
908
 
                    doing);
909
 
        else if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
 
661
        if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
910
662
            fprintf(stderr, "%s: Password incorrect while %s\n", progname,
911
663
                    doing);
912
664
        else
914
666
        goto cleanup;
915
667
    }
916
668
 
917
 
    if (!opts->lifetime) {
918
 
        /* We need to figure out what lifetime to use for Kerberos 4. */
919
 
        opts->lifetime = my_creds.times.endtime - my_creds.times.authtime;
920
 
    }
921
 
 
922
 
    code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me);
 
669
    code = krb5_cc_initialize(k5->ctx, k5->cc,
 
670
                              opts->canonicalize ? my_creds.client : k5->me);
923
671
    if (code) {
924
672
        com_err(progname, code, "when initializing cache %s",
925
673
                opts->k5_cache_name?opts->k5_cache_name:"");
951
699
    return notix?0:1;
952
700
}
953
701
 
954
 
static int
955
 
k4_kinit(opts, k4, ctx)
956
 
    struct k_opts* opts;
957
 
    struct k4_data* k4;
958
 
    krb5_context ctx;
959
 
{
960
 
#ifdef KRB5_KRB4_COMPAT
961
 
    char* progname = progname_v4;
962
 
    int k_errno = 0;
963
 
#endif
964
 
 
965
 
    if (!got_k4)
966
 
        return 0;
967
 
 
968
 
    if (opts->starttime)
969
 
        return 0;
970
 
 
971
 
#ifdef KRB5_KRB4_COMPAT
972
 
    if (!k4->lifetime)
973
 
        k4->lifetime = opts->lifetime;
974
 
    if (!k4->lifetime)
975
 
        k4->lifetime = KRB4_BACKUP_DEFAULT_LIFE_SECS;
976
 
 
977
 
    k4->lifetime = krb_time_to_life(0, k4->lifetime);
978
 
 
979
 
    switch (opts->action)
980
 
    {
981
 
    case INIT_PW:
982
 
        if (!got_password) {
983
 
            unsigned int pwsize = sizeof(stash_password);
984
 
            krb5_error_code code;
985
 
            char prompt[1024];
986
 
 
987
 
            sprintf(prompt, "Password for %s", opts->principal_name);
988
 
            stash_password[0] = 0;
989
 
            /*
990
 
              Note: krb5_read_password does not actually look at the
991
 
              context, so we're ok even if we don't have a context.  If
992
 
              we cannot dynamically load krb5, we can substitute any
993
 
              decent read password function instead of the krb5 one.
994
 
            */
995
 
            code = krb5_read_password(ctx, prompt, 0, stash_password, &pwsize);
996
 
            if (code || pwsize == 0)
997
 
            {
998
 
                fprintf(stderr, "Error while reading password for '%s'\n",
999
 
                        opts->principal_name);
1000
 
                memset(stash_password, 0, sizeof(stash_password));
1001
 
                return 0;
1002
 
            }
1003
 
            got_password = 1;
1004
 
        }
1005
 
        k_errno = krb_get_pw_in_tkt(k4->aname, k4->inst, k4->realm, "krbtgt", 
1006
 
                                    k4->realm, k4->lifetime, stash_password);
1007
 
 
1008
 
        if (k_errno) {
1009
 
            fprintf(stderr, "%s: %s\n", progname, 
1010
 
                    krb_get_err_text(k_errno));
1011
 
            if (authed_k5)
1012
 
                fprintf(stderr, "Maybe your KDC does not support v4.  "
1013
 
                        "Try the -5 option next time.\n");
1014
 
            return 0;
1015
 
        }
1016
 
        return 1;
1017
 
#ifndef HAVE_KRB524
1018
 
    case INIT_KT:
1019
 
        fprintf(stderr, "%s: srvtabs are not supported\n", progname);
1020
 
        return 0;
1021
 
    case RENEW:
1022
 
        fprintf(stderr, "%s: renewal of krb4 tickets is not supported\n",
1023
 
                progname);
1024
 
        return 0;
1025
 
#else
1026
 
    /* These cases are handled by the 524 code - this prevents the compiler 
1027
 
       warnings of not using all the enumerated types.
1028
 
    */ 
1029
 
    case INIT_KT:
1030
 
    case RENEW:
1031
 
    case VALIDATE:
1032
 
        return 0;
1033
 
#endif
1034
 
    }
1035
 
#endif
1036
 
    return 0;
1037
 
}
1038
 
 
1039
 
static char*
1040
 
getvprogname(v, progname)
1041
 
    char *v, *progname;
1042
 
{
1043
 
    unsigned int len = strlen(progname) + 2 + strlen(v) + 2;
1044
 
    char *ret = malloc(len);
1045
 
    if (ret)
1046
 
        sprintf(ret, "%s(v%s)", progname, v);
1047
 
    else
1048
 
        ret = progname;
1049
 
    return ret;
1050
 
}
1051
 
 
1052
 
#ifdef HAVE_KRB524
1053
 
/* Convert krb5 tickets to krb4. */
1054
 
static int try_convert524(k5)
1055
 
    struct k5_data* k5;
1056
 
{
1057
 
    char * progname = progname_v524;
1058
 
    krb5_error_code code = 0;
1059
 
    int icode = 0;
1060
 
    krb5_principal kpcserver = 0;
1061
 
    krb5_creds *v5creds = 0;
1062
 
    krb5_creds increds;
1063
 
    CREDENTIALS v4creds;
1064
 
 
1065
 
    if (!got_k4 || !got_k5)
1066
 
        return 0;
1067
 
 
1068
 
    memset((char *) &increds, 0, sizeof(increds));
1069
 
    /*
1070
 
      From this point on, we can goto cleanup because increds is
1071
 
      initialized.
1072
 
    */
1073
 
 
1074
 
    if ((code = krb5_build_principal(k5->ctx,
1075
 
                                     &kpcserver, 
1076
 
                                     krb5_princ_realm(k5->ctx, k5->me)->length,
1077
 
                                     krb5_princ_realm(k5->ctx, k5->me)->data,
1078
 
                                     "krbtgt",
1079
 
                                     krb5_princ_realm(k5->ctx, k5->me)->data,
1080
 
                                     NULL))) {
1081
 
        com_err(progname, code,
1082
 
                "while creating service principal name");
1083
 
        goto cleanup;
1084
 
    }
1085
 
 
1086
 
    increds.client = k5->me;
1087
 
    increds.server = kpcserver;
1088
 
    /* Prevent duplicate free calls.  */
1089
 
    kpcserver = 0;
1090
 
 
1091
 
    increds.times.endtime = 0;
1092
 
    increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
1093
 
    if ((code = krb5_get_credentials(k5->ctx, 0, 
1094
 
                                     k5->cc,
1095
 
                                     &increds, 
1096
 
                                     &v5creds))) {
1097
 
        com_err(progname, code,
1098
 
                "getting V5 credentials");
1099
 
        goto cleanup;
1100
 
    }
1101
 
    if ((icode = krb524_convert_creds_kdc(k5->ctx,
1102
 
                                          v5creds,
1103
 
                                          &v4creds))) {
1104
 
        com_err(progname, icode, 
1105
 
                "converting to V4 credentials");
1106
 
        goto cleanup;
1107
 
    }
1108
 
    /* this is stolen from the v4 kinit */
1109
 
    /* initialize ticket cache */
1110
 
    if ((icode = in_tkt(v4creds.pname, v4creds.pinst)
1111
 
         != KSUCCESS)) {
1112
 
        com_err(progname, icode,
1113
 
                "trying to create the V4 ticket file");
1114
 
        goto cleanup;
1115
 
    }
1116
 
    /* stash ticket, session key, etc. for future use */
1117
 
    if ((icode = krb_save_credentials(v4creds.service,
1118
 
                                      v4creds.instance,
1119
 
                                      v4creds.realm, 
1120
 
                                      v4creds.session,
1121
 
                                      v4creds.lifetime,
1122
 
                                      v4creds.kvno,
1123
 
                                      &(v4creds.ticket_st), 
1124
 
                                      v4creds.issue_date))) {
1125
 
        com_err(progname, icode,
1126
 
                "trying to save the V4 ticket");
1127
 
        goto cleanup;
1128
 
    }
1129
 
 
1130
 
 cleanup:
1131
 
    memset(&v4creds, 0, sizeof(v4creds));
1132
 
    if (v5creds)
1133
 
        krb5_free_creds(k5->ctx, v5creds);
1134
 
    increds.client = 0;
1135
 
    krb5_free_cred_contents(k5->ctx, &increds);
1136
 
    if (kpcserver)
1137
 
        krb5_free_principal(k5->ctx, kpcserver);
1138
 
    return !(code || icode);
1139
 
}
1140
 
#endif /* HAVE_KRB524 */
1141
 
 
1142
702
int
1143
703
main(argc, argv)
1144
704
    int argc;
1146
706
{
1147
707
    struct k_opts opts;
1148
708
    struct k5_data k5;
1149
 
    struct k4_data k4;
1150
 
    char *progname;
1151
 
 
 
709
    int authed_k5 = 0;
1152
710
 
1153
711
    progname = GET_PROGNAME(argv[0]);
1154
 
    progname_v5 = getvprogname("5", progname);
1155
 
#ifdef KRB5_KRB4_COMPAT
1156
 
    progname_v4 = getvprogname("4", progname);
1157
 
    progname_v524 = getvprogname("524", progname);
1158
 
#endif
1159
712
 
1160
713
    /* Ensure we can be driven from a pipe */
1161
714
    if(!isatty(fileno(stdin)))
1165
718
    if(!isatty(fileno(stderr)))
1166
719
        setvbuf(stderr, 0, _IONBF, 0);
1167
720
 
1168
 
    /*
1169
 
      This is where we would put in code to dynamically load Kerberos
1170
 
      libraries.  Currenlty, we just get them implicitly.
1171
 
    */
1172
 
    got_k5 = 1;
1173
 
#ifdef KRB5_KRB4_COMPAT
1174
 
    got_k4 = 1;
1175
 
#endif
1176
 
 
1177
721
    memset(&opts, 0, sizeof(opts));
1178
722
    opts.action = INIT_PW;
1179
723
 
1180
724
    memset(&k5, 0, sizeof(k5));
1181
 
    memset(&k4, 0, sizeof(k4));
1182
725
 
1183
726
    set_com_err_hook (extended_com_err_fn);
1184
727
 
1185
 
    parse_options(argc, argv, &opts, progname);
1186
 
 
1187
 
    got_k5 = k5_begin(&opts, &k5, &k4);
1188
 
    got_k4 = k4_begin(&opts, &k4);
1189
 
 
1190
 
    authed_k5 = k5_kinit(&opts, &k5);
1191
 
#ifdef HAVE_KRB524
1192
 
    if (authed_k5)
1193
 
        authed_k4 = try_convert524(&k5);
1194
 
#endif
1195
 
    if (!authed_k4)
1196
 
        authed_k4 = k4_kinit(&opts, &k4, k5.ctx);
1197
 
#ifdef KRB5_KRB4_COMPAT
1198
 
    memset(stash_password, 0, sizeof(stash_password));
1199
 
#endif
 
728
    parse_options(argc, argv, &opts);
 
729
 
 
730
    if (k5_begin(&opts, &k5))
 
731
        authed_k5 = k5_kinit(&opts, &k5);
1200
732
 
1201
733
    if (authed_k5 && opts.verbose)
1202
734
        fprintf(stderr, "Authenticated to Kerberos v5\n");
1203
 
    if (authed_k4 && opts.verbose)
1204
 
        fprintf(stderr, "Authenticated to Kerberos v4\n");
1205
735
 
1206
736
    k5_end(&k5);
1207
 
    k4_end(&k4);
1208
737
 
1209
 
    if ((got_k5 && !authed_k5) || (got_k4 && !authed_k4) ||
1210
 
        (!got_k5 && !got_k4))
 
738
    if (!authed_k5)
1211
739
        exit(1);
1212
740
    return 0;
1213
741
}