Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/clients/kinit/kinit.c
34914 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* clients/kinit/kinit.c - Initialize a credential cache */
3
/*
4
* Copyright 1990, 2008 by the Massachusetts Institute of Technology.
5
* All Rights Reserved.
6
*
7
* Export of this software from the United States of America may
8
* require a specific license from the United States Government.
9
* It is the responsibility of any person or organization contemplating
10
* export to obtain such a license before exporting.
11
*
12
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13
* distribute this software and its documentation for any purpose and
14
* without fee is hereby granted, provided that the above copyright
15
* notice appear in all copies and that both that copyright notice and
16
* this permission notice appear in supporting documentation, and that
17
* the name of M.I.T. not be used in advertising or publicity pertaining
18
* to distribution of the software without specific, written prior
19
* permission. Furthermore if you modify this software you must label
20
* your software as modified software and not distribute it in such a
21
* fashion that it might be confused with the original M.I.T. software.
22
* M.I.T. makes no representations about the suitability of
23
* this software for any purpose. It is provided "as is" without express
24
* or implied warranty.
25
*/
26
27
#include "autoconf.h"
28
#include <k5-int.h>
29
#include "k5-platform.h" /* For asprintf and getopt */
30
#include <krb5.h>
31
#include "extern.h"
32
#include <locale.h>
33
#include <string.h>
34
#include <stdio.h>
35
#include <time.h>
36
#include <errno.h>
37
#include <com_err.h>
38
39
#ifndef _WIN32
40
#define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/') + 1 : (x))
41
#else
42
#define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x))
43
#endif
44
45
#ifdef HAVE_PWD_H
46
#include <pwd.h>
47
static char *
48
get_name_from_os(void)
49
{
50
struct passwd *pw;
51
52
pw = getpwuid(getuid());
53
return (pw != NULL) ? pw->pw_name : NULL;
54
}
55
#else /* HAVE_PWD_H */
56
#ifdef _WIN32
57
static char *
58
get_name_from_os(void)
59
{
60
static char name[1024];
61
DWORD name_size = sizeof(name);
62
63
if (GetUserName(name, &name_size)) {
64
name[sizeof(name) - 1] = '\0'; /* Just to be extra safe */
65
return name;
66
} else {
67
return NULL;
68
}
69
}
70
#else /* _WIN32 */
71
static char *
72
get_name_from_os(void)
73
{
74
return NULL;
75
}
76
#endif /* _WIN32 */
77
#endif /* HAVE_PWD_H */
78
79
static char *progname;
80
81
typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;
82
83
struct k_opts
84
{
85
/* In seconds */
86
krb5_deltat starttime;
87
krb5_deltat lifetime;
88
krb5_deltat rlife;
89
90
int forwardable;
91
int proxiable;
92
int request_pac;
93
int anonymous;
94
int addresses;
95
96
int not_forwardable;
97
int not_proxiable;
98
int not_request_pac;
99
int no_addresses;
100
101
int verbose;
102
103
char *principal_name;
104
char *service_name;
105
char *keytab_name;
106
char *k5_in_cache_name;
107
char *k5_out_cache_name;
108
char *armor_ccache;
109
110
action_type action;
111
int use_client_keytab;
112
113
int num_pa_opts;
114
krb5_gic_opt_pa_data *pa_opts;
115
116
int canonicalize;
117
int enterprise;
118
};
119
120
struct k5_data
121
{
122
krb5_context ctx;
123
krb5_ccache in_cc, out_cc;
124
krb5_principal me;
125
char *name;
126
krb5_boolean switch_to_cache;
127
};
128
129
/*
130
* If struct[2] == NULL, then long_getopt acts as if the short flag struct[3]
131
* were specified. If struct[2] != NULL, then struct[3] is stored in
132
* *(struct[2]), the array index which was specified is stored in *index, and
133
* long_getopt() returns 0.
134
*/
135
const char *shopts = "r:fpFPn54aAVl:s:c:kit:T:RS:vX:CEI:";
136
137
#define USAGE_BREAK "\n\t"
138
139
static void
140
usage(void)
141
{
142
fprintf(stderr,
143
_("Usage: %s [-V] [-l lifetime] [-s start_time] "
144
"[-r renewable_life]\n"
145
"\t[-f | -F] [-p | -P] [-n] [-a | -A] [-C] [-E]\n"
146
"\t[--request-pac | --no-request-pac]\n"
147
"\t[-v] [-R] [-k [-i|-t keytab_file]] [-c cachename]\n"
148
"\t[-S service_name] [-I input_ccache] [-T ticket_armor_cache]\n"
149
"\t[-X <attribute>[=<value>]] [principal]\n"
150
"\n"), progname);
151
152
fprintf(stderr, " options:\n");
153
fprintf(stderr, _("\t-V verbose\n"));
154
fprintf(stderr, _("\t-l lifetime\n"));
155
fprintf(stderr, _("\t-s start time\n"));
156
fprintf(stderr, _("\t-r renewable lifetime\n"));
157
fprintf(stderr, _("\t-f forwardable\n"));
158
fprintf(stderr, _("\t-F not forwardable\n"));
159
fprintf(stderr, _("\t-p proxiable\n"));
160
fprintf(stderr, _("\t-P not proxiable\n"));
161
fprintf(stderr, _("\t-n anonymous\n"));
162
fprintf(stderr, _("\t-a include addresses\n"));
163
fprintf(stderr, _("\t-A do not include addresses\n"));
164
fprintf(stderr, _("\t-v validate\n"));
165
fprintf(stderr, _("\t-R renew\n"));
166
fprintf(stderr, _("\t-C canonicalize\n"));
167
fprintf(stderr, _("\t-E client is enterprise principal name\n"));
168
fprintf(stderr, _("\t-k use keytab\n"));
169
fprintf(stderr, _("\t-i use default client keytab (with -k)\n"));
170
fprintf(stderr, _("\t-t filename of keytab to use\n"));
171
fprintf(stderr, _("\t-c Kerberos 5 cache name\n"));
172
fprintf(stderr, _("\t-S service\n"));
173
fprintf(stderr, _("\t-I input credential cache\n"));
174
fprintf(stderr, _("\t-T armor credential cache\n"));
175
fprintf(stderr, _("\t-X <attribute>[=<value>]\n"));
176
fprintf(stderr,
177
_("\t--{,no}-request-pac request KDC include/exclude a PAC\n"));
178
exit(2);
179
}
180
181
static krb5_context errctx;
182
static void
183
extended_com_err_fn(const char *myprog, errcode_t code, const char *fmt,
184
va_list args)
185
{
186
const char *emsg;
187
188
emsg = krb5_get_error_message(errctx, code);
189
fprintf(stderr, "%s: %s ", myprog, emsg);
190
krb5_free_error_message(errctx, emsg);
191
vfprintf(stderr, fmt, args);
192
fprintf(stderr, "\n");
193
}
194
195
static int
196
add_preauth_opt(struct k_opts *opts, char *av)
197
{
198
char *sep, *v;
199
krb5_gic_opt_pa_data *p, *x;
200
size_t newsize = (opts->num_pa_opts + 1) * sizeof(*opts->pa_opts);
201
202
x = realloc(opts->pa_opts, newsize);
203
if (x == NULL)
204
return ENOMEM;
205
opts->pa_opts = x;
206
207
p = &opts->pa_opts[opts->num_pa_opts];
208
sep = strchr(av, '=');
209
if (sep) {
210
*sep = '\0';
211
v = ++sep;
212
p->value = v;
213
} else {
214
p->value = "yes";
215
}
216
p->attr = av;
217
opts->num_pa_opts++;
218
return 0;
219
}
220
221
static char *
222
parse_options(int argc, char **argv, struct k_opts *opts)
223
{
224
struct option long_options[] = {
225
{ "noforwardable", 0, NULL, 'F' },
226
{ "noproxiable", 0, NULL, 'P' },
227
{ "addresses", 0, NULL, 'a'},
228
{ "forwardable", 0, NULL, 'f' },
229
{ "proxiable", 0, NULL, 'p' },
230
{ "noaddresses", 0, NULL, 'A' },
231
{ "canonicalize", 0, NULL, 'C' },
232
{ "enterprise", 0, NULL, 'E' },
233
{ "request-pac", 0, &opts->request_pac, 1 },
234
{ "no-request-pac", 0, &opts->not_request_pac, 1 },
235
{ NULL, 0, NULL, 0 }
236
};
237
krb5_error_code ret;
238
int errflg = 0;
239
int i;
240
241
while ((i = getopt_long(argc, argv, shopts, long_options, 0)) != -1) {
242
switch (i) {
243
case 'V':
244
opts->verbose = 1;
245
break;
246
case 'l':
247
/* Lifetime */
248
ret = krb5_string_to_deltat(optarg, &opts->lifetime);
249
if (ret || opts->lifetime == 0) {
250
fprintf(stderr, _("Bad lifetime value %s\n"), optarg);
251
errflg++;
252
}
253
break;
254
case 'r':
255
/* Renewable Time */
256
ret = krb5_string_to_deltat(optarg, &opts->rlife);
257
if (ret || opts->rlife == 0) {
258
fprintf(stderr, _("Bad lifetime value %s\n"), optarg);
259
errflg++;
260
}
261
break;
262
case 'f':
263
opts->forwardable = 1;
264
break;
265
case 'F':
266
opts->not_forwardable = 1;
267
break;
268
case 'p':
269
opts->proxiable = 1;
270
break;
271
case 'P':
272
opts->not_proxiable = 1;
273
break;
274
case 'n':
275
opts->anonymous = 1;
276
break;
277
case 'a':
278
opts->addresses = 1;
279
break;
280
case 'A':
281
opts->no_addresses = 1;
282
break;
283
case 's':
284
ret = krb5_string_to_deltat(optarg, &opts->starttime);
285
if (ret || opts->starttime == 0) {
286
/* Parse as an absolute time; intentionally undocumented
287
* but left for backwards compatibility. */
288
krb5_timestamp abs_starttime;
289
290
ret = krb5_string_to_timestamp(optarg, &abs_starttime);
291
if (ret || abs_starttime == 0) {
292
fprintf(stderr, _("Bad start time value %s\n"), optarg);
293
errflg++;
294
} else {
295
opts->starttime = ts_delta(abs_starttime, time(NULL));
296
}
297
}
298
break;
299
case 'S':
300
opts->service_name = optarg;
301
break;
302
case 'k':
303
opts->action = INIT_KT;
304
break;
305
case 'i':
306
opts->use_client_keytab = 1;
307
break;
308
case 't':
309
if (opts->keytab_name != NULL) {
310
fprintf(stderr, _("Only one -t option allowed.\n"));
311
errflg++;
312
} else {
313
opts->keytab_name = optarg;
314
}
315
break;
316
case 'T':
317
if (opts->armor_ccache != NULL) {
318
fprintf(stderr, _("Only one armor_ccache\n"));
319
errflg++;
320
} else {
321
opts->armor_ccache = optarg;
322
}
323
break;
324
case 'R':
325
opts->action = RENEW;
326
break;
327
case 'v':
328
opts->action = VALIDATE;
329
break;
330
case 'c':
331
if (opts->k5_out_cache_name != NULL) {
332
fprintf(stderr, _("Only one -c option allowed\n"));
333
errflg++;
334
} else {
335
opts->k5_out_cache_name = optarg;
336
}
337
break;
338
case 'I':
339
if (opts->k5_in_cache_name != NULL) {
340
fprintf(stderr, _("Only one -I option allowed\n"));
341
errflg++;
342
} else {
343
opts->k5_in_cache_name = optarg;
344
}
345
break;
346
case 'X':
347
ret = add_preauth_opt(opts, optarg);
348
if (ret) {
349
com_err(progname, ret, _("while adding preauth option"));
350
errflg++;
351
}
352
break;
353
case 'C':
354
opts->canonicalize = 1;
355
break;
356
case 'E':
357
opts->enterprise = 1;
358
break;
359
case '4':
360
fprintf(stderr, _("Kerberos 4 is no longer supported\n"));
361
exit(3);
362
break;
363
case '5':
364
break;
365
case 0:
366
/* If this option set a flag, do nothing else now. */
367
break;
368
default:
369
errflg++;
370
break;
371
}
372
}
373
374
if (opts->forwardable && opts->not_forwardable) {
375
fprintf(stderr, _("Only one of -f and -F allowed\n"));
376
errflg++;
377
}
378
if (opts->proxiable && opts->not_proxiable) {
379
fprintf(stderr, _("Only one of -p and -P allowed\n"));
380
errflg++;
381
}
382
if (opts->request_pac && opts->not_request_pac) {
383
fprintf(stderr, _("Only one of --request-pac and --no-request-pac "
384
"allowed\n"));
385
errflg++;
386
}
387
if (opts->addresses && opts->no_addresses) {
388
fprintf(stderr, _("Only one of -a and -A allowed\n"));
389
errflg++;
390
}
391
if (opts->keytab_name != NULL && opts->use_client_keytab == 1) {
392
fprintf(stderr, _("Only one of -t and -i allowed\n"));
393
errflg++;
394
}
395
if ((opts->keytab_name != NULL || opts->use_client_keytab == 1) &&
396
opts->action != INIT_KT) {
397
opts->action = INIT_KT;
398
fprintf(stderr, _("keytab specified, forcing -k\n"));
399
}
400
if (argc - optind > 1) {
401
fprintf(stderr, _("Extra arguments (starting with \"%s\").\n"),
402
argv[optind + 1]);
403
errflg++;
404
}
405
406
if (errflg)
407
usage();
408
409
opts->principal_name = (optind == argc - 1) ? argv[optind] : 0;
410
return opts->principal_name;
411
}
412
413
static int
414
k5_begin(struct k_opts *opts, struct k5_data *k5)
415
{
416
krb5_error_code ret;
417
int success = 0;
418
int flags = opts->enterprise ? KRB5_PRINCIPAL_PARSE_ENTERPRISE : 0;
419
krb5_ccache defcache = NULL;
420
krb5_principal defcache_princ = NULL, princ;
421
krb5_keytab keytab;
422
const char *deftype = NULL;
423
char *defrealm, *name;
424
425
ret = krb5_init_context(&k5->ctx);
426
if (ret) {
427
com_err(progname, ret, _("while initializing Kerberos 5 library"));
428
return 0;
429
}
430
errctx = k5->ctx;
431
432
if (opts->k5_out_cache_name) {
433
ret = krb5_cc_resolve(k5->ctx, opts->k5_out_cache_name, &k5->out_cc);
434
if (ret) {
435
com_err(progname, ret, _("resolving ccache %s"),
436
opts->k5_out_cache_name);
437
goto cleanup;
438
}
439
if (opts->verbose) {
440
fprintf(stderr, _("Using specified cache: %s\n"),
441
opts->k5_out_cache_name);
442
}
443
} else {
444
/* Resolve the default ccache and get its type and default principal
445
* (if it is initialized). */
446
ret = krb5_cc_default(k5->ctx, &defcache);
447
if (ret) {
448
com_err(progname, ret, _("while getting default ccache"));
449
goto cleanup;
450
}
451
deftype = krb5_cc_get_type(k5->ctx, defcache);
452
if (krb5_cc_get_principal(k5->ctx, defcache, &defcache_princ) != 0)
453
defcache_princ = NULL;
454
}
455
456
/* Choose a client principal name. */
457
if (opts->principal_name != NULL) {
458
/* Use the specified principal name. */
459
ret = krb5_parse_name_flags(k5->ctx, opts->principal_name, flags,
460
&k5->me);
461
if (ret) {
462
com_err(progname, ret, _("when parsing name %s"),
463
opts->principal_name);
464
goto cleanup;
465
}
466
} else if (opts->anonymous) {
467
/* Use the anonymous principal for the local realm. */
468
ret = krb5_get_default_realm(k5->ctx, &defrealm);
469
if (ret) {
470
com_err(progname, ret, _("while getting default realm"));
471
goto cleanup;
472
}
473
ret = krb5_build_principal_ext(k5->ctx, &k5->me,
474
strlen(defrealm), defrealm,
475
strlen(KRB5_WELLKNOWN_NAMESTR),
476
KRB5_WELLKNOWN_NAMESTR,
477
strlen(KRB5_ANONYMOUS_PRINCSTR),
478
KRB5_ANONYMOUS_PRINCSTR, 0);
479
krb5_free_default_realm(k5->ctx, defrealm);
480
if (ret) {
481
com_err(progname, ret, _("while building principal"));
482
goto cleanup;
483
}
484
} else if (opts->action == INIT_KT && opts->use_client_keytab) {
485
/* Use the first entry from the client keytab. */
486
ret = krb5_kt_client_default(k5->ctx, &keytab);
487
if (ret) {
488
com_err(progname, ret,
489
_("When resolving the default client keytab"));
490
goto cleanup;
491
}
492
ret = k5_kt_get_principal(k5->ctx, keytab, &k5->me);
493
krb5_kt_close(k5->ctx, keytab);
494
if (ret) {
495
com_err(progname, ret,
496
_("When determining client principal name from keytab"));
497
goto cleanup;
498
}
499
} else if (opts->action == INIT_KT) {
500
/* Use the default host/service name. */
501
ret = krb5_sname_to_principal(k5->ctx, NULL, NULL, KRB5_NT_SRV_HST,
502
&k5->me);
503
if (ret) {
504
com_err(progname, ret,
505
_("when creating default server principal name"));
506
goto cleanup;
507
}
508
} else if (k5->out_cc != NULL) {
509
/* If the output ccache is initialized, use its principal. */
510
if (krb5_cc_get_principal(k5->ctx, k5->out_cc, &princ) == 0)
511
k5->me = princ;
512
} else if (defcache_princ != NULL) {
513
/* Use the default cache's principal, and use the default cache as the
514
* output cache. */
515
k5->out_cc = defcache;
516
defcache = NULL;
517
k5->me = defcache_princ;
518
defcache_princ = NULL;
519
}
520
521
/* If we still haven't chosen, use the local username. */
522
if (k5->me == NULL) {
523
name = get_name_from_os();
524
if (name == NULL) {
525
fprintf(stderr, _("Unable to identify user\n"));
526
goto cleanup;
527
}
528
ret = krb5_parse_name_flags(k5->ctx, name, flags, &k5->me);
529
if (ret) {
530
com_err(progname, ret, _("when parsing name %s"), name);
531
goto cleanup;
532
}
533
}
534
535
if (k5->out_cc == NULL && krb5_cc_support_switch(k5->ctx, deftype)) {
536
/* Use an existing cache for the client principal if we can. */
537
ret = krb5_cc_cache_match(k5->ctx, k5->me, &k5->out_cc);
538
if (ret && ret != KRB5_CC_NOTFOUND) {
539
com_err(progname, ret, _("while searching for ccache for %s"),
540
opts->principal_name);
541
goto cleanup;
542
}
543
if (!ret) {
544
if (opts->verbose) {
545
fprintf(stderr, _("Using existing cache: %s\n"),
546
krb5_cc_get_name(k5->ctx, k5->out_cc));
547
}
548
k5->switch_to_cache = 1;
549
} else if (defcache_princ != NULL) {
550
/* Create a new cache to avoid overwriting the initialized default
551
* cache. */
552
ret = krb5_cc_new_unique(k5->ctx, deftype, NULL, &k5->out_cc);
553
if (ret) {
554
com_err(progname, ret, _("while generating new ccache"));
555
goto cleanup;
556
}
557
if (opts->verbose) {
558
fprintf(stderr, _("Using new cache: %s\n"),
559
krb5_cc_get_name(k5->ctx, k5->out_cc));
560
}
561
k5->switch_to_cache = 1;
562
}
563
}
564
565
/* Use the default cache if we haven't picked one yet. */
566
if (k5->out_cc == NULL) {
567
k5->out_cc = defcache;
568
defcache = NULL;
569
if (opts->verbose) {
570
fprintf(stderr, _("Using default cache: %s\n"),
571
krb5_cc_get_name(k5->ctx, k5->out_cc));
572
}
573
}
574
575
if (opts->k5_in_cache_name) {
576
ret = krb5_cc_resolve(k5->ctx, opts->k5_in_cache_name, &k5->in_cc);
577
if (ret) {
578
com_err(progname, ret, _("resolving ccache %s"),
579
opts->k5_in_cache_name);
580
goto cleanup;
581
}
582
if (opts->verbose) {
583
fprintf(stderr, _("Using specified input cache: %s\n"),
584
opts->k5_in_cache_name);
585
}
586
}
587
588
ret = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
589
if (ret) {
590
com_err(progname, ret, _("when unparsing name"));
591
goto cleanup;
592
}
593
if (opts->verbose)
594
fprintf(stderr, _("Using principal: %s\n"), k5->name);
595
596
opts->principal_name = k5->name;
597
598
success = 1;
599
600
cleanup:
601
if (defcache != NULL)
602
krb5_cc_close(k5->ctx, defcache);
603
krb5_free_principal(k5->ctx, defcache_princ);
604
return success;
605
}
606
607
static void
608
k5_end(struct k5_data *k5)
609
{
610
krb5_free_unparsed_name(k5->ctx, k5->name);
611
krb5_free_principal(k5->ctx, k5->me);
612
if (k5->in_cc != NULL)
613
krb5_cc_close(k5->ctx, k5->in_cc);
614
if (k5->out_cc != NULL)
615
krb5_cc_close(k5->ctx, k5->out_cc);
616
krb5_free_context(k5->ctx);
617
errctx = NULL;
618
memset(k5, 0, sizeof(*k5));
619
}
620
621
static krb5_error_code KRB5_CALLCONV
622
kinit_prompter(krb5_context ctx, void *data, const char *name,
623
const char *banner, int num_prompts, krb5_prompt prompts[])
624
{
625
krb5_boolean *pwprompt = data;
626
krb5_prompt_type *ptypes;
627
int i;
628
629
/* Make a note if we receive a password prompt. */
630
ptypes = krb5_get_prompt_types(ctx);
631
for (i = 0; i < num_prompts; i++) {
632
if (ptypes != NULL && ptypes[i] == KRB5_PROMPT_TYPE_PASSWORD)
633
*pwprompt = TRUE;
634
}
635
return krb5_prompter_posix(ctx, data, name, banner, num_prompts, prompts);
636
}
637
638
static int
639
k5_kinit(struct k_opts *opts, struct k5_data *k5)
640
{
641
int notix = 1;
642
krb5_keytab keytab = 0;
643
krb5_creds my_creds;
644
krb5_error_code ret;
645
krb5_get_init_creds_opt *options = NULL;
646
krb5_boolean pwprompt = FALSE;
647
krb5_address **addresses = NULL;
648
krb5_principal cprinc;
649
krb5_ccache mcc = NULL;
650
int i;
651
652
memset(&my_creds, 0, sizeof(my_creds));
653
654
ret = krb5_get_init_creds_opt_alloc(k5->ctx, &options);
655
if (ret)
656
goto cleanup;
657
658
if (opts->lifetime)
659
krb5_get_init_creds_opt_set_tkt_life(options, opts->lifetime);
660
if (opts->rlife)
661
krb5_get_init_creds_opt_set_renew_life(options, opts->rlife);
662
if (opts->forwardable)
663
krb5_get_init_creds_opt_set_forwardable(options, 1);
664
if (opts->not_forwardable)
665
krb5_get_init_creds_opt_set_forwardable(options, 0);
666
if (opts->proxiable)
667
krb5_get_init_creds_opt_set_proxiable(options, 1);
668
if (opts->not_proxiable)
669
krb5_get_init_creds_opt_set_proxiable(options, 0);
670
if (opts->canonicalize)
671
krb5_get_init_creds_opt_set_canonicalize(options, 1);
672
if (opts->anonymous)
673
krb5_get_init_creds_opt_set_anonymous(options, 1);
674
if (opts->addresses) {
675
ret = krb5_os_localaddr(k5->ctx, &addresses);
676
if (ret) {
677
com_err(progname, ret, _("getting local addresses"));
678
goto cleanup;
679
}
680
krb5_get_init_creds_opt_set_address_list(options, addresses);
681
}
682
if (opts->no_addresses)
683
krb5_get_init_creds_opt_set_address_list(options, NULL);
684
if (opts->armor_ccache != NULL) {
685
krb5_get_init_creds_opt_set_fast_ccache_name(k5->ctx, options,
686
opts->armor_ccache);
687
}
688
if (opts->request_pac)
689
krb5_get_init_creds_opt_set_pac_request(k5->ctx, options, TRUE);
690
if (opts->not_request_pac)
691
krb5_get_init_creds_opt_set_pac_request(k5->ctx, options, FALSE);
692
693
694
if (opts->action == INIT_KT && opts->keytab_name != NULL) {
695
#ifndef _WIN32
696
if (strncmp(opts->keytab_name, "KDB:", 4) == 0) {
697
ret = kinit_kdb_init(&k5->ctx, k5->me->realm.data);
698
errctx = k5->ctx;
699
if (ret) {
700
com_err(progname, ret,
701
_("while setting up KDB keytab for realm %s"),
702
k5->me->realm.data);
703
goto cleanup;
704
}
705
}
706
#endif
707
708
ret = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab);
709
if (ret) {
710
com_err(progname, ret, _("resolving keytab %s"),
711
opts->keytab_name);
712
goto cleanup;
713
}
714
if (opts->verbose)
715
fprintf(stderr, _("Using keytab: %s\n"), opts->keytab_name);
716
} else if (opts->action == INIT_KT && opts->use_client_keytab) {
717
ret = krb5_kt_client_default(k5->ctx, &keytab);
718
if (ret) {
719
com_err(progname, ret, _("resolving default client keytab"));
720
goto cleanup;
721
}
722
}
723
724
for (i = 0; i < opts->num_pa_opts; i++) {
725
ret = krb5_get_init_creds_opt_set_pa(k5->ctx, options,
726
opts->pa_opts[i].attr,
727
opts->pa_opts[i].value);
728
if (ret) {
729
com_err(progname, ret, _("while setting '%s'='%s'"),
730
opts->pa_opts[i].attr, opts->pa_opts[i].value);
731
goto cleanup;
732
}
733
if (opts->verbose) {
734
fprintf(stderr, _("PA Option %s = %s\n"), opts->pa_opts[i].attr,
735
opts->pa_opts[i].value);
736
}
737
}
738
if (k5->in_cc) {
739
ret = krb5_get_init_creds_opt_set_in_ccache(k5->ctx, options,
740
k5->in_cc);
741
if (ret)
742
goto cleanup;
743
}
744
ret = krb5_get_init_creds_opt_set_out_ccache(k5->ctx, options, k5->out_cc);
745
if (ret)
746
goto cleanup;
747
748
switch (opts->action) {
749
case INIT_PW:
750
ret = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, 0,
751
kinit_prompter, &pwprompt,
752
opts->starttime, opts->service_name,
753
options);
754
break;
755
case INIT_KT:
756
ret = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, keytab,
757
opts->starttime, opts->service_name,
758
options);
759
break;
760
case VALIDATE:
761
ret = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->out_cc,
762
opts->service_name);
763
break;
764
case RENEW:
765
ret = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->out_cc,
766
opts->service_name);
767
break;
768
}
769
770
if (ret) {
771
char *doing = NULL;
772
switch (opts->action) {
773
case INIT_PW:
774
case INIT_KT:
775
doing = _("getting initial credentials");
776
break;
777
case VALIDATE:
778
doing = _("validating credentials");
779
break;
780
case RENEW:
781
doing = _("renewing credentials");
782
break;
783
}
784
785
/* If reply decryption failed, or if pre-authentication failed and we
786
* were prompted for a password, assume the password was wrong. */
787
if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY ||
788
(pwprompt && ret == KRB5KDC_ERR_PREAUTH_FAILED)) {
789
fprintf(stderr, _("%s: Password incorrect while %s\n"), progname,
790
doing);
791
} else {
792
com_err(progname, ret, _("while %s"), doing);
793
}
794
goto cleanup;
795
}
796
797
if (opts->action != INIT_PW && opts->action != INIT_KT) {
798
cprinc = opts->canonicalize ? my_creds.client : k5->me;
799
ret = krb5_cc_new_unique(k5->ctx, "MEMORY", NULL, &mcc);
800
if (!ret)
801
ret = krb5_cc_initialize(k5->ctx, mcc, cprinc);
802
if (ret) {
803
com_err(progname, ret, _("when creating temporary cache"));
804
goto cleanup;
805
}
806
if (opts->verbose)
807
fprintf(stderr, _("Initialized cache\n"));
808
809
ret = k5_cc_store_primary_cred(k5->ctx, mcc, &my_creds);
810
if (ret) {
811
com_err(progname, ret, _("while storing credentials"));
812
goto cleanup;
813
}
814
ret = krb5_cc_move(k5->ctx, mcc, k5->out_cc);
815
if (ret) {
816
com_err(progname, ret, _("while saving to cache %s"),
817
opts->k5_out_cache_name ? opts->k5_out_cache_name : "");
818
goto cleanup;
819
}
820
mcc = NULL;
821
if (opts->verbose)
822
fprintf(stderr, _("Stored credentials\n"));
823
}
824
notix = 0;
825
if (k5->switch_to_cache) {
826
ret = krb5_cc_switch(k5->ctx, k5->out_cc);
827
if (ret) {
828
com_err(progname, ret, _("while switching to new ccache"));
829
goto cleanup;
830
}
831
}
832
833
cleanup:
834
#ifndef _WIN32
835
kinit_kdb_fini();
836
#endif
837
if (mcc != NULL)
838
krb5_cc_destroy(k5->ctx, mcc);
839
if (options)
840
krb5_get_init_creds_opt_free(k5->ctx, options);
841
if (my_creds.client == k5->me)
842
my_creds.client = 0;
843
if (opts->pa_opts) {
844
free(opts->pa_opts);
845
opts->pa_opts = NULL;
846
opts->num_pa_opts = 0;
847
}
848
krb5_free_cred_contents(k5->ctx, &my_creds);
849
if (keytab != NULL)
850
krb5_kt_close(k5->ctx, keytab);
851
return notix ? 0 : 1;
852
}
853
854
int
855
main(int argc, char *argv[])
856
{
857
struct k_opts opts;
858
struct k5_data k5;
859
int authed_k5 = 0;
860
861
setlocale(LC_ALL, "");
862
progname = GET_PROGNAME(argv[0]);
863
864
/* Ensure we can be driven from a pipe */
865
if (!isatty(fileno(stdin)))
866
setvbuf(stdin, 0, _IONBF, 0);
867
if (!isatty(fileno(stdout)))
868
setvbuf(stdout, 0, _IONBF, 0);
869
if (!isatty(fileno(stderr)))
870
setvbuf(stderr, 0, _IONBF, 0);
871
872
memset(&opts, 0, sizeof(opts));
873
opts.action = INIT_PW;
874
875
memset(&k5, 0, sizeof(k5));
876
877
set_com_err_hook(extended_com_err_fn);
878
879
parse_options(argc, argv, &opts);
880
881
if (k5_begin(&opts, &k5))
882
authed_k5 = k5_kinit(&opts, &k5);
883
884
if (authed_k5 && opts.verbose)
885
fprintf(stderr, _("Authenticated to Kerberos v5\n"));
886
887
k5_end(&k5);
888
889
if (!authed_k5)
890
exit(1);
891
return 0;
892
}
893
894