~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/kuser/kinit.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan
 
3
 * (Royal Institute of Technology, Stockholm, Sweden).
 
4
 * All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 *
 
10
 * 1. Redistributions of source code must retain the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer.
 
12
 *
 
13
 * 2. Redistributions in binary form must reproduce the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer in the
 
15
 *    documentation and/or other materials provided with the distribution.
 
16
 *
 
17
 * 3. Neither the name of the Institute nor the names of its contributors
 
18
 *    may be used to endorse or promote products derived from this software
 
19
 *    without specific prior written permission.
 
20
 *
 
21
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
31
 * SUCH DAMAGE.
 
32
 */
 
33
 
 
34
#include "kuser_locl.h"
 
35
RCSID("$Id$");
 
36
 
 
37
#include "krb5-v4compat.h"
 
38
 
 
39
#include "heimntlm.h"
 
40
 
 
41
int forwardable_flag    = -1;
 
42
int proxiable_flag      = -1;
 
43
int renewable_flag      = -1;
 
44
int renew_flag          = 0;
 
45
int pac_flag            = -1;
 
46
int validate_flag       = 0;
 
47
int version_flag        = 0;
 
48
int help_flag           = 0;
 
49
int addrs_flag          = -1;
 
50
struct getarg_strings extra_addresses;
 
51
int anonymous_flag      = 0;
 
52
char *lifetime          = NULL;
 
53
char *renew_life        = NULL;
 
54
char *server_str        = NULL;
 
55
char *cred_cache        = NULL;
 
56
char *start_str         = NULL;
 
57
struct getarg_strings etype_str;
 
58
int use_keytab          = 0;
 
59
char *keytab_str        = NULL;
 
60
int do_afslog           = -1;
 
61
#ifndef HEIMDAL_SMALLER
 
62
int get_v4_tgt          = -1;
 
63
int convert_524         = 0;
 
64
static char *krb4_cc_name;
 
65
#endif
 
66
int fcache_version;
 
67
char *password_file     = NULL;
 
68
char *pk_user_id        = NULL;
 
69
char *pk_x509_anchors   = NULL;
 
70
int pk_use_enckey       = 0;
 
71
static int canonicalize_flag = 0;
 
72
static int ok_as_delegate_flag = 0;
 
73
static int use_referrals_flag = 0;
 
74
static int windows_flag = 0;
 
75
static char *ntlm_domain;
 
76
 
 
77
 
 
78
static struct getargs args[] = {
 
79
    /*
 
80
     * used by MIT
 
81
     * a: ~A
 
82
     * V: verbose
 
83
     * F: ~f
 
84
     * P: ~p
 
85
     * C: v4 cache name?
 
86
     * 5:
 
87
     */
 
88
#ifndef HEIMDAL_SMALLER
 
89
    { "524init",        '4', arg_flag, &get_v4_tgt,
 
90
      NP_("obtain version 4 TGT", "") },
 
91
 
 
92
    { "524convert",     '9', arg_flag, &convert_524,
 
93
      NP_("only convert ticket to version 4", "") },
 
94
#endif
 
95
    { "afslog",         0  , arg_flag, &do_afslog,
 
96
      NP_("obtain afs tokens", "")  },
 
97
 
 
98
    { "cache",          'c', arg_string, &cred_cache,
 
99
      NP_("credentials cache", ""), "cachename" },
 
100
 
 
101
    { "forwardable",    'f', arg_flag, &forwardable_flag,
 
102
      NP_("get forwardable tickets", "")},
 
103
 
 
104
    { "keytab",         't', arg_string, &keytab_str,
 
105
      NP_("keytab to use", ""), "keytabname" },
 
106
 
 
107
    { "lifetime",       'l', arg_string, &lifetime,
 
108
      NP_("lifetime of tickets", ""), "time"},
 
109
 
 
110
    { "proxiable",      'p', arg_flag, &proxiable_flag,
 
111
      NP_("get proxiable tickets", "") },
 
112
 
 
113
    { "renew",          'R', arg_flag, &renew_flag,
 
114
      NP_("renew TGT", "") },
 
115
 
 
116
    { "renewable",      0,   arg_flag, &renewable_flag,
 
117
      NP_("get renewable tickets", "") },
 
118
 
 
119
    { "renewable-life", 'r', arg_string, &renew_life,
 
120
      NP_("renewable lifetime of tickets", ""), "time" },
 
121
 
 
122
    { "server",         'S', arg_string, &server_str,
 
123
      NP_("server to get ticket for", ""), "principal" },
 
124
 
 
125
    { "start-time",     's', arg_string, &start_str,
 
126
      NP_("when ticket gets valid", ""), "time" },
 
127
 
 
128
    { "use-keytab",     'k', arg_flag, &use_keytab,
 
129
      NP_("get key from keytab", "") },
 
130
 
 
131
    { "validate",       'v', arg_flag, &validate_flag,
 
132
      NP_("validate TGT", "") },
 
133
 
 
134
    { "enctypes",       'e', arg_strings, &etype_str,
 
135
      NP_("encryption types to use", ""), "enctypes" },
 
136
 
 
137
    { "fcache-version", 0,   arg_integer, &fcache_version,
 
138
      NP_("file cache version to create", "") },
 
139
 
 
140
    { "addresses",      'A',   arg_negative_flag,       &addrs_flag,
 
141
      NP_("request a ticket with no addresses", "") },
 
142
 
 
143
    { "extra-addresses",'a', arg_strings,       &extra_addresses,
 
144
      NP_("include these extra addresses", ""), "addresses" },
 
145
 
 
146
    { "anonymous",      0,   arg_flag,  &anonymous_flag,
 
147
      NP_("request an anonymous ticket", "") },
 
148
 
 
149
    { "request-pac",    0,   arg_flag,  &pac_flag,
 
150
      NP_("request a Windows PAC", "") },
 
151
 
 
152
    { "password-file",  0,   arg_string, &password_file,
 
153
      NP_("read the password from a file", "") },
 
154
 
 
155
    { "canonicalize",0,   arg_flag, &canonicalize_flag,
 
156
      NP_("canonicalize client principal", "") },
 
157
#ifdef PKINIT
 
158
    { "pk-user",        'C',    arg_string,     &pk_user_id,
 
159
      NP_("principal's public/private/certificate identifier", ""), "id" },
 
160
 
 
161
    { "x509-anchors",   'D',  arg_string, &pk_x509_anchors,
 
162
      NP_("directory with CA certificates", ""), "directory" },
 
163
 
 
164
    { "pk-use-enckey",  0,  arg_flag, &pk_use_enckey,
 
165
      NP_("Use RSA encrypted reply (instead of DH)", "") },
 
166
#endif
 
167
    { "ntlm-domain",    0,  arg_string, &ntlm_domain,
 
168
      NP_("NTLM domain", ""), "domain" },
 
169
 
 
170
    { "ok-as-delegate", 0,  arg_flag, &ok_as_delegate_flag,
 
171
      NP_("honor ok-as-delegate on tickets", "") },
 
172
 
 
173
    { "use-referrals",  0,  arg_flag, &use_referrals_flag,
 
174
      NP_("only use referrals, no dns canalisation", "") },
 
175
 
 
176
    { "windows",        0,  arg_flag, &windows_flag,
 
177
      NP_("get windows behavior", "") },
 
178
 
 
179
    { "version",        0,   arg_flag, &version_flag },
 
180
    { "help",           0,   arg_flag, &help_flag }
 
181
};
 
182
 
 
183
static void
 
184
usage (int ret)
 
185
{
 
186
    arg_printusage_i18n (args,
 
187
                         sizeof(args)/sizeof(*args),
 
188
                         N_("Usage: ", ""),
 
189
                         NULL,
 
190
                         "[principal [command]]",
 
191
                         getarg_i18n);
 
192
    exit (ret);
 
193
}
 
194
 
 
195
static krb5_error_code
 
196
get_server(krb5_context context,
 
197
           krb5_principal client,
 
198
           const char *server,
 
199
           krb5_principal *princ)
 
200
{
 
201
    krb5_realm *client_realm;
 
202
    if(server)
 
203
        return krb5_parse_name(context, server, princ);
 
204
 
 
205
    client_realm = krb5_princ_realm (context, client);
 
206
    return krb5_make_principal(context, princ, *client_realm,
 
207
                               KRB5_TGS_NAME, *client_realm, NULL);
 
208
}
 
209
 
 
210
#ifndef HEIMDAL_SMALLER
 
211
 
 
212
static krb5_error_code
 
213
do_524init(krb5_context context, krb5_ccache ccache,
 
214
           krb5_creds *creds, const char *server)
 
215
{
 
216
    krb5_error_code ret;
 
217
 
 
218
    struct credentials c;
 
219
    krb5_creds in_creds, *real_creds;
 
220
 
 
221
    if(creds != NULL)
 
222
        real_creds = creds;
 
223
    else {
 
224
        krb5_principal client;
 
225
        krb5_cc_get_principal(context, ccache, &client);
 
226
        memset(&in_creds, 0, sizeof(in_creds));
 
227
        ret = get_server(context, client, server, &in_creds.server);
 
228
        if(ret) {
 
229
            krb5_free_principal(context, client);
 
230
            return ret;
 
231
        }
 
232
        in_creds.client = client;
 
233
        ret = krb5_get_credentials(context, 0, ccache, &in_creds, &real_creds);
 
234
        krb5_free_principal(context, client);
 
235
        krb5_free_principal(context, in_creds.server);
 
236
        if(ret)
 
237
            return ret;
 
238
    }
 
239
    ret = krb524_convert_creds_kdc_ccache(context, ccache, real_creds, &c);
 
240
    if(ret)
 
241
        krb5_warn(context, ret, "converting creds");
 
242
    else {
 
243
        krb5_error_code tret = _krb5_krb_tf_setup(context, &c, NULL, 0);
 
244
        if(tret)
 
245
            krb5_warn(context, tret, "saving v4 creds");
 
246
    }
 
247
 
 
248
    if(creds == NULL)
 
249
        krb5_free_creds(context, real_creds);
 
250
    memset(&c, 0, sizeof(c));
 
251
 
 
252
    return ret;
 
253
}
 
254
 
 
255
#endif
 
256
 
 
257
static int
 
258
renew_validate(krb5_context context,
 
259
               int renew,
 
260
               int validate,
 
261
               krb5_ccache cache,
 
262
               const char *server,
 
263
               krb5_deltat life)
 
264
{
 
265
    krb5_error_code ret;
 
266
    krb5_creds in, *out = NULL;
 
267
    krb5_kdc_flags flags;
 
268
 
 
269
    memset(&in, 0, sizeof(in));
 
270
 
 
271
    ret = krb5_cc_get_principal(context, cache, &in.client);
 
272
    if(ret) {
 
273
        krb5_warn(context, ret, "krb5_cc_get_principal");
 
274
        return ret;
 
275
    }
 
276
    ret = get_server(context, in.client, server, &in.server);
 
277
    if(ret) {
 
278
        krb5_warn(context, ret, "get_server");
 
279
        goto out;
 
280
    }
 
281
 
 
282
    if (renew) {
 
283
        /*
 
284
         * no need to check the error here, it's only to be
 
285
         * friendly to the user
 
286
         */
 
287
        krb5_get_credentials(context, KRB5_GC_CACHED, cache, &in, &out);
 
288
    }
 
289
 
 
290
    flags.i = 0;
 
291
    flags.b.renewable         = flags.b.renew = renew;
 
292
    flags.b.validate          = validate;
 
293
 
 
294
    if (forwardable_flag != -1)
 
295
        flags.b.forwardable       = forwardable_flag;
 
296
    else if (out)
 
297
        flags.b.forwardable       = out->flags.b.forwardable;
 
298
 
 
299
    if (proxiable_flag != -1)
 
300
        flags.b.proxiable         = proxiable_flag;
 
301
    else if (out)
 
302
        flags.b.proxiable         = out->flags.b.proxiable;
 
303
 
 
304
    if (anonymous_flag != -1)
 
305
        flags.b.request_anonymous = anonymous_flag;
 
306
    if(life)
 
307
        in.times.endtime = time(NULL) + life;
 
308
 
 
309
    if (out) {
 
310
        krb5_free_creds (context, out);
 
311
        out = NULL;
 
312
    }
 
313
 
 
314
 
 
315
    ret = krb5_get_kdc_cred(context,
 
316
                            cache,
 
317
                            flags,
 
318
                            NULL,
 
319
                            NULL,
 
320
                            &in,
 
321
                            &out);
 
322
    if(ret) {
 
323
        krb5_warn(context, ret, "krb5_get_kdc_cred");
 
324
        goto out;
 
325
    }
 
326
    ret = krb5_cc_initialize(context, cache, in.client);
 
327
    if(ret) {
 
328
        krb5_free_creds (context, out);
 
329
        krb5_warn(context, ret, "krb5_cc_initialize");
 
330
        goto out;
 
331
    }
 
332
    ret = krb5_cc_store_cred(context, cache, out);
 
333
 
 
334
    if(ret == 0 && server == NULL) {
 
335
        /* only do this if it's a general renew-my-tgt request */
 
336
#ifndef HEIMDAL_SMALLER
 
337
        if(get_v4_tgt)
 
338
            do_524init(context, cache, out, NULL);
 
339
#endif
 
340
        if(do_afslog && k_hasafs())
 
341
            krb5_afslog(context, cache, NULL, NULL);
 
342
    }
 
343
 
 
344
    krb5_free_creds (context, out);
 
345
    if(ret) {
 
346
        krb5_warn(context, ret, "krb5_cc_store_cred");
 
347
        goto out;
 
348
    }
 
349
out:
 
350
    krb5_free_cred_contents(context, &in);
 
351
    return ret;
 
352
}
 
353
 
 
354
static krb5_error_code
 
355
store_ntlmkey(krb5_context context, krb5_ccache id,
 
356
              const char *domain, struct ntlm_buf *buf)
 
357
{
 
358
    krb5_error_code ret;
 
359
    krb5_data data;
 
360
    char *name;
 
361
 
 
362
    asprintf(&name, "ntlm-key-%s", domain);
 
363
    if (name == NULL) {
 
364
        krb5_clear_error_message(context);
 
365
        return ENOMEM;
 
366
    }
 
367
 
 
368
    data.length = buf->length;
 
369
    data.data = buf->data;
 
370
 
 
371
    ret = krb5_cc_set_config(context, id, NULL, name, &data);
 
372
    free(name);
 
373
    return ret;
 
374
}
 
375
 
 
376
static krb5_error_code
 
377
get_new_tickets(krb5_context context,
 
378
                krb5_principal principal,
 
379
                krb5_ccache ccache,
 
380
                krb5_deltat ticket_life,
 
381
                int interactive)
 
382
{
 
383
    krb5_error_code ret;
 
384
    krb5_get_init_creds_opt *opt;
 
385
    krb5_creds cred;
 
386
    char passwd[256];
 
387
    krb5_deltat start_time = 0;
 
388
    krb5_deltat renew = 0;
 
389
    char *renewstr = NULL;
 
390
    krb5_enctype *enctype = NULL;
 
391
    struct ntlm_buf ntlmkey;
 
392
    krb5_ccache tempccache;
 
393
 
 
394
    memset(&ntlmkey, 0, sizeof(ntlmkey));
 
395
    passwd[0] = '\0';
 
396
 
 
397
    if (password_file) {
 
398
        FILE *f;
 
399
 
 
400
        if (strcasecmp("STDIN", password_file) == 0)
 
401
            f = stdin;
 
402
        else
 
403
            f = fopen(password_file, "r");
 
404
        if (f == NULL)
 
405
            krb5_errx(context, 1, "Failed to open the password file %s",
 
406
                      password_file);
 
407
 
 
408
        if (fgets(passwd, sizeof(passwd), f) == NULL)
 
409
            krb5_errx(context, 1,
 
410
                      N_("Failed to read password from file %s", ""),
 
411
                      password_file);
 
412
        if (f != stdin)
 
413
            fclose(f);
 
414
        passwd[strcspn(passwd, "\n")] = '\0';
 
415
    }
 
416
 
 
417
 
 
418
    memset(&cred, 0, sizeof(cred));
 
419
 
 
420
    ret = krb5_get_init_creds_opt_alloc (context, &opt);
 
421
    if (ret)
 
422
        krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
 
423
 
 
424
    krb5_get_init_creds_opt_set_default_flags(context, "kinit",
 
425
        krb5_principal_get_realm(context, principal), opt);
 
426
 
 
427
    if(forwardable_flag != -1)
 
428
        krb5_get_init_creds_opt_set_forwardable (opt, forwardable_flag);
 
429
    if(proxiable_flag != -1)
 
430
        krb5_get_init_creds_opt_set_proxiable (opt, proxiable_flag);
 
431
    if(anonymous_flag != -1)
 
432
        krb5_get_init_creds_opt_set_anonymous (opt, anonymous_flag);
 
433
    if (pac_flag != -1)
 
434
        krb5_get_init_creds_opt_set_pac_request(context, opt,
 
435
                                                pac_flag ? TRUE : FALSE);
 
436
    if (canonicalize_flag)
 
437
        krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE);
 
438
    if (pk_user_id) {
 
439
        ret = krb5_get_init_creds_opt_set_pkinit(context, opt,
 
440
                                                 principal,
 
441
                                                 pk_user_id,
 
442
                                                 pk_x509_anchors,
 
443
                                                 NULL,
 
444
                                                 NULL,
 
445
                                                 pk_use_enckey ? 2 : 0,
 
446
                                                 krb5_prompter_posix,
 
447
                                                 NULL,
 
448
                                                 passwd);
 
449
        if (ret)
 
450
            krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_pkinit");
 
451
    }
 
452
 
 
453
    if (addrs_flag != -1)
 
454
        krb5_get_init_creds_opt_set_addressless(context, opt,
 
455
                                                addrs_flag ? FALSE : TRUE);
 
456
 
 
457
    if (renew_life == NULL && renewable_flag)
 
458
        renewstr = "1 month";
 
459
    if (renew_life)
 
460
        renewstr = renew_life;
 
461
    if (renewstr) {
 
462
        renew = parse_time (renewstr, "s");
 
463
        if (renew < 0)
 
464
            errx (1, "unparsable time: %s", renewstr);
 
465
        
 
466
        krb5_get_init_creds_opt_set_renew_life (opt, renew);
 
467
    }
 
468
 
 
469
    if(ticket_life != 0)
 
470
        krb5_get_init_creds_opt_set_tkt_life (opt, ticket_life);
 
471
 
 
472
    if(start_str) {
 
473
        int tmp = parse_time (start_str, "s");
 
474
        if (tmp < 0)
 
475
            errx (1, N_("unparsable time: %s", ""), start_str);
 
476
 
 
477
        start_time = tmp;
 
478
    }
 
479
 
 
480
    if(etype_str.num_strings) {
 
481
        int i;
 
482
 
 
483
        enctype = malloc(etype_str.num_strings * sizeof(*enctype));
 
484
        if(enctype == NULL)
 
485
            errx(1, "out of memory");
 
486
        for(i = 0; i < etype_str.num_strings; i++) {
 
487
            ret = krb5_string_to_enctype(context,
 
488
                                         etype_str.strings[i],
 
489
                                         &enctype[i]);
 
490
            if(ret)
 
491
                errx(1, "unrecognized enctype: %s", etype_str.strings[i]);
 
492
        }
 
493
        krb5_get_init_creds_opt_set_etype_list(opt, enctype,
 
494
                                               etype_str.num_strings);
 
495
    }
 
496
 
 
497
    if(use_keytab || keytab_str) {
 
498
        krb5_keytab kt;
 
499
        if(keytab_str)
 
500
            ret = krb5_kt_resolve(context, keytab_str, &kt);
 
501
        else
 
502
            ret = krb5_kt_default(context, &kt);
 
503
        if (ret)
 
504
            krb5_err (context, 1, ret, "resolving keytab");
 
505
        ret = krb5_get_init_creds_keytab (context,
 
506
                                          &cred,
 
507
                                          principal,
 
508
                                          kt,
 
509
                                          start_time,
 
510
                                          server_str,
 
511
                                          opt);
 
512
        krb5_kt_close(context, kt);
 
513
    } else if (pk_user_id) {
 
514
        ret = krb5_get_init_creds_password (context,
 
515
                                            &cred,
 
516
                                            principal,
 
517
                                            passwd,
 
518
                                            krb5_prompter_posix,
 
519
                                            NULL,
 
520
                                            start_time,
 
521
                                            server_str,
 
522
                                            opt);
 
523
    } else if (!interactive) {
 
524
        krb5_warnx(context, "Not interactive, failed to get initial ticket");
 
525
        krb5_get_init_creds_opt_free(context, opt);
 
526
        return 0;
 
527
    } else {
 
528
 
 
529
        if (passwd[0] == '\0') {
 
530
            char *p, *prompt;
 
531
        
 
532
            krb5_unparse_name (context, principal, &p);
 
533
            asprintf (&prompt, N_("%s's Password: ", ""), p);
 
534
            free (p);
 
535
        
 
536
            if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){
 
537
                memset(passwd, 0, sizeof(passwd));
 
538
                exit(1);
 
539
            }
 
540
            free (prompt);
 
541
        }
 
542
 
 
543
        
 
544
        ret = krb5_get_init_creds_password (context,
 
545
                                            &cred,
 
546
                                            principal,
 
547
                                            passwd,
 
548
                                            krb5_prompter_posix,
 
549
                                            NULL,
 
550
                                            start_time,
 
551
                                            server_str,
 
552
                                            opt);
 
553
    }
 
554
    krb5_get_init_creds_opt_free(context, opt);
 
555
    if (ntlm_domain && passwd[0])
 
556
        heim_ntlm_nt_key(passwd, &ntlmkey);
 
557
    memset(passwd, 0, sizeof(passwd));
 
558
 
 
559
    switch(ret){
 
560
    case 0:
 
561
        break;
 
562
    case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */
 
563
        exit(1);
 
564
    case KRB5KRB_AP_ERR_BAD_INTEGRITY:
 
565
    case KRB5KRB_AP_ERR_MODIFIED:
 
566
    case KRB5KDC_ERR_PREAUTH_FAILED:
 
567
        krb5_errx(context, 1, N_("Password incorrect", ""));
 
568
        break;
 
569
    case KRB5KRB_AP_ERR_V4_REPLY:
 
570
        krb5_errx(context, 1, N_("Looks like a Kerberos 4 reply", ""));
 
571
        break;
 
572
    default:
 
573
        krb5_err(context, 1, ret, "krb5_get_init_creds");
 
574
    }
 
575
 
 
576
    if(ticket_life != 0) {
 
577
        if(abs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) {
 
578
            char life[64];
 
579
            unparse_time_approx(cred.times.endtime - cred.times.starttime,
 
580
                                life, sizeof(life));
 
581
            krb5_warnx(context, N_("NOTICE: ticket lifetime is %s", ""), life);
 
582
        }
 
583
    }
 
584
    if(renew_life) {
 
585
        if(abs(cred.times.renew_till - cred.times.starttime - renew) > 30) {
 
586
            char life[64];
 
587
            unparse_time_approx(cred.times.renew_till - cred.times.starttime,
 
588
                                life, sizeof(life));
 
589
            krb5_warnx(context, 
 
590
                       N_("NOTICE: ticket renewable lifetime is %s", ""),
 
591
                       life);
 
592
        }
 
593
    }
 
594
 
 
595
    ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache),
 
596
                             NULL, &tempccache);
 
597
    if (ret)
 
598
        krb5_err (context, 1, ret, "krb5_cc_new_unique");
 
599
 
 
600
    ret = krb5_cc_initialize (context, tempccache, cred.client);
 
601
    if (ret)
 
602
        krb5_err (context, 1, ret, "krb5_cc_initialize");
 
603
 
 
604
    ret = krb5_cc_store_cred (context, tempccache, &cred);
 
605
    if (ret)
 
606
        krb5_err (context, 1, ret, "krb5_cc_store_cred");
 
607
 
 
608
    krb5_free_cred_contents (context, &cred);
 
609
 
 
610
    ret = krb5_cc_move(context, tempccache, ccache);
 
611
    if (ret)
 
612
        krb5_err (context, 1, ret, "krb5_cc_move");
 
613
 
 
614
    if (ntlm_domain && ntlmkey.data)
 
615
        store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey);
 
616
 
 
617
    if (ok_as_delegate_flag || windows_flag || use_referrals_flag) {
 
618
        unsigned char d = 0;
 
619
        krb5_data data;
 
620
 
 
621
        if (ok_as_delegate_flag || windows_flag)
 
622
            d |= 1;
 
623
        if (use_referrals_flag || windows_flag)
 
624
            d |= 2;
 
625
 
 
626
        data.length = 1;
 
627
        data.data = &d;
 
628
 
 
629
        krb5_cc_set_config(context, ccache, NULL, "realm-config", &data);
 
630
    }
 
631
 
 
632
 
 
633
    if (enctype)
 
634
        free(enctype);
 
635
 
 
636
    return 0;
 
637
}
 
638
 
 
639
static time_t
 
640
ticket_lifetime(krb5_context context, krb5_ccache cache,
 
641
                krb5_principal client, const char *server)
 
642
{
 
643
    krb5_creds in_cred, *cred;
 
644
    krb5_error_code ret;
 
645
    time_t timeout;
 
646
 
 
647
    memset(&in_cred, 0, sizeof(in_cred));
 
648
 
 
649
    ret = krb5_cc_get_principal(context, cache, &in_cred.client);
 
650
    if(ret) {
 
651
        krb5_warn(context, ret, "krb5_cc_get_principal");
 
652
        return 0;
 
653
    }
 
654
    ret = get_server(context, in_cred.client, server, &in_cred.server);
 
655
    if(ret) {
 
656
        krb5_free_principal(context, in_cred.client);
 
657
        krb5_warn(context, ret, "get_server");
 
658
        return 0;
 
659
    }
 
660
 
 
661
    ret = krb5_get_credentials(context, KRB5_GC_CACHED,
 
662
                               cache, &in_cred, &cred);
 
663
    krb5_free_principal(context, in_cred.client);
 
664
    krb5_free_principal(context, in_cred.server);
 
665
    if(ret) {
 
666
        krb5_warn(context, ret, "krb5_get_credentials");
 
667
        return 0;
 
668
    }
 
669
    timeout = cred->times.endtime - cred->times.starttime;
 
670
    if (timeout < 0)
 
671
        timeout = 0;
 
672
    krb5_free_creds(context, cred);
 
673
    return timeout;
 
674
}
 
675
 
 
676
struct renew_ctx {
 
677
    krb5_context context;
 
678
    krb5_ccache  ccache;
 
679
    krb5_principal principal;
 
680
    krb5_deltat ticket_life;
 
681
};
 
682
 
 
683
static time_t
 
684
renew_func(void *ptr)
 
685
{
 
686
    struct renew_ctx *ctx = ptr;
 
687
    krb5_error_code ret;
 
688
    time_t expire;
 
689
    int new_tickets = 0;
 
690
 
 
691
    if (renewable_flag) {
 
692
        ret = renew_validate(ctx->context, renewable_flag, validate_flag,
 
693
                             ctx->ccache, server_str, ctx->ticket_life);
 
694
        if (ret)
 
695
            new_tickets = 1;
 
696
    } else
 
697
        new_tickets = 1;
 
698
 
 
699
    if (new_tickets)
 
700
        get_new_tickets(ctx->context, ctx->principal,
 
701
                        ctx->ccache, ctx->ticket_life, 0);
 
702
 
 
703
#ifndef HEIMDAL_SMALLER
 
704
    if(get_v4_tgt || convert_524)
 
705
        do_524init(ctx->context, ctx->ccache, NULL, server_str);
 
706
#endif
 
707
    if(do_afslog && k_hasafs())
 
708
        krb5_afslog(ctx->context, ctx->ccache, NULL, NULL);
 
709
 
 
710
    expire = ticket_lifetime(ctx->context, ctx->ccache, ctx->principal,
 
711
                             server_str) / 2;
 
712
    return expire + 1;
 
713
}
 
714
 
 
715
int
 
716
main (int argc, char **argv)
 
717
{
 
718
    krb5_error_code ret;
 
719
    krb5_context context;
 
720
    krb5_ccache  ccache;
 
721
    krb5_principal principal;
 
722
    int optidx = 0;
 
723
    krb5_deltat ticket_life = 0;
 
724
    int parseflags = 0;
 
725
 
 
726
    setprogname (argv[0]);
 
727
 
 
728
    setlocale (LC_ALL, "");
 
729
#if defined(HEIMDAL_LOCALEDIR)
 
730
    bindtextdomain ("heimdal_kuser", HEIMDAL_LOCALEDIR);
 
731
    textdomain("heimdal_kuser");
 
732
#endif
 
733
 
 
734
    ret = krb5_init_context (&context);
 
735
    if (ret == KRB5_CONFIG_BADFORMAT)
 
736
        errx (1, "krb5_init_context failed to parse configuration file");
 
737
    else if (ret)
 
738
        errx(1, "krb5_init_context failed: %d", ret);
 
739
 
 
740
    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
 
741
        usage(1);
 
742
 
 
743
    if (help_flag)
 
744
        usage (0);
 
745
 
 
746
    if(version_flag) {
 
747
        print_version(NULL);
 
748
        exit(0);
 
749
    }
 
750
 
 
751
    argc -= optidx;
 
752
    argv += optidx;
 
753
 
 
754
    if (canonicalize_flag)
 
755
        parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;
 
756
 
 
757
    if (argv[0]) {
 
758
        ret = krb5_parse_name_flags (context, argv[0], parseflags, &principal);
 
759
        if (ret)
 
760
            krb5_err (context, 1, ret, "krb5_parse_name");
 
761
    } else {
 
762
        ret = krb5_get_default_principal (context, &principal);
 
763
        if (ret)
 
764
            krb5_err (context, 1, ret, "krb5_get_default_principal");
 
765
    }
 
766
 
 
767
    if(fcache_version)
 
768
        krb5_set_fcache_version(context, fcache_version);
 
769
 
 
770
    if(renewable_flag == -1)
 
771
        /* this seems somewhat pointless, but whatever */
 
772
        krb5_appdefault_boolean(context, "kinit",
 
773
                                krb5_principal_get_realm(context, principal),
 
774
                                "renewable", FALSE, &renewable_flag);
 
775
#ifndef HEIMDAL_SMALLER
 
776
    if(get_v4_tgt == -1)
 
777
        krb5_appdefault_boolean(context, "kinit",
 
778
                                krb5_principal_get_realm(context, principal),
 
779
                                "krb4_get_tickets", FALSE, &get_v4_tgt);
 
780
#endif
 
781
    if(do_afslog == -1)
 
782
        krb5_appdefault_boolean(context, "kinit",
 
783
                                krb5_principal_get_realm(context, principal),
 
784
                                "afslog", TRUE, &do_afslog);
 
785
 
 
786
    if(cred_cache)
 
787
        ret = krb5_cc_resolve(context, cred_cache, &ccache);
 
788
    else {
 
789
        if(argc > 1) {
 
790
            char s[1024];
 
791
            ret = krb5_cc_gen_new(context, &krb5_fcc_ops, &ccache);
 
792
            if(ret)
 
793
                krb5_err(context, 1, ret, "creating cred cache");
 
794
            snprintf(s, sizeof(s), "%s:%s",
 
795
                     krb5_cc_get_type(context, ccache),
 
796
                     krb5_cc_get_name(context, ccache));
 
797
            setenv("KRB5CCNAME", s, 1);
 
798
#ifndef HEIMDAL_SMALLER
 
799
            if (get_v4_tgt) {
 
800
                int fd;
 
801
                if (asprintf(&krb4_cc_name, "%s_XXXXXX", TKT_ROOT) < 0)
 
802
                    krb5_errx(context, 1, "out of memory");
 
803
                if((fd = mkstemp(krb4_cc_name)) >= 0) {
 
804
                    close(fd);
 
805
                    setenv("KRBTKFILE", krb4_cc_name, 1);
 
806
                } else {
 
807
                    free(krb4_cc_name);
 
808
                    krb4_cc_name = NULL;
 
809
                }
 
810
            }
 
811
#endif
 
812
        } else {
 
813
            ret = krb5_cc_cache_match(context, principal, &ccache);
 
814
            if (ret)
 
815
                ret = krb5_cc_default (context, &ccache);
 
816
        }
 
817
    }
 
818
    if (ret)
 
819
        krb5_err (context, 1, ret, N_("resolving credentials cache", ""));
 
820
 
 
821
    if(argc > 1 && k_hasafs ())
 
822
        k_setpag();
 
823
 
 
824
    if (lifetime) {
 
825
        int tmp = parse_time (lifetime, "s");
 
826
        if (tmp < 0)
 
827
            errx (1, N_("unparsable time: %s", ""), lifetime);
 
828
 
 
829
        ticket_life = tmp;
 
830
    }
 
831
 
 
832
    if(addrs_flag == 0 && extra_addresses.num_strings > 0)
 
833
        krb5_errx(context, 1,
 
834
                  N_("specifying both extra addresses and "
 
835
                     "no addresses makes no sense", ""));
 
836
    {
 
837
        int i;
 
838
        krb5_addresses addresses;
 
839
        memset(&addresses, 0, sizeof(addresses));
 
840
        for(i = 0; i < extra_addresses.num_strings; i++) {
 
841
            ret = krb5_parse_address(context, extra_addresses.strings[i],
 
842
                                     &addresses);
 
843
            if (ret == 0) {
 
844
                krb5_add_extra_addresses(context, &addresses);
 
845
                krb5_free_addresses(context, &addresses);
 
846
            }
 
847
        }
 
848
        free_getarg_strings(&extra_addresses);
 
849
    }
 
850
 
 
851
    if(renew_flag || validate_flag) {
 
852
        ret = renew_validate(context, renew_flag, validate_flag,
 
853
                             ccache, server_str, ticket_life);
 
854
        exit(ret != 0);
 
855
    }
 
856
 
 
857
#ifndef HEIMDAL_SMALLER
 
858
    if(!convert_524)
 
859
#endif
 
860
        get_new_tickets(context, principal, ccache, ticket_life, 1);
 
861
 
 
862
#ifndef HEIMDAL_SMALLER
 
863
    if(get_v4_tgt || convert_524)
 
864
        do_524init(context, ccache, NULL, server_str);
 
865
#endif
 
866
    if(do_afslog && k_hasafs())
 
867
        krb5_afslog(context, ccache, NULL, NULL);
 
868
    if(argc > 1) {
 
869
        struct renew_ctx ctx;
 
870
        time_t timeout;
 
871
 
 
872
        timeout = ticket_lifetime(context, ccache, principal, server_str) / 2;
 
873
 
 
874
        ctx.context = context;
 
875
        ctx.ccache = ccache;
 
876
        ctx.principal = principal;
 
877
        ctx.ticket_life = ticket_life;
 
878
 
 
879
        ret = simple_execvp_timed(argv[1], argv+1,
 
880
                                  renew_func, &ctx, timeout);
 
881
#define EX_NOEXEC       126
 
882
#define EX_NOTFOUND     127
 
883
        if(ret == EX_NOEXEC)
 
884
            krb5_warnx(context, N_("permission denied: %s", ""), argv[1]);
 
885
        else if(ret == EX_NOTFOUND)
 
886
            krb5_warnx(context, N_("command not found: %s", ""), argv[1]);
 
887
        
 
888
        krb5_cc_destroy(context, ccache);
 
889
#ifndef HEIMDAL_SMALLER
 
890
        _krb5_krb_dest_tkt(context, krb4_cc_name);
 
891
#endif
 
892
        if(k_hasafs())
 
893
            k_unlog();
 
894
    } else {
 
895
        krb5_cc_close (context, ccache);
 
896
        ret = 0;
 
897
    }
 
898
    krb5_free_principal(context, principal);
 
899
    krb5_free_context (context);
 
900
    return ret;
 
901
}