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