Krb5Credentials Krb5Keytab::getInitCreds( krb5_principal princ, krb5_get_init_creds_opt* opts) { krb5_creds creds; krb5_error_code code = krb5_get_init_creds_keytab( context_, &creds, princ, keytab_, 0 /* starttime */, nullptr /* initial sname */, opts); raiseIf(context_, code, "getting credentials from keytab"); return Krb5Credentials(std::move(creds)); }
/* Similar to krb5_get_in_tkt_with_password. Attempts to get an initial ticket for creds->client to use server creds->server, (realm is taken from creds->client), with options options, and using creds->times.starttime, creds->times.endtime, creds->times.renew_till as from, till, and rtime. creds->times.renew_till is ignored unless the RENEWABLE option is requested. If addrs is non-NULL, it is used for the addresses requested. If it is null, the system standard addresses are used. If keyblock is NULL, an appropriate key for creds->client is retrieved from the system key store (e.g. /etc/srvtab). If keyblock is non-NULL, it is used as the decryption key. A succesful call will place the ticket in the credentials cache ccache. returns system errors, encryption errors */ krb5_error_code KRB5_CALLCONV krb5_get_in_tkt_with_skey(krb5_context context, krb5_flags options, krb5_address *const *addrs, krb5_enctype *ktypes, krb5_preauthtype *pre_auth_types, const krb5_keyblock *key, krb5_ccache ccache, krb5_creds *creds, krb5_kdc_rep **ret_as_reply) { krb5_error_code retval; char *server; krb5_principal server_princ, client_princ; int use_master = 0; krb5_get_init_creds_opt *opts = NULL; retval = k5_populate_gic_opt(context, &opts, options, addrs, ktypes, pre_auth_types, creds); if (retval) return retval; retval = krb5_get_init_creds_opt_set_out_ccache(context, opts, ccache); if (retval) goto cleanup; #ifndef LEAN_CLIENT if (key == NULL) { retval = krb5_get_init_creds_keytab(context, creds, creds->client, NULL /* keytab */, creds->times.starttime, NULL /* in_tkt_service */, opts); goto cleanup; } #endif /* LEAN_CLIENT */ retval = krb5_unparse_name(context, creds->server, &server); if (retval) goto cleanup; server_princ = creds->server; client_princ = creds->client; retval = k5_get_init_creds(context, creds, creds->client, krb5_prompter_posix, NULL, 0, server, opts, get_as_key_skey, (void *)key, &use_master, ret_as_reply); krb5_free_unparsed_name(context, server); if (retval) goto cleanup; krb5_free_principal( context, creds->server); krb5_free_principal( context, creds->client); creds->client = client_princ; creds->server = server_princ; cleanup: krb5_get_init_creds_opt_free(context, opts); return retval; }
static void get_tickets(krb5_context context) { char *server; krb5_error_code retval; krb5_keytab keytab = NULL; krb5_principal server_princ = NULL; /* Figure out what tickets we'll be using to send. */ retval = sn2princ_realm(context, NULL, KPROP_SERVICE_NAME, realm, &my_principal); if (retval) { com_err(progname, errno, _("while setting client principal name")); exit(1); } /* Construct the principal name for the slave host. */ memset(&creds, 0, sizeof(creds)); retval = sn2princ_realm(context, slave_host, KPROP_SERVICE_NAME, realm, &server_princ); if (retval) { com_err(progname, errno, _("while setting server principal name")); exit(1); } retval = krb5_unparse_name_flags(context, server_princ, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server); if (retval) { com_err(progname, retval, _("while unparsing server name")); exit(1); } if (srvtab != NULL) { retval = krb5_kt_resolve(context, srvtab, &keytab); if (retval) { com_err(progname, retval, _("while resolving keytab")); exit(1); } } retval = krb5_get_init_creds_keytab(context, &creds, my_principal, keytab, 0, server, NULL); if (retval) { com_err(progname, retval, _("while getting initial credentials\n")); exit(1); } if (keytab != NULL) krb5_kt_close(context, keytab); krb5_free_unparsed_name(context, server); krb5_free_principal(context, server_princ); }
static PyObject * k5_get_init_creds_keytab(PyObject *self, PyObject *args) { char *name, *ktname; krb5_context ctx; krb5_error_code code; krb5_keytab keytab; krb5_ccache ccache; krb5_principal principal; krb5_get_init_creds_opt options; krb5_creds creds; if (!PyArg_ParseTuple(args, "sz", &name, &ktname)) return NULL; /* Initialize parameters. */ code = krb5_init_context(&ctx); RETURN_ON_ERROR("krb5_init_context()", code); code = krb5_parse_name(ctx, name, &principal); RETURN_ON_ERROR("krb5_parse_name()", code); krb5_get_init_creds_opt_init(&options); memset(&creds, 0, sizeof (creds)); /* Resolve keytab */ if (ktname) { code = krb5_kt_resolve(ctx, ktname, &keytab); RETURN_ON_ERROR("krb5_kt_resolve()", code); } else { code = krb5_kt_default(ctx, &keytab); RETURN_ON_ERROR("krb5_kt_resolve()", code); } /* Get the credentials. */ code = krb5_get_init_creds_keytab(ctx, &creds, principal, keytab, 0, NULL, &options); RETURN_ON_ERROR("krb5_get_init_creds_keytab()", code); /* Store the credential in the credential cache. */ code = krb5_cc_default(ctx, &ccache); RETURN_ON_ERROR("krb5_cc_default()", code); code = krb5_cc_initialize(ctx, ccache, principal); RETURN_ON_ERROR("krb5_cc_initialize()", code); code = krb5_cc_store_cred(ctx, ccache, &creds); RETURN_ON_ERROR("krb5_cc_store_creds()", code); krb5_cc_close(ctx, ccache); Py_INCREF(Py_None); return Py_None; }
static int k5ping(krb5_context ctx, const char *host, int socktype, krb5_principal princ, int use_kt, const char *passwd, krb5_principal sprinc) { K5BAIL_DECLS; krb5_error_code kerr; krb5_ccache ccache = NULL; krb5_keytab kt; krb5_creds creds; krb5_get_init_creds_opt *opt = NULL; VERBOSE(1, (stderr, "initiating kerberos5/%s ping to %s\n", socktype == SOCK_DGRAM ? "udp" : "tcp", host)); parse_kdc(host); current_socktype = socktype; K5BAIL(krb5_cc_resolve(ctx, "MEMORY:k5ping", &ccache)); K5BAIL(krb5_get_init_creds_opt_alloc(ctx, &opt)); krb5_get_init_creds_opt_set_tkt_life(opt, 15 * 60); if (use_kt) { K5BAIL(krb5_kt_default(ctx, &kt)); K5BAIL(krb5_get_init_creds_keytab(ctx, &creds, princ, kt, 0, NULL, opt)); } else { K5BAIL(krb5_get_init_creds_password(ctx, &creds, princ, passwd, krb5_prompter_posix, NULL, 0, NULL, opt)); } K5BAIL(krb5_cc_store_cred(ctx, ccache, &creds)); kret = kvno5(ctx, host, socktype, princ, sprinc, ccache); done: if (ccache) krb5_cc_destroy(ctx, ccache); /* XXXrcd: free a few more things here... */ /* opt. creds. */ if (croakstr[0]) fail_msg("kerberos5", socktype, host, croakstr); return kret; }
static void get_creds(krb5_context context, krb5_ccache *cache) { krb5_keytab keytab; krb5_principal client; krb5_error_code ret; krb5_get_init_creds_opt *init_opts; krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP; krb5_creds creds; ret = krb5_kt_register(context, &hdb_kt_ops); if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); ret = krb5_kt_resolve(context, ktname, &keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); ret = krb5_make_principal(context, &client, NULL, "kadmin", HPROP_NAME, NULL); if(ret) krb5_err(context, 1, ret, "krb5_make_principal"); ret = krb5_get_init_creds_opt_alloc(context, &init_opts); if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); krb5_get_init_creds_opt_set_preauth_list(init_opts, &preauth, 1); ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, NULL, init_opts); if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); krb5_get_init_creds_opt_free(context, init_opts); ret = krb5_kt_close(context, keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, cache); if(ret) krb5_err(context, 1, ret, "krb5_cc_new_unique"); ret = krb5_cc_initialize(context, *cache, client); if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); krb5_free_principal(context, client); ret = krb5_cc_store_cred(context, *cache, &creds); if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); krb5_free_cred_contents(context, &creds); }
static OM_uint32 acquire_initiator_cred (OM_uint32 * minor_status, krb5_context context, const gss_name_t desired_name, OM_uint32 time_req, gss_cred_usage_t cred_usage, gsskrb5_cred handle ) { OM_uint32 ret = GSS_S_FAILURE; krb5_creds cred; krb5_principal def_princ = NULL; krb5_get_init_creds_opt *opt; krb5_ccache ccache = NULL; krb5_error_code kret; memset(&cred, 0, sizeof(cred)); /* * If we have a preferred principal, lets try to find it in all * caches, otherwise, fall back to default cache, ignore all * errors while searching. */ if (handle->principal) { kret = krb5_cc_cache_match (context, handle->principal, &ccache); if (kret == 0) { goto found; } } if (ccache == NULL) { kret = krb5_cc_default(context, &ccache); if (kret) goto end; } kret = krb5_cc_get_principal(context, ccache, &def_princ); if (kret != 0) { /* we'll try to use a keytab below */ krb5_cc_close(context, ccache); def_princ = NULL; kret = 0; } else if (handle->principal == NULL) { kret = krb5_copy_principal(context, def_princ, &handle->principal); if (kret) goto end; } else if (handle->principal != NULL && krb5_principal_compare(context, handle->principal, def_princ) == FALSE) { krb5_free_principal(context, def_princ); def_princ = NULL; krb5_cc_close(context, ccache); ccache = NULL; } if (def_princ == NULL) { /* We have no existing credentials cache, * so attempt to get a TGT using a keytab. */ if (handle->principal == NULL) { kret = krb5_get_default_principal(context, &handle->principal); if (kret) goto end; } /* * Require user is in the keytab before trying to talk to * the KDC. */ kret = get_keytab(context, handle, 0); if (kret) goto end; /* since the name might have changed, let double check the credential cache */ kret = krb5_cc_cache_match(context, handle->principal, &ccache); if (kret == 0) goto found; kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, handle->keytab, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if (kret) goto end; kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) { krb5_cc_destroy(context, ccache); goto end; } kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) { krb5_cc_destroy(context, ccache); goto end; } handle->endtime = cred.times.endtime; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; } else { found: ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &handle->endtime); if (ret != GSS_S_COMPLETE) { krb5_cc_close(context, ccache); goto end; } kret = 0; } handle->ccache = ccache; ret = GSS_S_COMPLETE; end: if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (def_princ != NULL) krb5_free_principal(context, def_princ); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }
static int create_krb5_cred(krb5_context ctx, char *realm, char *user, char *password, char *ktname, krb5_ccache *ccache, gss_cred_id_t *gsscred, char **errmsg) { int rc = 0, len = 0; unsigned int minor_stat = 0, major_stat = 0; const char *errmsg_tmp = NULL; const char *cctype = NULL; char *cname = NULL; krb5_ccache defcc = NULL; krb5_creds creds; krb5_principal princ = NULL; krb5_keytab keytab = NULL; gss_key_value_element_desc elems[2]; gss_key_value_set_desc store; gss_name_t sname = NULL; gss_buffer_desc pr_name; pr_name.value = NULL; pr_name.length = 0; store.count = 0; store.elements = elems; if (user == NULL || realm == NULL) return 1; len = strlen(realm); if (len == 0 || strlen(user) == 0) return 0; DEBUG("create_krb5_cred (ctx:%p, realm:%s, user:%s, password:%s, ktname: %s," " ccache:%p, gsscred:%p)", ctx, realm, user, "****", ktname, ccache, gsscred); rc = krb5_cc_default(ctx, &defcc); if (rc != 0) goto end; cctype = krb5_cc_get_type(ctx, defcc); rc = krb5_cc_new_unique(ctx, cctype, NULL, ccache); if (rc != 0) goto end; rc = krb5_build_principal(ctx, &princ, len, realm, user, NULL); if (rc != 0) goto end; rc = krb5_cc_initialize(ctx, *ccache, princ); if (rc != 0) goto end; if (password != NULL && strlen(password) > 0) { rc = krb5_get_init_creds_password(ctx, &creds, princ, password, 0, NULL, 0, NULL, NULL); if (rc != 0) goto end; rc = krb5_cc_store_cred(ctx, *ccache, &creds); if (rc != 0) goto end; rc = krb5_cc_get_full_name(ctx, *ccache, &cname); if (rc != 0) goto end; store.elements[store.count].key = "ccache"; store.elements[store.count].value = cname; store.count++; } if (ktname != NULL && strlen(ktname) > 0) { rc = krb5_kt_resolve(ctx, ktname, &keytab); if (rc != 0) goto end; rc = krb5_get_init_creds_keytab(ctx, &creds, princ, keytab, 0, NULL, NULL); if (rc != 0) goto end; rc = krb5_cc_store_cred(ctx, *ccache, &creds); if (rc != 0) goto end; rc = krb5_cc_get_full_name(ctx, *ccache, &cname); if (rc != 0) goto end; store.elements[store.count].key = "client_keytab"; store.elements[store.count].value = ktname; store.count++; store.elements[store.count].key = "ccache"; store.elements[store.count].value = cname; store.count++; rc = krb5_unparse_name(ctx, princ, (char**)&pr_name.value); if (rc != 0) goto end; pr_name.length = strlen(pr_name.value); major_stat = gss_import_name(&minor_stat, &pr_name, GSS_KRB5_NT_PRINCIPAL_NAME, &sname); if (major_stat != 0) goto end; } // Does not work with GSS-SPENGO. //major_stat = gss_krb5_import_cred(&minor_stat, *ccache, princ, NULL, gsscred); major_stat = gss_acquire_cred_from(&minor_stat, sname, 0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &store, gsscred, NULL, NULL); end: if (keytab != NULL) krb5_kt_close(ctx, keytab); if (princ != NULL) krb5_free_principal(ctx, princ); if (defcc != NULL) krb5_cc_close(ctx, defcc); if (cname != NULL) free(cname); if (pr_name.value != NULL) krb5_free_unparsed_name(ctx, pr_name.value); if (sname != NULL) { major_stat = gss_release_name(&minor_stat, &sname); } if (rc != 0) { /* Create error message with the error code. */ errmsg_tmp = krb5_get_error_message(ctx, rc); if (errmsg != NULL && errmsg_tmp != NULL) { len = strlen(errmsg_tmp) + 26; *errmsg = (char *)malloc(len); if (*errmsg == NULL) { krb5_free_error_message(ctx, errmsg_tmp); return -1; } snprintf(*errmsg, len,"%s. (KRB5_ERROR 0x%08x)", errmsg_tmp, rc); } krb5_free_error_message(ctx, errmsg_tmp); } if (major_stat != 0) return major_stat; return rc; }
static void kerberos_kinit(void) { char *name, *krbtgt; krb5_error_code code; krb5_context ctx; krb5_ccache ccache; krb5_principal kprinc; krb5_keytab keytab; krb5_get_init_creds_opt *opts; krb5_creds creds; const char *realm; /* * Determine the principal corresponding to that keytab. We copy the * memory to ensure that it's allocated in the right memory domain on * systems where that may matter (like Windows). */ code = krb5_init_context(&ctx); if (code != 0) bail_krb5(ctx, code, "error initializing Kerberos"); kprinc = kerberos_keytab_principal(ctx, config->keytab); code = krb5_unparse_name(ctx, kprinc, &name); if (code != 0) bail_krb5(ctx, code, "error unparsing name"); krb5_free_principal(ctx, kprinc); config->principal = bstrdup(name); krb5_free_unparsed_name(ctx, name); /* Now do the Kerberos initialization. */ code = krb5_cc_default(ctx, &ccache); if (code != 0) bail_krb5(ctx, code, "error setting ticket cache"); code = krb5_parse_name(ctx, config->principal, &kprinc); if (code != 0) bail_krb5(ctx, code, "error parsing principal %s", config->principal); realm = krb5_principal_get_realm(ctx, kprinc); basprintf(&krbtgt, "krbtgt/%s@%s", realm, realm); code = krb5_kt_resolve(ctx, config->keytab, &keytab); if (code != 0) bail_krb5(ctx, code, "cannot open keytab %s", config->keytab); code = krb5_get_init_creds_opt_alloc(ctx, &opts); if (code != 0) bail_krb5(ctx, code, "cannot allocate credential options"); krb5_get_init_creds_opt_set_default_flags(ctx, NULL, realm, opts); krb5_get_init_creds_opt_set_forwardable(opts, 0); krb5_get_init_creds_opt_set_proxiable(opts, 0); code = krb5_get_init_creds_keytab(ctx, &creds, kprinc, keytab, 0, krbtgt, opts); if (code != 0) bail_krb5(ctx, code, "cannot get Kerberos tickets"); code = krb5_cc_initialize(ctx, ccache, kprinc); if (code != 0) bail_krb5(ctx, code, "error initializing ticket cache"); code = krb5_cc_store_cred(ctx, ccache, &creds); if (code != 0) bail_krb5(ctx, code, "error storing credentials"); krb5_cc_close(ctx, ccache); krb5_free_cred_contents(ctx, &creds); krb5_kt_close(ctx, keytab); krb5_free_principal(ctx, kprinc); krb5_get_init_creds_opt_free(ctx, opts); krb5_free_context(ctx); free(krbtgt); }
krb5_error_code kcm_ccache_acquire(krb5_context context, kcm_ccache ccache, time_t *expire) { krb5_error_code ret = 0; krb5_creds cred; krb5_const_realm realm; krb5_get_init_creds_opt *opt = NULL; krb5_ccache_data ccdata; char *in_tkt_service = NULL; *expire = 0; memset(&cred, 0, sizeof(cred)); KCM_ASSERT_VALID(ccache); /* We need a cached key or keytab to acquire credentials */ if (ccache->flags & KCM_FLAGS_USE_PASSWORD) { if (ccache->password == NULL) krb5_abortx(context, "kcm_ccache_acquire: KCM_FLAGS_USE_PASSWORD without password"); } else if (ccache->flags & KCM_FLAGS_USE_KEYTAB) { if (ccache->keytab == NULL) krb5_abortx(context, "kcm_ccache_acquire: KCM_FLAGS_USE_KEYTAB without keytab"); } else { kcm_log(0, "Cannot acquire initial credentials for cache %s without key", ccache->name); return KRB5_FCC_INTERNAL; } /* Fake up an internal ccache */ kcm_internal_ccache(context, ccache, &ccdata); /* Now, actually acquire the creds */ if (ccache->server != NULL) { ret = krb5_unparse_name(context, ccache->server, &in_tkt_service); if (ret) { kcm_log(0, "Failed to unparse service name for cache %s", ccache->name); return ret; } } realm = krb5_principal_get_realm(context, ccache->client); ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) goto out; krb5_get_init_creds_opt_set_default_flags(context, "kcm", realm, opt); if (ccache->tkt_life != 0) krb5_get_init_creds_opt_set_tkt_life(opt, ccache->tkt_life); if (ccache->renew_life != 0) krb5_get_init_creds_opt_set_renew_life(opt, ccache->renew_life); krb5_get_init_creds_opt_set_forwardable(opt, 1); if (ccache->flags & KCM_FLAGS_USE_PASSWORD) { ret = krb5_get_init_creds_password(context, &cred, ccache->client, ccache->password, NULL, NULL, 0, in_tkt_service, opt); } else { ret = krb5_get_init_creds_keytab(context, &cred, ccache->client, ccache->keytab, 0, in_tkt_service, opt); } if (ret) { const char *msg = krb5_get_error_message(context, ret); kcm_log(0, "Failed to acquire credentials for cache %s: %s", ccache->name, msg); krb5_free_error_message(context, msg); if (in_tkt_service != NULL) free(in_tkt_service); goto out; } if (in_tkt_service != NULL) free(in_tkt_service); /* Swap them in */ kcm_ccache_remove_creds_internal(context, ccache); ret = kcm_ccache_store_cred_internal(context, ccache, &cred, NULL, 0); if (ret) { const char *msg = krb5_get_error_message(context, ret); kcm_log(0, "Failed to store credentials for cache %s: %s", ccache->name, msg); krb5_free_error_message(context, msg); krb5_free_cred_contents(context, &cred); goto out; } *expire = cred.times.endtime; out: if (opt) krb5_get_init_creds_opt_free(context, opt); return ret; }
static void get_tickets(krb5_context context) { char *def_realm, *server; krb5_error_code retval; krb5_keytab keytab = NULL; krb5_principal server_princ = NULL; /* Figure out what tickets we'll be using to send. */ retval = krb5_sname_to_principal(context, NULL, NULL, KRB5_NT_SRV_HST, &my_principal); if (retval) { com_err(progname, errno, _("while setting client principal name")); exit(1); } if (realm != NULL) { retval = krb5_set_principal_realm(context, my_principal, realm); if (retval) { com_err(progname, errno, _("while setting client principal realm")); exit(1); } } else if (krb5_is_referral_realm(krb5_princ_realm(context, my_principal))) { /* We're going to use this as a client principal, so it can't have the * referral realm. Use the default realm instead. */ retval = krb5_get_default_realm(context, &def_realm); if (retval) { com_err(progname, errno, _("while getting default realm")); exit(1); } retval = krb5_set_principal_realm(context, my_principal, def_realm); if (retval) { com_err(progname, errno, _("while setting client principal realm")); exit(1); } } /* Construct the principal name for the slave host. */ memset(&creds, 0, sizeof(creds)); retval = krb5_sname_to_principal(context, slave_host, KPROP_SERVICE_NAME, KRB5_NT_SRV_HST, &server_princ); if (retval) { com_err(progname, errno, _("while setting server principal name")); exit(1); } retval = krb5_unparse_name_flags(context, server_princ, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server); if (retval) { com_err(progname, retval, _("while unparsing server name")); exit(1); } /* Fill in the client. */ retval = krb5_copy_principal(context, my_principal, &creds.client); if (retval) { com_err(progname, retval, _("while copying client principal")); exit(1); } if (srvtab != NULL) { retval = krb5_kt_resolve(context, srvtab, &keytab); if (retval) { com_err(progname, retval, _("while resolving keytab")); exit(1); } } retval = krb5_get_init_creds_keytab(context, &creds, my_principal, keytab, 0, server, NULL); if (retval) { com_err(progname, retval, _("while getting initial credentials\n")); exit(1); } if (keytab != NULL) krb5_kt_close(context, keytab); krb5_free_unparsed_name(context, server); krb5_free_principal(context, server_princ); }
static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, const char *realm_str, const char *princ_str, const char *keytab_name, const krb5_deltat lifetime, const char **ccname_out, time_t *expire_time_out) { char *ccname; char *realm_name = NULL; char *full_princ = NULL; char *default_realm = NULL; char *tmp_str = NULL; krb5_context context = NULL; krb5_keytab keytab = NULL; krb5_ccache ccache = NULL; krb5_principal kprinc; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_error_code krberr; krb5_timestamp kdc_time_offset; int canonicalize = 0; int kdc_time_offset_usec; int ret; krberr = krb5_init_context(&context); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to init kerberos context\n")); return krberr; } DEBUG(SSSDBG_TRACE_INTERNAL, ("Kerberos context initialized\n")); krberr = set_child_debugging(context); if (krberr != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("Cannot set krb5_child debugging\n")); } if (!realm_str) { krberr = krb5_get_default_realm(context, &default_realm); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to get default realm name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } realm_name = talloc_strdup(memctx, default_realm); krb5_free_default_realm(context, default_realm); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } else { realm_name = talloc_strdup(memctx, realm_str); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } DEBUG(SSSDBG_TRACE_INTERNAL, ("got realm_name: [%s]\n", realm_name)); if (princ_str) { if (!strchr(princ_str, '@')) { full_princ = talloc_asprintf(memctx, "%s@%s", princ_str, realm_name); } else { full_princ = talloc_strdup(memctx, princ_str); } } else { char hostname[512]; ret = gethostname(hostname, 511); if (ret == -1) { krberr = KRB5KRB_ERR_GENERIC; goto done; } hostname[511] = '\0'; DEBUG(SSSDBG_TRACE_LIBS, ("got hostname: [%s]\n", hostname)); ret = select_principal_from_keytab(memctx, hostname, realm_name, keytab_name, &full_princ, NULL, NULL); if (ret) { krberr = KRB5_KT_IOERR; goto done; } } if (!full_princ) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(SSSDBG_CONF_SETTINGS, ("Principal name is: [%s]\n", full_princ)); krberr = krb5_parse_name(context, full_princ, &kprinc); if (krberr) { DEBUG(2, ("Unable to build principal: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } if (keytab_name) { krberr = krb5_kt_resolve(context, keytab_name, &keytab); } else { krberr = krb5_kt_default(context, &keytab); } DEBUG(SSSDBG_CONF_SETTINGS, ("Using keytab [%s]\n", KEYTAB_CLEAN_NAME)); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to read keytab file [%s]: %s\n", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr))); goto done; } /* Verify the keytab */ ret = sss_krb5_verify_keytab_ex(full_princ, keytab_name, context, keytab); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Unable to verify principal is present in the keytab\n")); krberr = KRB5_KT_IOERR; goto done; } ccname = talloc_asprintf(memctx, "FILE:%s/ccache_%s", DB_PATH, realm_name); if (!ccname) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, ("keytab ccname: [%s]\n", ccname)); krberr = krb5_cc_resolve(context, ccname, &ccache); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to set cache name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krb5_get_init_creds_opt_set_tkt_life(&options, lifetime); tmp_str = getenv("KRB5_CANONICALIZE"); if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) { DEBUG(SSSDBG_CONF_SETTINGS, ("Will canonicalize principals\n")); canonicalize = 1; } sss_krb5_get_init_creds_opt_set_canonicalize(&options, canonicalize); krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc, keytab, 0, NULL, &options); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to init credentials: %s\n", sss_krb5_get_error_message(context, krberr))); sss_log(SSS_LOG_ERR, "Failed to initialize credentials using keytab [%s]: %s. " "Unable to create GSSAPI-encrypted LDAP connection.", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr)); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, ("credentials initialized\n")); /* Use updated principal if changed due to canonicalization. */ krberr = krb5_cc_initialize(context, ccache, my_creds.client); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to init ccache: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } krberr = krb5_cc_store_cred(context, ccache, &my_creds); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to store creds: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, ("credentials stored\n")); #ifdef HAVE_KRB5_GET_TIME_OFFSETS krberr = krb5_get_time_offsets(context, &kdc_time_offset, &kdc_time_offset_usec); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to get KDC time offset: %s\n", sss_krb5_get_error_message(context, krberr))); kdc_time_offset = 0; } else { if (kdc_time_offset_usec > 0) { kdc_time_offset++; } } DEBUG(SSSDBG_TRACE_INTERNAL, ("Got KDC time offset\n")); #else /* If we don't have this function, just assume no offset */ kdc_time_offset = 0; #endif krberr = 0; *ccname_out = ccname; *expire_time_out = my_creds.times.endtime - kdc_time_offset; done: if (krberr != 0) KRB5_SYSLOG(krberr); if (keytab) krb5_kt_close(context, keytab); if (context) krb5_free_context(context); return krberr; }
krb5_error_code kcm_ccache_acquire(krb5_context context, kcm_ccache ccache, krb5_creds **credp) { krb5_error_code ret = 0; krb5_creds cred; krb5_const_realm realm; krb5_get_init_creds_opt opt; krb5_ccache_data ccdata; char *in_tkt_service = NULL; int done = 0; memset(&cred, 0, sizeof(cred)); KCM_ASSERT_VALID(ccache); /* We need a cached key or keytab to acquire credentials */ if (ccache->flags & KCM_FLAGS_USE_CACHED_KEY) { if (ccache->key.keyblock.keyvalue.length == 0) krb5_abortx(context, "kcm_ccache_acquire: KCM_FLAGS_USE_CACHED_KEY without key"); } else if (ccache->flags & KCM_FLAGS_USE_KEYTAB) { if (ccache->key.keytab == NULL) krb5_abortx(context, "kcm_ccache_acquire: KCM_FLAGS_USE_KEYTAB without keytab"); } else { kcm_log(0, "Cannot acquire initial credentials for cache %s without key", ccache->name); return KRB5_FCC_INTERNAL; } HEIMDAL_MUTEX_lock(&ccache->mutex); /* Fake up an internal ccache */ kcm_internal_ccache(context, ccache, &ccdata); /* Now, actually acquire the creds */ if (ccache->server != NULL) { ret = krb5_unparse_name(context, ccache->server, &in_tkt_service); if (ret) { kcm_log(0, "Failed to unparse service principal name for cache %s: %s", ccache->name, krb5_get_err_text(context, ret)); return ret; } } realm = krb5_principal_get_realm(context, ccache->client); krb5_get_init_creds_opt_init(&opt); krb5_get_init_creds_opt_set_default_flags(context, "kcm", realm, &opt); if (ccache->tkt_life != 0) krb5_get_init_creds_opt_set_tkt_life(&opt, ccache->tkt_life); if (ccache->renew_life != 0) krb5_get_init_creds_opt_set_renew_life(&opt, ccache->renew_life); if (ccache->flags & KCM_FLAGS_USE_CACHED_KEY) { ret = krb5_get_init_creds_keyblock(context, &cred, ccache->client, &ccache->key.keyblock, 0, in_tkt_service, &opt); } else { /* loosely based on lib/krb5/init_creds_pw.c */ while (!done) { ret = krb5_get_init_creds_keytab(context, &cred, ccache->client, ccache->key.keytab, 0, in_tkt_service, &opt); switch (ret) { case KRB5KDC_ERR_KEY_EXPIRED: if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0) { goto out; } ret = change_pw_and_update_keytab(context, ccache); if (ret) goto out; break; case 0: default: done = 1; break; } } } if (ret) { kcm_log(0, "Failed to acquire credentials for cache %s: %s", ccache->name, krb5_get_err_text(context, ret)); if (in_tkt_service != NULL) free(in_tkt_service); goto out; } if (in_tkt_service != NULL) free(in_tkt_service); /* Swap them in */ kcm_ccache_remove_creds_internal(context, ccache); ret = kcm_ccache_store_cred_internal(context, ccache, &cred, 0, credp); if (ret) { kcm_log(0, "Failed to store credentials for cache %s: %s", ccache->name, krb5_get_err_text(context, ret)); krb5_free_cred_contents(context, &cred); goto out; } out: HEIMDAL_MUTEX_unlock(&ccache->mutex); return ret; }
/* Perform one iteration of attempting to get credentials. This includes * searching existing ccache for requested service if INIT_CREDS. */ static kadm5_ret_t gic_iter(kadm5_server_handle_t handle, enum init_type init_type, krb5_ccache ccache, krb5_principal client, char *pass, char *svcname, char *realm, krb5_principal *server_out) { kadm5_ret_t code; krb5_context ctx; krb5_keytab kt; krb5_get_init_creds_opt *opt = NULL; krb5_creds mcreds, outcreds; *server_out = NULL; ctx = handle->context; kt = NULL; memset(&opt, 0, sizeof(opt)); memset(&mcreds, 0, sizeof(mcreds)); memset(&outcreds, 0, sizeof(outcreds)); /* Credentials for kadmin don't need to be forwardable or proxiable. */ if (init_type != INIT_CREDS) { code = krb5_get_init_creds_opt_alloc(ctx, &opt); krb5_get_init_creds_opt_set_forwardable(opt, 0); krb5_get_init_creds_opt_set_proxiable(opt, 0); krb5_get_init_creds_opt_set_out_ccache(ctx, opt, ccache); if (init_type == INIT_ANONYMOUS) krb5_get_init_creds_opt_set_anonymous(opt, 1); } if (init_type == INIT_PASS || init_type == INIT_ANONYMOUS) { code = krb5_get_init_creds_password(ctx, &outcreds, client, pass, krb5_prompter_posix, NULL, 0, svcname, opt); if (code) goto error; } else if (init_type == INIT_SKEY) { if (pass) { code = krb5_kt_resolve(ctx, pass, &kt); if (code) goto error; } code = krb5_get_init_creds_keytab(ctx, &outcreds, client, kt, 0, svcname, opt); if (pass) krb5_kt_close(ctx, kt); if (code) goto error; } else if (init_type == INIT_CREDS) { mcreds.client = client; code = krb5_parse_name_flags(ctx, svcname, KRB5_PRINCIPAL_PARSE_IGNORE_REALM, &mcreds.server); if (code) goto error; code = krb5_set_principal_realm(ctx, mcreds.server, realm); if (code) goto error; code = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcreds, &outcreds); krb5_free_principal(ctx, mcreds.server); if (code) goto error; } else { code = EINVAL; goto error; } /* Steal the server principal of the creds we acquired and return it to the * caller, which needs to knows what service to authenticate to. */ *server_out = outcreds.server; outcreds.server = NULL; error: krb5_free_cred_contents(ctx, &outcreds); if (opt) krb5_get_init_creds_opt_free(ctx, opt); return code; }
static OM_uint32 acquire_initiator_cred (OM_uint32 * minor_status, krb5_context context, gss_const_OID credential_type, const void *credential_data, gss_const_name_t desired_name, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gsskrb5_cred handle ) { OM_uint32 ret; krb5_creds cred; krb5_principal def_princ; krb5_get_init_creds_opt *opt; krb5_ccache ccache; krb5_keytab keytab; krb5_error_code kret; keytab = NULL; ccache = NULL; def_princ = NULL; ret = GSS_S_FAILURE; memset(&cred, 0, sizeof(cred)); /* * If we have a preferred principal, lets try to find it in all * caches, otherwise, fall back to default cache, ignore all * errors while searching. */ if (credential_type != GSS_C_NO_OID && !gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { kret = KRB5_NOCREDS_SUPPLIED; /* XXX */ goto end; } if (handle->principal) { kret = krb5_cc_cache_match (context, handle->principal, &ccache); if (kret == 0) { ret = GSS_S_COMPLETE; goto found; } } if (ccache == NULL) { kret = krb5_cc_default(context, &ccache); if (kret) goto end; } kret = krb5_cc_get_principal(context, ccache, &def_princ); if (kret != 0) { /* we'll try to use a keytab below */ krb5_cc_close(context, ccache); def_princ = NULL; kret = 0; } else if (handle->principal == NULL) { kret = krb5_copy_principal(context, def_princ, &handle->principal); if (kret) goto end; } else if (handle->principal != NULL && krb5_principal_compare(context, handle->principal, def_princ) == FALSE) { krb5_free_principal(context, def_princ); def_princ = NULL; krb5_cc_close(context, ccache); ccache = NULL; } if (def_princ == NULL) { /* We have no existing credentials cache, * so attempt to get a TGT using a keytab. */ if (handle->principal == NULL) { kret = krb5_get_default_principal(context, &handle->principal); if (kret) goto end; } kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; if (credential_type != GSS_C_NO_OID && gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { gss_buffer_t password = (gss_buffer_t)credential_data; /* XXX are we requiring password to be NUL terminated? */ kret = krb5_get_init_creds_password(context, &cred, handle->principal, password->value, NULL, NULL, 0, NULL, opt); } else { kret = get_keytab(context, &keytab); if (kret) { krb5_get_init_creds_opt_free(context, opt); goto end; } kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, keytab, 0, NULL, opt); } krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if (kret) goto end; kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) { krb5_cc_destroy(context, ccache); goto end; } kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) { krb5_cc_destroy(context, ccache); goto end; } handle->lifetime = cred.times.endtime; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; } else { ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &handle->lifetime); if (ret != GSS_S_COMPLETE) { krb5_cc_close(context, ccache); goto end; } kret = 0; } found: handle->ccache = ccache; ret = GSS_S_COMPLETE; end: if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (def_princ != NULL) krb5_free_principal(context, def_princ); if (keytab != NULL) krb5_kt_close(context, keytab); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }
static krb5_error_code get_new_tickets(krb5_context context, krb5_principal principal, krb5_ccache ccache, krb5_deltat ticket_life, int interactive) { krb5_error_code ret; krb5_get_init_creds_opt *opt; krb5_creds cred; char passwd[256]; krb5_deltat start_time = 0; krb5_deltat renew = 0; const char *renewstr = NULL; krb5_enctype *enctype = NULL; krb5_ccache tempccache; #ifndef NO_NTLM struct ntlm_buf ntlmkey; memset(&ntlmkey, 0, sizeof(ntlmkey)); #endif passwd[0] = '\0'; if (password_file) { FILE *f; if (strcasecmp("STDIN", password_file) == 0) f = stdin; else f = fopen(password_file, "r"); if (f == NULL) krb5_errx(context, 1, "Failed to open the password file %s", password_file); if (fgets(passwd, sizeof(passwd), f) == NULL) krb5_errx(context, 1, N_("Failed to read password from file %s", ""), password_file); if (f != stdin) fclose(f); passwd[strcspn(passwd, "\n")] = '\0'; } #ifdef __APPLE__ if (passwd[0] == '\0') { const char *realm; OSStatus osret; UInt32 length; void *buffer; char *name; realm = krb5_principal_get_realm(context, principal); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret) goto nopassword; osret = SecKeychainFindGenericPassword(NULL, strlen(realm), realm, strlen(name), name, &length, &buffer, NULL); free(name); if (osret == noErr && length < sizeof(passwd) - 1) { memcpy(passwd, buffer, length); passwd[length] = '\0'; } nopassword: do { } while(0); } #endif memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); krb5_get_init_creds_opt_set_default_flags(context, "kinit", krb5_principal_get_realm(context, principal), opt); if(forwardable_flag != -1) krb5_get_init_creds_opt_set_forwardable (opt, forwardable_flag); if(proxiable_flag != -1) krb5_get_init_creds_opt_set_proxiable (opt, proxiable_flag); if(anonymous_flag) krb5_get_init_creds_opt_set_anonymous (opt, anonymous_flag); if (pac_flag != -1) krb5_get_init_creds_opt_set_pac_request(context, opt, pac_flag ? TRUE : FALSE); if (canonicalize_flag) krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag) krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); if (pk_user_id || ent_user_id || anonymous_flag) { ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, pk_x509_anchors, NULL, NULL, pk_use_enckey ? 2 : 0 | anonymous_flag ? 4 : 0, krb5_prompter_posix, NULL, passwd); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_pkinit"); if (ent_user_id) krb5_get_init_creds_opt_set_pkinit_user_certs(context, opt, ent_user_id); } if (addrs_flag != -1) krb5_get_init_creds_opt_set_addressless(context, opt, addrs_flag ? FALSE : TRUE); if (renew_life == NULL && renewable_flag) renewstr = "1 month"; if (renew_life) renewstr = renew_life; if (renewstr) { renew = parse_time (renewstr, "s"); if (renew < 0) errx (1, "unparsable time: %s", renewstr); krb5_get_init_creds_opt_set_renew_life (opt, renew); } if(ticket_life != 0) krb5_get_init_creds_opt_set_tkt_life (opt, ticket_life); if(start_str) { int tmp = parse_time (start_str, "s"); if (tmp < 0) errx (1, N_("unparsable time: %s", ""), start_str); start_time = tmp; } if(etype_str.num_strings) { int i; enctype = malloc(etype_str.num_strings * sizeof(*enctype)); if(enctype == NULL) errx(1, "out of memory"); for(i = 0; i < etype_str.num_strings; i++) { ret = krb5_string_to_enctype(context, etype_str.strings[i], &enctype[i]); if(ret) errx(1, "unrecognized enctype: %s", etype_str.strings[i]); } krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); } if(use_keytab || keytab_str) { krb5_keytab kt; if(keytab_str) ret = krb5_kt_resolve(context, keytab_str, &kt); else ret = krb5_kt_default(context, &kt); if (ret) krb5_err (context, 1, ret, "resolving keytab"); ret = krb5_get_init_creds_keytab (context, &cred, principal, kt, start_time, server_str, opt); krb5_kt_close(context, kt); } else if (pk_user_id || ent_user_id || anonymous_flag) { ret = krb5_get_init_creds_password (context, &cred, principal, passwd, krb5_prompter_posix, NULL, start_time, server_str, opt); } else if (!interactive) { krb5_warnx(context, "Not interactive, failed to get initial ticket"); krb5_get_init_creds_opt_free(context, opt); return 0; } else { if (passwd[0] == '\0') { char *p, *prompt; krb5_unparse_name (context, principal, &p); asprintf (&prompt, N_("%s's Password: "******""), p); free (p); if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ memset(passwd, 0, sizeof(passwd)); exit(1); } free (prompt); } ret = krb5_get_init_creds_password (context, &cred, principal, passwd, krb5_prompter_posix, NULL, start_time, server_str, opt); } krb5_get_init_creds_opt_free(context, opt); #ifndef NO_NTLM if (ntlm_domain && passwd[0]) heim_ntlm_nt_key(passwd, &ntlmkey); #endif memset(passwd, 0, sizeof(passwd)); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ exit(1); case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: case KRB5KDC_ERR_PREAUTH_FAILED: krb5_errx(context, 1, N_("Password incorrect", "")); break; case KRB5KRB_AP_ERR_V4_REPLY: krb5_errx(context, 1, N_("Looks like a Kerberos 4 reply", "")); break; default: krb5_err(context, 1, ret, "krb5_get_init_creds"); } if(ticket_life != 0) { if(abs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) { char life[64]; unparse_time_approx(cred.times.endtime - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket lifetime is %s", ""), life); } } if(renew_life) { if(abs(cred.times.renew_till - cred.times.starttime - renew) > 30) { char life[64]; unparse_time_approx(cred.times.renew_till - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket renewable lifetime is %s", ""), life); } } ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), NULL, &tempccache); if (ret) krb5_err (context, 1, ret, "krb5_cc_new_unique"); ret = krb5_cc_initialize (context, tempccache, cred.client); if (ret) krb5_err (context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_store_cred (context, tempccache, &cred); if (ret) krb5_err (context, 1, ret, "krb5_cc_store_cred"); krb5_free_cred_contents (context, &cred); ret = krb5_cc_move(context, tempccache, ccache); if (ret) krb5_err (context, 1, ret, "krb5_cc_move"); if (switch_cache_flags) krb5_cc_switch(context, ccache); #ifndef NO_NTLM if (ntlm_domain && ntlmkey.data) store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey); #endif if (ok_as_delegate_flag || windows_flag || use_referrals_flag) { unsigned char d = 0; krb5_data data; if (ok_as_delegate_flag || windows_flag) d |= 1; if (use_referrals_flag || windows_flag) d |= 2; data.length = 1; data.data = &d; krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); } if (enctype) free(enctype); return 0; }
/* * Obtain credentials via a key in the keytab given * a keytab handle and a gssd_k5_kt_princ structure. * Checks to see if current credentials are expired, * if not, uses the keytab to obtain new credentials. * * Returns: * 0 => success (or credentials have not expired) * nonzero => error */ static int gssd_get_single_krb5_cred(krb5_context context, krb5_keytab kt, struct gssd_k5_kt_princ *ple, int nocache) { #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS krb5_get_init_creds_opt *init_opts = NULL; #else krb5_get_init_creds_opt options; #endif krb5_get_init_creds_opt *opts; krb5_creds my_creds; krb5_ccache ccache = NULL; char kt_name[BUFSIZ]; char cc_name[BUFSIZ]; int code; time_t now = time(0); char *cache_type; char *pname = NULL; char *k5err = NULL; memset(&my_creds, 0, sizeof(my_creds)); if (ple->ccname && ple->endtime > now && !nocache) { printerr(2, "INFO: Credentials in CC '%s' are good until %d\n", ple->ccname, ple->endtime); code = 0; goto out; } code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ); if (code != 0) { printerr(0, "ERROR: Unable to get keytab name in " "gssd_get_single_krb5_cred\n"); goto out; } if ((krb5_unparse_name(context, ple->princ, &pname))) pname = NULL; #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS code = krb5_get_init_creds_opt_alloc(context, &init_opts); if (code) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s allocating gic options\n", k5err); goto out; } if (krb5_get_init_creds_opt_set_addressless(context, init_opts, 1)) printerr(1, "WARNING: Unable to set option for addressless " "tickets. May have problems behind a NAT.\n"); #ifdef TEST_SHORT_LIFETIME /* set a short lifetime (for debugging only!) */ printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); krb5_get_init_creds_opt_set_tkt_life(init_opts, 5 * 60); #endif opts = init_opts; #else /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS */ krb5_get_init_creds_opt_init(&options); krb5_get_init_creds_opt_set_address_list(&options, NULL); #ifdef TEST_SHORT_LIFETIME /* set a short lifetime (for debugging only!) */ printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); krb5_get_init_creds_opt_set_tkt_life(&options, 5 * 60); #endif opts = &options; #endif code = krb5_get_init_creds_keytab(context, &my_creds, ple->princ, kt, 0, NULL, opts); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(1, "WARNING: %s while getting initial ticket for " "principal '%s' using keytab '%s'\n", k5err, pname ? pname : "<unparsable>", kt_name); goto out; } /* * Initialize cache file which we're going to be using */ if (use_memcache) cache_type = "MEMORY"; else cache_type = "FILE"; snprintf(cc_name, sizeof(cc_name), "%s:%s/%s%s_%s", cache_type, ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX, GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm); ple->endtime = my_creds.times.endtime; if (ple->ccname != NULL) gsh_free(ple->ccname); ple->ccname = gsh_strdup(cc_name); if (ple->ccname == NULL) { printerr(0, "ERROR: no storage to duplicate credentials " "cache name '%s'\n", cc_name); code = ENOMEM; goto out; } code = krb5_cc_resolve(context, cc_name, &ccache); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s while opening credential cache '%s'\n", k5err, cc_name); goto out; } code = krb5_cc_initialize(context, ccache, ple->princ); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s while initializing credential " "cache '%s'\n", k5err, cc_name); } code = krb5_cc_store_cred(context, ccache, &my_creds); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s while storing credentials in '%s'\n", k5err, cc_name); goto out; } /* if we get this far, let gss mech know */ gssd_set_krb5_ccache_name(cc_name); code = 0; printerr(2, "Successfully obtained machine credentials for " "principal '%s' stored in ccache '%s'\n", pname, cc_name); out: #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS if (init_opts) krb5_get_init_creds_opt_free(context, init_opts); #endif if (pname) k5_free_unparsed_name(context, pname); if (ccache) krb5_cc_close(context, ccache); krb5_free_cred_contents(context, &my_creds); gsh_free(k5err); return code; }
static DWORD IDMKrbRenewCredentials( PIDM_KRB_CONTEXT pKrbContext ) { DWORD dwError = 0; DWORD dwCleanupError = 0; BOOLEAN bLocked = FALSE; BOOLEAN bRefreshCreds = FALSE; krb5_context pCtx = NULL; PSTR pszPrincipal = NULL; krb5_principal pPrincipal = NULL; krb5_keytab ktid = 0; krb5_ccache pCache = NULL; krb5_creds creds = {0}; IDM_RWMUTEX_LOCK_SHARED(&pKrbContext->mutex_rw, bLocked, dwError); BAIL_ON_ERROR(dwError); if (!pKrbContext->expiryTime) { bRefreshCreds = TRUE; } else { krb5_timestamp now = time(NULL); if (now >= pKrbContext->expiryTime) { bRefreshCreds = TRUE; } else { double threshold = (30 * 60); // 30 minutes double interval = difftime(pKrbContext->expiryTime, now); if (interval <= threshold) { bRefreshCreds = TRUE; } } } if (bRefreshCreds) { krb5_error_code errKrb = 0; krb5_deltat startTime = 0; PSTR pszServiceName = NULL; krb5_get_init_creds_opt options = {0}; krb5_timestamp origExpiryTime = pKrbContext->expiryTime; IDM_RWMUTEX_UNLOCK(&pKrbContext->mutex_rw, bLocked, dwError); BAIL_ON_ERROR(dwError); dwError = IDMKrbGetPrincipal( pKrbContext->pszAccount, pKrbContext->pszDomain, &pszPrincipal); BAIL_ON_ERROR(dwError); errKrb = krb5_init_context(&pCtx); BAIL_ON_KERBEROS_ERROR(NULL, errKrb, dwError); errKrb = krb5_parse_name(pCtx, pszPrincipal, &pPrincipal); BAIL_ON_KERBEROS_ERROR(NULL, errKrb, dwError); errKrb = krb5_kt_default(pCtx, &ktid); BAIL_ON_KERBEROS_ERROR(NULL, errKrb, dwError); krb5_get_init_creds_opt_init(&options); krb5_get_init_creds_opt_set_forwardable(&options, TRUE); errKrb = krb5_get_init_creds_keytab( pCtx, &creds, pPrincipal, ktid, startTime, pszServiceName, &options); BAIL_ON_KERBEROS_ERROR(NULL, errKrb, dwError); IDM_RWMUTEX_LOCK_EXCLUSIVE(&pKrbContext->mutex_rw, bLocked, dwError); BAIL_ON_ERROR(dwError); if (pKrbContext->expiryTime <= origExpiryTime) { errKrb = krb5_cc_resolve(pCtx, pKrbContext->pszCachePath, &pCache); BAIL_ON_KERBEROS_ERROR(NULL, errKrb, dwError); errKrb = krb5_cc_initialize(pCtx, pCache, pPrincipal); BAIL_ON_KERBEROS_ERROR(NULL, errKrb, dwError); errKrb = krb5_cc_store_cred(pCtx, pCache, &creds); BAIL_ON_KERBEROS_ERROR(NULL, errKrb, dwError); pKrbContext->expiryTime = creds.times.endtime; } } cleanup: IDM_RWMUTEX_UNLOCK(&pKrbContext->mutex_rw, bLocked, dwCleanupError); if (pCtx) { if (ktid) { krb5_kt_close(pCtx, ktid); ktid = 0; } if (pPrincipal) { if (creds.client == pPrincipal) { creds.client = NULL; } krb5_free_principal(pCtx, pPrincipal); } krb5_free_cred_contents(pCtx, &creds); if (pCache) { krb5_cc_close(pCtx, pCache); } krb5_free_context(pCtx); } IDM_SAFE_FREE_MEMORY(pszPrincipal); if(!dwError) { dwError = dwCleanupError; } return dwError; error: goto cleanup; }
/* * call-seq: * get_init_creds_keytab([principal][,keytab]) * * Call krb5_get_init_creds_keytab() to get credentials based on a keytab. With no parameters, gets the default principal (probably the username@DEFAULT_REALM) from the default keytab (as configured in /etc/krb5.conf). With one parameter, get the named principal from the default keytab (as configured in /etc/krb5.conf). With two parameters, get the named principal from the named keytab. Returns true on success, raises Krb5Auth::Krb5::Exception on failure. */ static VALUE Krb5_get_init_creds_keytab(int argc, VALUE *argv, VALUE self) { VALUE princ_val, keytab_val; char *princ; char *keytab_name; struct ruby_krb5 *kerb; krb5_error_code krbret; krb5_keytab keytab; keytab = NULL; rb_scan_args(argc, argv, "02", &princ_val, &keytab_val); princ = get_string_or_nil(princ_val); keytab_name = get_string_or_nil(keytab_val); Data_Get_Struct(self, struct ruby_krb5, kerb); if (!kerb) { NOSTRUCT_EXCEPT(); return Qfalse; } if (keytab_name != NULL) { krbret = krb5_kt_resolve(kerb->ctx, keytab_name, &keytab); if (krbret) { goto failed_keytab; } } // implicit else: if we weren't passed a keytab name, just leave keytab as // NULL to use the default if (princ != NULL) { krbret = krb5_parse_name(kerb->ctx, princ, &kerb->princ); } else { // if we weren't passed a principal, we just get the default principal // (which is generally the hostname) krbret = krb5_sname_to_principal(kerb->ctx, NULL, NULL, KRB5_NT_SRV_HST, &kerb->princ); } if (krbret) { goto failed_keytab; } krbret = krb5_get_init_creds_keytab(kerb->ctx, &kerb->creds, kerb->princ, keytab, 0, NULL, NULL); if (krbret) { goto failed_keytab; } if (keytab) krb5_kt_close(kerb->ctx, keytab); return Qtrue; failed_keytab: if (keytab) krb5_kt_close(kerb->ctx, keytab); Krb5_register_error(krbret); // we will never reach here, since Krb5_register_error will rb_raise(). just // leave it to shut the compiler up return Qfalse; }
static krb5_error_code get_ccache(krb5_context context, int *destroy, krb5_ccache *id) { krb5_principal principal = NULL; krb5_error_code ret; krb5_keytab kt = NULL; *id = NULL; if (!issuid()) { const char *cache; cache = getenv("NTLM_ACCEPTOR_CCACHE"); if (cache) { ret = krb5_cc_resolve(context, cache, id); if (ret) goto out; return 0; } } ret = krb5_sname_to_principal(context, NULL, "host", KRB5_NT_SRV_HST, &principal); if (ret) goto out; ret = krb5_cc_cache_match(context, principal, id); if (ret == 0) return 0; /* did not find in default credcache, lets try default keytab */ ret = krb5_kt_default(context, &kt); if (ret) goto out; /* XXX check in keytab */ { krb5_get_init_creds_opt *opt; krb5_creds cred; memset(&cred, 0, sizeof(cred)); ret = krb5_cc_new_unique(context, "MEMORY", NULL, id); if (ret) goto out; *destroy = 1; ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) goto out; ret = krb5_get_init_creds_keytab (context, &cred, principal, kt, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if (ret) goto out; ret = krb5_cc_initialize (context, *id, cred.client); if (ret) { krb5_free_cred_contents (context, &cred); goto out; } ret = krb5_cc_store_cred (context, *id, &cred); krb5_free_cred_contents (context, &cred); if (ret) goto out; } krb5_kt_close(context, kt); return 0; out: if (*id) { if (*destroy) krb5_cc_destroy(context, *id); else krb5_cc_close(context, *id); *id = NULL; } if (kt) krb5_kt_close(context, kt); if (principal) krb5_free_principal(context, principal); return ret; }
/* call-seq: * krb5.get_init_creds_keytab(principal = nil, keytab = nil, service = nil, ccache = nil) * * Acquire credentials for +principal+ from +keytab+ using +service+. If * no principal is specified, then a principal is derived from the service * name. If no service name is specified, kerberos defaults to "host". * * If no keytab file is provided, the default keytab file is used. This is * typically /etc/krb5.keytab. * * If +ccache+ is supplied and is a Kerberos::Krb5::CredentialsCache, the * resulting credentials will be stored in the credential cache. */ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){ RUBY_KRB5* ptr; VALUE v_user, v_keytab_name, v_service, v_ccache; char* user; char* service; char keytab_name[MAX_KEYTAB_NAME_LEN]; krb5_error_code kerror; krb5_get_init_creds_opt* opt; krb5_creds cred; Data_Get_Struct(self, RUBY_KRB5, ptr); if(!ptr->ctx) rb_raise(cKrb5Exception, "no context has been established"); kerror = krb5_get_init_creds_opt_alloc(ptr->ctx, &opt); if(kerror) rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_alloc: %s", error_message(kerror)); rb_scan_args(argc, argv, "04", &v_user, &v_keytab_name, &v_service, &v_ccache); // We need the service information for later. if(NIL_P(v_service)){ service = NULL; } else{ Check_Type(v_service, T_STRING); service = StringValueCStr(v_service); } // Convert the name (or service name) to a kerberos principal. if(NIL_P(v_user)){ kerror = krb5_sname_to_principal( ptr->ctx, NULL, service, KRB5_NT_SRV_HST, &ptr->princ ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_sname_to_principal: %s", error_message(kerror)); } } else{ Check_Type(v_user, T_STRING); user = StringValueCStr(v_user); kerror = krb5_parse_name(ptr->ctx, user, &ptr->princ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror)); } } // Use the default keytab if none is specified. if(NIL_P(v_keytab_name)){ kerror = krb5_kt_default_name(ptr->ctx, keytab_name, MAX_KEYTAB_NAME_LEN); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_kt_default_name: %s", error_message(kerror)); } } else{ Check_Type(v_keytab_name, T_STRING); strncpy(keytab_name, StringValueCStr(v_keytab_name), MAX_KEYTAB_NAME_LEN); } kerror = krb5_kt_resolve( ptr->ctx, keytab_name, &ptr->keytab ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_kt_resolve: %s", error_message(kerror)); } // Set the credential cache from the supplied Kerberos::Krb5::CredentialsCache if(!NIL_P(v_ccache)){ RUBY_KRB5_CCACHE* ccptr; Data_Get_Struct(v_ccache, RUBY_KRB5_CCACHE, ccptr); kerror = krb5_get_init_creds_opt_set_out_ccache(ptr->ctx, opt, ccptr->ccache); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_set_out_ccache: %s", error_message(kerror)); } } kerror = krb5_get_init_creds_keytab( ptr->ctx, &cred, ptr->princ, ptr->keytab, 0, service, opt ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_get_init_creds_keytab: %s", error_message(kerror)); } krb5_get_init_creds_opt_free(ptr->ctx, opt); return self; }
isc_result_t krb5_get_tgt(const char *principal, const char *keyfile) { isc_result_t result = ISC_R_FAILURE; char *ccname = NULL; krb5_context context = NULL; krb5_error_code krberr; krb5_ccache ccache = NULL; krb5_principal kprincpw = NULL; krb5_creds my_creds; krb5_creds * my_creds_ptr = NULL; krb5_get_init_creds_opt options; krb5_keytab keytab = NULL; int ret; if (keyfile == NULL || keyfile[0] == '\0') { keyfile = KRB_DEFAULT_KEYTAB; log_info("Using default keytab %s\n", keyfile); } else { if (strncmp(keyfile, "FILE:", 5) != 0) { log_error("Unknown keytab path format: Does it start with FILE:?\n"); return ISC_R_FAILURE; } } krberr = krb5_init_context(&context); CHECK_KRB5(NULL, krberr, "Kerberos context initialization failed"); result = ISC_R_SUCCESS; ccname = "MEMORY:dhcp_ld_krb5_cc"; log_info("Using ccache %s\n" , ccname); ret = setenv("KRB5CCNAME", ccname, 1); if (ret == -1) { log_error("Failed to setup environment\n"); result = ISC_R_FAILURE; goto cleanup; } krberr = krb5_cc_resolve(context, ccname, &ccache); CHECK_KRB5(context, krberr, "Couldnt resolve ccache '%s'", ccname); krberr = krb5_parse_name(context, principal, &kprincpw); CHECK_KRB5(context, krberr, "Failed to parse princ '%s'", princpal); result = check_credentials(context, ccache, kprincpw); if (result == ISC_R_SUCCESS) { log_info("Found valid kerberos credentials\n"); goto cleanup; } else { log_error("No valid krb5 credentials\n"); } krberr = krb5_kt_resolve(context, keyfile, &keytab); CHECK_KRB5(context, krberr, "Failed to resolve kt files '%s'\n", keyfile); memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_tkt_life(&options, KRB_MIN_TIME * 2); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krberr = krb5_get_init_creds_keytab(context, &my_creds, kprincpw, keytab, 0, NULL, &options); CHECK_KRB5(context, krberr, "Failed to get initial credentials TGT\n"); my_creds_ptr = &my_creds; krberr = krb5_cc_initialize(context, ccache, kprincpw); CHECK_KRB5(context, krberr, "Failed to init ccache\n"); krberr = krb5_cc_store_cred(context, ccache, &my_creds); CHECK_KRB5(context, krberr, "Failed to store credentials\n"); result = ISC_R_SUCCESS; log_info("Successfully init krb tgt %s", principal); cleanup: if (ccache) krb5_cc_close(context, ccache); if (keytab) krb5_kt_close(context, keytab); if (kprincpw) krb5_free_principal(context, kprincpw); if (my_creds_ptr) krb5_free_cred_contents(context, &my_creds); if (context) krb5_free_context(context); return result; }
static krb5_error_code change_pw(krb5_context context, kcm_ccache ccache, char *cpn, char *newpw) { krb5_error_code ret; krb5_creds cpw_cred; int result_code; krb5_data result_code_string; krb5_data result_string; krb5_get_init_creds_opt options; memset(&cpw_cred, 0, sizeof(cpw_cred)); krb5_get_init_creds_opt_init(&options); krb5_get_init_creds_opt_set_tkt_life(&options, 60); krb5_get_init_creds_opt_set_forwardable(&options, FALSE); krb5_get_init_creds_opt_set_proxiable(&options, FALSE); krb5_data_zero(&result_code_string); krb5_data_zero(&result_string); ret = krb5_get_init_creds_keytab(context, &cpw_cred, ccache->client, ccache->key.keytab, 0, "kadmin/changepw", &options); if (ret) { kcm_log(0, "Failed to acquire password change credentials " "for principal %s: %s", cpn, krb5_get_err_text(context, ret)); goto out; } ret = krb5_set_password(context, &cpw_cred, newpw, ccache->client, &result_code, &result_code_string, &result_string); if (ret) { kcm_log(0, "Failed to change password for principal %s: %s", cpn, krb5_get_err_text(context, ret)); goto out; } if (result_code) { kcm_log(0, "Failed to change password for principal %s: %.*s", cpn, (int)result_string.length, result_string.length > 0 ? (char *)result_string.data : ""); goto out; } out: krb5_data_free(&result_string); krb5_data_free(&result_code_string); krb5_free_cred_contents(context, &cpw_cred); return ret; }
static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, krb5_context context, const char *realm_str, const char *princ_str, const char *keytab_name, const krb5_deltat lifetime, const char **ccname_out, time_t *expire_time_out) { int fd; char *ccname; char *ccname_dummy; char *realm_name = NULL; char *full_princ = NULL; char *default_realm = NULL; char *tmp_str = NULL; krb5_keytab keytab = NULL; krb5_ccache ccache = NULL; krb5_principal kprinc; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_error_code krberr; krb5_timestamp kdc_time_offset; int canonicalize = 0; int kdc_time_offset_usec; int ret; TALLOC_CTX *tmp_ctx; char *ccname_file_dummy = NULL; char *ccname_file; mode_t old_umask; tmp_ctx = talloc_new(memctx); if (tmp_ctx == NULL) { krberr = KRB5KRB_ERR_GENERIC; goto done; } krberr = set_child_debugging(context); if (krberr != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set krb5_child debugging\n"); } if (!realm_str) { krberr = krb5_get_default_realm(context, &default_realm); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to get default realm name: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } realm_name = talloc_strdup(tmp_ctx, default_realm); krb5_free_default_realm(context, default_realm); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } else { realm_name = talloc_strdup(tmp_ctx, realm_str); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } DEBUG(SSSDBG_TRACE_INTERNAL, "got realm_name: [%s]\n", realm_name); if (princ_str) { if (!strchr(princ_str, '@')) { full_princ = talloc_asprintf(tmp_ctx, "%s@%s", princ_str, realm_name); } else { full_princ = talloc_strdup(tmp_ctx, princ_str); } } else { char hostname[HOST_NAME_MAX + 1]; ret = gethostname(hostname, HOST_NAME_MAX); if (ret == -1) { krberr = KRB5KRB_ERR_GENERIC; goto done; } hostname[HOST_NAME_MAX] = '\0'; DEBUG(SSSDBG_TRACE_LIBS, "got hostname: [%s]\n", hostname); ret = select_principal_from_keytab(tmp_ctx, hostname, realm_name, keytab_name, &full_princ, NULL, NULL); if (ret) { krberr = KRB5_KT_IOERR; goto done; } } if (!full_princ) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(SSSDBG_CONF_SETTINGS, "Principal name is: [%s]\n", full_princ); krberr = krb5_parse_name(context, full_princ, &kprinc); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Unable to build principal: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } if (keytab_name) { krberr = krb5_kt_resolve(context, keytab_name, &keytab); } else { krberr = krb5_kt_default(context, &keytab); } DEBUG(SSSDBG_CONF_SETTINGS, "Using keytab [%s]\n", KEYTAB_CLEAN_NAME); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to read keytab file [%s]: %s\n", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr)); goto done; } /* Verify the keytab */ ret = lc_verify_keytab_ex(full_princ, keytab_name, context, keytab); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Unable to verify principal is present in the keytab\n"); krberr = KRB5_KT_IOERR; goto done; } memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krb5_get_init_creds_opt_set_tkt_life(&options, lifetime); tmp_str = getenv("KRB5_CANONICALIZE"); if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) { DEBUG(SSSDBG_CONF_SETTINGS, "Will canonicalize principals\n"); canonicalize = 1; } sss_krb5_get_init_creds_opt_set_canonicalize(&options, canonicalize); ccname_file = talloc_asprintf(tmp_ctx, "%s/ccache_%s", DB_PATH, realm_name); if (ccname_file == NULL) { krberr = ENOMEM; DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed: %s:[%d].\n", strerror(krberr), krberr); goto done; } ccname_file_dummy = talloc_asprintf(tmp_ctx, "%s/ccache_%s_XXXXXX", DB_PATH, realm_name); if (ccname_file_dummy == NULL) { krberr = ENOMEM; DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed: %s:[%d].\n", strerror(krberr), krberr); goto done; } old_umask = umask(077); fd = mkstemp(ccname_file_dummy); umask(old_umask); if (fd == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "mkstemp failed: %s:[%d].\n", strerror(ret), ret); krberr = KRB5KRB_ERR_GENERIC; goto done; } /* We only care about creating a unique file name here, we don't * need the fd */ close(fd); krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc, keytab, 0, NULL, &options); krb5_kt_close(context, keytab); keytab = NULL; if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init credentials: %s\n", sss_krb5_get_error_message(context, krberr)); sss_log(SSS_LOG_ERR, "Failed to initialize credentials using keytab [%s]: %s. " "Unable to create GSSAPI-encrypted LDAP connection.", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr)); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "credentials initialized\n"); ccname_dummy = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file_dummy); ccname = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file); if (ccname_dummy == NULL || ccname == NULL) { krberr = ENOMEM; goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "keytab ccname: [%s]\n", ccname_dummy); krberr = krb5_cc_resolve(context, ccname_dummy, &ccache); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to set cache name: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } /* Use updated principal if changed due to canonicalization. */ krberr = krb5_cc_initialize(context, ccache, my_creds.client); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to init ccache: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } krberr = krb5_cc_store_cred(context, ccache, &my_creds); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to store creds: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "credentials stored\n"); #ifdef HAVE_KRB5_GET_TIME_OFFSETS krberr = krb5_get_time_offsets(context, &kdc_time_offset, &kdc_time_offset_usec); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to get KDC time offset: %s\n", sss_krb5_get_error_message(context, krberr)); kdc_time_offset = 0; } else { if (kdc_time_offset_usec > 0) { kdc_time_offset++; } } DEBUG(SSSDBG_TRACE_INTERNAL, "Got KDC time offset\n"); #else /* If we don't have this function, just assume no offset */ kdc_time_offset = 0; #endif DEBUG(SSSDBG_TRACE_INTERNAL, "Renaming [%s] to [%s]\n", ccname_file_dummy, ccname_file); ret = rename(ccname_file_dummy, ccname_file); if (ret == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "rename failed [%d][%s].\n", ret, strerror(ret)); goto done; } ccname_file_dummy = NULL; krberr = 0; *ccname_out = talloc_steal(memctx, ccname); *expire_time_out = my_creds.times.endtime - kdc_time_offset; done: if (krberr != 0) KRB5_SYSLOG(krberr); if (keytab) krb5_kt_close(context, keytab); if (context) krb5_free_context(context); if (ccname_file_dummy) { DEBUG(SSSDBG_TRACE_INTERNAL, "Unlinking [%s]\n", ccname_file_dummy); ret = unlink(ccname_file_dummy); if (ret == -1) { ret = errno; DEBUG(SSSDBG_MINOR_FAILURE, "Unlink failed [%d][%s].\n", ret, strerror(ret)); } } talloc_free(tmp_ctx); return krberr; }
static krb5_error_code get_new_cache(krb5_context context, krb5_principal client, const char *password, krb5_prompter_fct prompter, const char *keytab, const char *server_name, krb5_ccache *ret_cache) { krb5_error_code ret; krb5_creds cred; krb5_get_init_creds_opt *opt; krb5_ccache id; ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) return ret; krb5_get_init_creds_opt_set_default_flags(context, "kadmin", krb5_principal_get_realm(context, client), opt); krb5_get_init_creds_opt_set_forwardable (opt, FALSE); krb5_get_init_creds_opt_set_proxiable (opt, FALSE); if(password == NULL && prompter == NULL) { krb5_keytab kt; if(keytab == NULL) ret = krb5_kt_default(context, &kt); else ret = krb5_kt_resolve(context, keytab, &kt); if(ret) { krb5_get_init_creds_opt_free(context, opt); return ret; } ret = krb5_get_init_creds_keytab (context, &cred, client, kt, 0, server_name, opt); krb5_kt_close(context, kt); } else { ret = krb5_get_init_creds_password (context, &cred, client, password, prompter, NULL, 0, server_name, opt); } krb5_get_init_creds_opt_free(context, opt); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: return KADM5_BAD_PASSWORD; default: return ret; } ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); if(ret) return ret; ret = krb5_cc_initialize (context, id, cred.client); if (ret) return ret; ret = krb5_cc_store_cred (context, id, &cred); if (ret) return ret; krb5_free_cred_contents (context, &cred); *ret_cache = id; return 0; }
static OM_uint32 acquire_initiator_cred (OM_uint32 * minor_status, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t handle, gss_OID_set * actual_mechs, OM_uint32 * time_rec ) { OM_uint32 ret; krb5_creds cred; krb5_principal def_princ; krb5_get_init_creds_opt *opt; krb5_ccache ccache; krb5_keytab keytab; krb5_error_code kret; keytab = NULL; ccache = NULL; def_princ = NULL; ret = GSS_S_FAILURE; memset(&cred, 0, sizeof(cred)); kret = krb5_cc_default(gssapi_krb5_context, &ccache); if (kret) goto end; kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, &def_princ); if (kret != 0) { /* we'll try to use a keytab below */ krb5_cc_destroy(gssapi_krb5_context, ccache); ccache = NULL; kret = 0; } else if (handle->principal == NULL) { kret = krb5_copy_principal(gssapi_krb5_context, def_princ, &handle->principal); if (kret) goto end; } else if (handle->principal != NULL && krb5_principal_compare(gssapi_krb5_context, handle->principal, def_princ) == FALSE) { /* Before failing, lets check the keytab */ krb5_free_principal(gssapi_krb5_context, def_princ); def_princ = NULL; } if (def_princ == NULL) { /* We have no existing credentials cache, * so attempt to get a TGT using a keytab. */ if (handle->principal == NULL) { kret = krb5_get_default_principal(gssapi_krb5_context, &handle->principal); if (kret) goto end; } kret = get_keytab(&keytab); if (kret) goto end; kret = krb5_get_init_creds_opt_alloc(gssapi_krb5_context, &opt); if (kret) goto end; kret = krb5_get_init_creds_keytab(gssapi_krb5_context, &cred, handle->principal, keytab, 0, NULL, opt); krb5_get_init_creds_opt_free(opt); if (kret) goto end; kret = krb5_cc_gen_new(gssapi_krb5_context, &krb5_mcc_ops, &ccache); if (kret) goto end; kret = krb5_cc_initialize(gssapi_krb5_context, ccache, cred.client); if (kret) goto end; kret = krb5_cc_store_cred(gssapi_krb5_context, ccache, &cred); if (kret) goto end; handle->lifetime = cred.times.endtime; } else { krb5_creds in_cred, *out_cred; krb5_const_realm realm; memset(&in_cred, 0, sizeof(in_cred)); in_cred.client = handle->principal; realm = krb5_principal_get_realm(gssapi_krb5_context, handle->principal); if (realm == NULL) { kret = KRB5_PRINC_NOMATCH; /* XXX */ goto end; } kret = krb5_make_principal(gssapi_krb5_context, &in_cred.server, realm, KRB5_TGS_NAME, realm, NULL); if (kret) goto end; kret = krb5_get_credentials(gssapi_krb5_context, 0, ccache, &in_cred, &out_cred); krb5_free_principal(gssapi_krb5_context, in_cred.server); if (kret) goto end; handle->lifetime = out_cred->times.endtime; krb5_free_creds(gssapi_krb5_context, out_cred); } handle->ccache = ccache; ret = GSS_S_COMPLETE; end: if (cred.client != NULL) krb5_free_cred_contents(gssapi_krb5_context, &cred); if (def_princ != NULL) krb5_free_principal(gssapi_krb5_context, def_princ); if (keytab != NULL) krb5_kt_close(gssapi_krb5_context, keytab); if (ret != GSS_S_COMPLETE) { if (ccache != NULL) krb5_cc_close(gssapi_krb5_context, ccache); if (kret != 0) { *minor_status = kret; gssapi_krb5_set_error_string (); } } return (ret); }
/* * Acquires an initiator credential from a ccache or using a keytab. */ static OM_uint32 acquire_initiator_cred(OM_uint32 *minor_status, krb5_context context, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gsskrb5_cred handle) { OM_uint32 ret = GSS_S_FAILURE; krb5_creds cred; krb5_get_init_creds_opt *opt; krb5_principal def_princ = NULL; krb5_ccache def_ccache = NULL; krb5_ccache ccache = NULL; /* we may store into this ccache */ krb5_keytab keytab = NULL; krb5_error_code kret = 0; OM_uint32 left; time_t lifetime = 0; time_t now; memset(&cred, 0, sizeof(cred)); /* * Get current time early so we can set handle->endtime to a value that * cannot accidentally be past the real endtime. We need a variant of * krb5_cc_get_lifetime() that returns absolute endtime. */ krb5_timeofday(context, &now); /* * First look for a ccache that has the desired_name (which may be * the default credential name). * * If we don't have an unexpired credential, acquire one with a * keytab. * * If we acquire one with a keytab, save it in the ccache we found * with the expired credential, if any. * * If we don't have any such ccache, then use a MEMORY ccache. */ if (handle->principal != NULL) { /* * Not default credential case. See if we can find a ccache in * the cccol for the desired_name. */ kret = krb5_cc_cache_match(context, handle->principal, &ccache); if (kret == 0) { kret = krb5_cc_get_lifetime(context, ccache, &lifetime); if (kret == 0) { if (lifetime > 0) goto found; else goto try_keytab; } } /* * Fall through. We shouldn't find this in the default ccache * either, but we'll give it a try, then we'll try using a keytab. */ } /* * Either desired_name was GSS_C_NO_NAME (default cred) or * krb5_cc_cache_match() failed (or found expired). */ kret = krb5_cc_default(context, &def_ccache); if (kret != 0) goto try_keytab; kret = krb5_cc_get_lifetime(context, def_ccache, &lifetime); if (kret != 0) lifetime = 0; kret = krb5_cc_get_principal(context, def_ccache, &def_princ); if (kret != 0) goto try_keytab; /* * Have a default ccache; see if it matches desired_name. */ if (handle->principal == NULL || krb5_principal_compare(context, handle->principal, def_princ) == TRUE) { /* * It matches. * * If we end up trying a keytab then we can write the result to * the default ccache. */ if (handle->principal == NULL) { kret = krb5_copy_principal(context, def_princ, &handle->principal); if (kret) goto end; } if (ccache != NULL) krb5_cc_close(context, ccache); ccache = def_ccache; def_ccache = NULL; if (lifetime > 0) goto found; /* else we fall through and try using a keytab */ } try_keytab: if (handle->principal == NULL) { /* We need to know what client principal to use */ kret = krb5_get_default_principal(context, &handle->principal); if (kret) goto end; } kret = get_keytab(context, &keytab); if (kret) goto end; kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; krb5_timeofday(context, &now); kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, keytab, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; /* * We got a credential with a keytab. Save it if we can. */ if (ccache == NULL) { /* * There's no ccache we can overwrite with the credentials we acquired * with a keytab. We'll use a MEMORY ccache then. * * Note that an application that falls into this repeatedly will do an * AS exchange every time it acquires a credential handle. Hopefully * this doesn't happen much. A workaround is to kinit -k once so that * we always re-initialize the matched/default ccache here. I.e., once * there's a FILE/DIR ccache, we'll keep it frash automatically if we * have a keytab, but if there's no FILE/DIR ccache, then we'll * get a fresh credential *every* time we're asked. */ kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if (kret) goto end; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; } /* else we'll re-initialize whichever ccache we matched above */ kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) goto end; kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) goto end; found: assert(handle->principal != NULL); ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &left); if (ret != GSS_S_COMPLETE) goto end; handle->endtime = now + left; handle->ccache = ccache; ccache = NULL; ret = GSS_S_COMPLETE; kret = 0; end: if (ccache != NULL) { if ((handle->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) != 0) krb5_cc_destroy(context, ccache); else krb5_cc_close(context, ccache); } if (def_ccache != NULL) krb5_cc_close(context, def_ccache); if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (def_princ != NULL) krb5_free_principal(context, def_princ); if (keytab != NULL) krb5_kt_close(context, keytab); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }
/* returns boolean */ static int k5_kinit(struct k_opts *opts, struct k5_data *k5, struct user_info *u_info) { char *doing; int notix = 1; krb5_keytab keytab = 0; krb5_creds my_creds; krb5_error_code code = 0; krb5_get_init_creds_opt options; krb5_address **addresses; krb5_get_init_creds_opt_init(&options); g_memset(&my_creds, 0, sizeof(my_creds)); /* From this point on, we can goto cleanup because my_creds is initialized. */ if (opts->lifetime) { krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime); } if (opts->rlife) { krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife); } if (opts->forwardable) { krb5_get_init_creds_opt_set_forwardable(&options, 1); } if (opts->not_forwardable) { krb5_get_init_creds_opt_set_forwardable(&options, 0); } if (opts->proxiable) { krb5_get_init_creds_opt_set_proxiable(&options, 1); } if (opts->not_proxiable) { krb5_get_init_creds_opt_set_proxiable(&options, 0); } if (opts->addresses) { addresses = NULL; code = krb5_os_localaddr(k5->ctx, &addresses); if (code != 0) { g_printf("krb5_os_localaddr failed in k5_kinit\n"); goto cleanup; } krb5_get_init_creds_opt_set_address_list(&options, addresses); } if (opts->no_addresses) { krb5_get_init_creds_opt_set_address_list(&options, NULL); } if ((opts->action == INIT_KT) && opts->keytab_name) { code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab); if (code != 0) { g_printf("krb5_kt_resolve failed in k5_kinit\n"); goto cleanup; } } switch (opts->action) { case INIT_PW: code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, 0, kinit_prompter, u_info, opts->starttime, opts->service_name, &options); break; case INIT_KT: code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, keytab, opts->starttime, opts->service_name, &options); break; case VALIDATE: code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc, opts->service_name); break; case RENEW: code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->cc, opts->service_name); break; } if (code != 0) { doing = 0; switch (opts->action) { case INIT_PW: case INIT_KT: doing = "getting initial credentials"; break; case VALIDATE: doing = "validating credentials"; break; case RENEW: doing = "renewing credentials"; break; } if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) { g_printf("sesman: Password incorrect while %s in k5_kinit\n", doing); } else { g_printf("sesman: error while %s in k5_kinit\n", doing); } goto cleanup; } if (!opts->lifetime) { /* We need to figure out what lifetime to use for Kerberos 4. */ opts->lifetime = my_creds.times.endtime - my_creds.times.authtime; } code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me); if (code != 0) { g_printf("krb5_cc_initialize failed in k5_kinit\n"); goto cleanup; } code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds); if (code != 0) { g_printf("krb5_cc_store_cred failed in k5_kinit\n"); goto cleanup; } notix = 0; cleanup: if (my_creds.client == k5->me) { my_creds.client = 0; } krb5_free_cred_contents(k5->ctx, &my_creds); if (keytab) { krb5_kt_close(k5->ctx, keytab); } return notix ? 0 : 1; }
void* kinit_qtask( void *ctx, void *arg ) { struct re_s *rtask = arg; kinit_data *kid = (kinit_data*)rtask->arg; krb5_error_code rc; krb5_creds creds; int nextcheck, remaining, renew=0; Log(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_qtask: running TGT check\n" ); memset(&creds, 0, sizeof(creds)); renew = kinit_check_tgt(kid, &remaining); if (renew > 0) { if (renew==1) { Log(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_qtask: Trying to renew TGT: "); rc = krb5_get_renewed_creds(kid->ctx, &creds, kid->princ, kid->ccache, NULL); if (rc!=0) { Log(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Failed\n" ); log_krb5_errmsg( kid->ctx, "kinit_qtask, Renewal failed: krb5_get_renewed_creds", rc ); renew++; } else { Log(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Success\n" ); krb5_cc_initialize(kid->ctx, kid->ccache, creds.client); krb5_cc_store_cred(kid->ctx, kid->ccache, &creds); krb5_free_cred_contents(kid->ctx, &creds); renew=kinit_check_tgt(kid, &remaining); } } if (renew > 1) { Log(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_qtask: Trying to get new TGT: "); rc = krb5_get_init_creds_keytab( kid->ctx, &creds, kid->princ, kid->keytab, 0, NULL, kid->opts); if (rc) { Log(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Failed\n" ); log_krb5_errmsg(kid->ctx, "krb5_get_init_creds_keytab", rc); } else { Log(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Success\n" ); renew=kinit_check_tgt(kid, &remaining); } krb5_free_cred_contents(kid->ctx, &creds); } } if (renew == 0) { nextcheck = remaining-30; } else { nextcheck = 60; } ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) { ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); } Log(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_qtask: Next TGT check in %dh:%02dm:%02ds\n", nextcheck/3600, (nextcheck%3600)/60, nextcheck%60); rtask->interval.tv_sec = nextcheck; ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 ); slap_wake_listener(); ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); return NULL; }
static char * init_cc_from_keytab(const char *keytab_name, const char *user) { krb5_context context = NULL; krb5_error_code ret; krb5_creds my_creds; krb5_keytab keytab = NULL; krb5_principal me = NULL; krb5_ccache cc = NULL; char *ccname = NULL; memset((char *) &my_creds, 0, sizeof(my_creds)); ret = krb5_init_context(&context); if (ret) { syslog(LOG_DEBUG, "krb5_init_context: %d", (int)ret); goto icfk_cleanup; } ret = krb5_kt_resolve(context, keytab_name, &keytab); if (ret) { syslog(LOG_DEBUG, "krb5_kt_resolve: %d", (int)ret); goto icfk_cleanup; } ret = krb5_parse_name(context, user, &me); if (ret) { syslog(LOG_DEBUG, "krb5_parse_name: %d", (int)ret); goto icfk_cleanup; } ret = krb5_get_init_creds_keytab(context, &my_creds, me, keytab, 0, NULL, NULL); if (ret) { syslog(LOG_DEBUG, "krb5_get_init_creds_keytab: %d", (int)ret); goto icfk_cleanup; } ret = krb5_cc_default(context, &cc); if (ret) { syslog(LOG_DEBUG, "krb5_cc_default: %d", (int)ret); goto icfk_cleanup; } ret = krb5_cc_initialize(context, cc, me); if (ret) { syslog(LOG_DEBUG, "krb5_cc_initialize: %d", (int)ret); goto icfk_cleanup; } ret = krb5_cc_store_cred(context, cc, &my_creds); if (ret) syslog(LOG_DEBUG, "krb5_cc_store_cred: %d", (int)ret); ccname = strdup(krb5_cc_default_name(context)); if (ccname == NULL) syslog(LOG_ERR, "Unable to allocate memory"); icfk_cleanup: my_creds.client = 0; krb5_free_cred_contents(context, &my_creds); if (me) krb5_free_principal(context, me); if (cc) krb5_cc_close(context, cc); if (keytab) krb5_kt_close(context, keytab); if (context) krb5_free_context(context); return ccname; }