static krb5_error_code verify_user_opt_int(krb5_context context, krb5_principal principal, const char *password, krb5_verify_opt *vopt) { krb5_error_code ret; krb5_get_init_creds_opt *opt; krb5_creds cred; ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) return ret; krb5_get_init_creds_opt_set_default_flags(context, NULL, krb5_principal_get_realm(context, principal), opt); ret = krb5_get_init_creds_password (context, &cred, principal, password, krb5_prompter_posix, NULL, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if(ret) return ret; #define OPT(V, D) ((vopt && (vopt->V)) ? (vopt->V) : (D)) return verify_common (context, principal, OPT(ccache, NULL), OPT(keytab, NULL), vopt ? vopt->secure : TRUE, OPT(service, "host"), cred); #undef OPT }
/* simulate a kinit, putting the tgt in the given credentials cache. Orignally by [email protected] */ int kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc, krb5_principal principal, const char *password, time_t *expire_time, time_t *kdc_time) { krb5_error_code code = 0; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_get_init_creds_opt_init(&options); krb5_get_init_creds_opt_set_default_flags(ctx, NULL, NULL, &options); if ((code = krb5_get_init_creds_password(ctx, &my_creds, principal, password, NULL, NULL, 0, NULL, &options))) { return code; } if ((code = krb5_cc_initialize(ctx, cc, principal))) { krb5_free_cred_contents(ctx, &my_creds); return code; } if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) { krb5_free_cred_contents(ctx, &my_creds); return code; } if (expire_time) { *expire_time = (time_t) my_creds.times.endtime; } if (kdc_time) { *kdc_time = (time_t) my_creds.times.starttime; } krb5_free_cred_contents(ctx, &my_creds); return 0; }
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_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 = NULL; krb5_init_creds_context ctx = NULL; krb5_get_init_creds_opt *opt = NULL; krb5_prompter_fct prompter = krb5_prompter_posix; #ifndef NO_NTLM struct ntlm_buf ntlmkey; memset(&ntlmkey, 0, sizeof(ntlmkey)); #endif passwd[0] = '\0'; if (!interactive) prompter = NULL; if (password_file) { FILE *f; if (strcasecmp("STDIN", password_file) == 0) f = stdin; else f = fopen(password_file, "r"); if (f == NULL) { krb5_warnx(context, "Failed to open the password file %s", password_file); return errno; } if (fgets(passwd, sizeof(passwd), f) == NULL) { krb5_warnx(context, N_("Failed to read password from file %s", ""), password_file); fclose(f); return EINVAL; /* XXX Need a better error */ } 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_warn(context, ret, "krb5_get_init_creds_opt_alloc"); goto out; } 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, prompter, NULL, passwd); if (ret) { krb5_warn(context, ret, "krb5_get_init_creds_opt_set_pkinit"); goto out; } 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); } ret = krb5_init_creds_init(context, principal, prompter, NULL, start_time, opt, &ctx); if (ret) { krb5_warn(context, ret, "krb5_init_creds_init"); goto out; } if (server_str) { ret = krb5_init_creds_set_service(context, ctx, server_str); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_service"); goto out; } } if (fast_armor_cache_string) { krb5_ccache fastid; ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); if (ret) { krb5_warn(context, ret, "krb5_cc_resolve(FAST cache)"); goto out; } ret = krb5_init_creds_set_fast_ccache(context, ctx, fastid); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_fast_ccache"); goto out; } } if (use_keytab || keytab_str) { ret = krb5_init_creds_set_keytab(context, ctx, kt); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_keytab"); goto out; } } else if (pk_user_id || ent_user_id || anonymous_flag) { } else if (!interactive && passwd[0] == '\0') { static int already_warned = 0; if (!already_warned) krb5_warnx(context, "Not interactive, failed to get " "initial ticket"); krb5_get_init_creds_opt_free(context, opt); already_warned = 1; return 0; } else { if (passwd[0] == '\0') { char *p, *prompt; int aret = 0; ret = krb5_unparse_name(context, principal, &p); if (ret) errx(1, "failed to generate passwd prompt: not enough memory"); aret = asprintf(&prompt, N_("%s's Password: "******""), p); free(p); if (aret == -1) errx(1, "failed to generate passwd prompt: not enough memory"); if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ memset(passwd, 0, sizeof(passwd)); errx(1, "failed to read password"); } free(prompt); } if (passwd[0]) { ret = krb5_init_creds_set_password(context, ctx, passwd); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_password"); goto out; } } } ret = krb5_init_creds_get(context, ctx); #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: case KRB5_GET_IN_TKT_LOOP: krb5_warnx(context, N_("Password incorrect", "")); goto out; case KRB5KRB_AP_ERR_V4_REPLY: krb5_warnx(context, N_("Looks like a Kerberos 4 reply", "")); goto out; case KRB5KDC_ERR_KEY_EXPIRED: krb5_warnx(context, N_("Password expired", "")); goto out; default: krb5_warn(context, ret, "krb5_get_init_creds"); goto out; } krb5_process_last_request(context, opt, ctx); ret = krb5_init_creds_get_creds(context, ctx, &cred); if (ret) { krb5_warn(context, ret, "krb5_init_creds_get_creds"); goto out; } 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); } } krb5_free_cred_contents(context, &cred); ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), NULL, &tempccache); if (ret) { krb5_warn(context, ret, "krb5_cc_new_unique"); goto out; } ret = krb5_init_creds_store(context, ctx, tempccache); if (ret) { krb5_warn(context, ret, "krb5_init_creds_store"); goto out; } krb5_init_creds_free(context, ctx); ctx = NULL; ret = krb5_cc_move(context, tempccache, ccache); if (ret) { krb5_warn(context, ret, "krb5_cc_move"); goto out; } tempccache = NULL; 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); } out: krb5_get_init_creds_opt_free(context, opt); if (ctx) krb5_init_creds_free(context, ctx); if (tempccache) krb5_cc_close(context, tempccache); if (enctype) free(enctype); return ret; }
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 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; }
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; }
OM_uint32 GSSAPI_CALLCONV _gss_krb5_acquire_cred_ext(OM_uint32 * minor_status, const gss_name_t desired_name, gss_const_OID credential_type, const void *credential_data, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gss_cred_id_t * output_cred_handle) { krb5_init_creds_context ctx = NULL; krb5_get_init_creds_opt *opt = NULL; krb5_principal principal; krb5_context context; krb5_error_code kret; gsskrb5_cred handle = NULL; krb5_ccache ccache = NULL, ccachereplace = NULL; char *passwordstr = NULL; char *cache_name = NULL; char *lkdc_hostname = NULL; hx509_cert hxcert = NULL; heim_array_t bundleacl = NULL; krb5_principal new_name = NULL; GSSAPI_KRB5_INIT(&context); cred_usage &= GSS_C_OPTION_MASK; if (cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } if (desired_name == GSS_C_NO_NAME) return GSS_S_FAILURE; if (gss_oid_equal(credential_type, GSS_C_CRED_HEIMBASE)) { heim_object_t pw, cname, cert, lkdc; heim_dict_t dict = (heim_dict_t)credential_data; pw = heim_dict_copy_value(dict, _gsskrb5_kGSSICPassword); if (pw) { if (heim_get_tid(pw) == heim_string_get_type_id()) { passwordstr = heim_string_copy_utf8(pw); if (passwordstr == NULL) { kret = ENOMEM; goto out; } } else if (heim_get_tid(pw) == heim_data_get_type_id()) { passwordstr = malloc(heim_data_get_length(pw) + 1); if (passwordstr == NULL) { kret = ENOMEM; goto out; } memcpy(passwordstr, heim_data_get_bytes(pw), heim_data_get_length(pw)); passwordstr[heim_data_get_length(pw)] = '\0'; } heim_release(pw); } cname = heim_dict_copy_value(dict, _gsskrb5_kGSSICKerberosCacheName); if (cname) { cache_name = heim_string_copy_utf8(cname); heim_release(cname); } bundleacl = heim_dict_copy_value(dict, _gsskrb5_kGSSICAppIdentifierACL); #ifdef PKINIT cert = heim_dict_copy_value(dict, _gsskrb5_kGSSICCertificate); if (cert) { kret = hx509_cert_init_SecFramework(context->hx509ctx, cert, &hxcert); if (kret) goto out; heim_release(cert); } #endif lkdc = heim_dict_copy_value(dict, _gsskrb5_kGSSICLKDCHostname); if (lkdc) { lkdc_hostname = heim_string_copy_utf8(lkdc); heim_release(lkdc); } } else if (gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { gss_buffer_t password = (gss_buffer_t)credential_data; passwordstr = malloc(password->length + 1); if (passwordstr == NULL) { kret = ENOMEM; goto out; } memcpy(passwordstr, password->value, password->length); passwordstr[password->length] = '\0'; } else { *minor_status = KRB5_NOCREDS_SUPPLIED; /* XXX */ return GSS_S_FAILURE; } if (passwordstr == NULL && hxcert == NULL) { *minor_status = KRB5_NOCREDS_SUPPLIED; /* XXX */ return GSS_S_FAILURE; } *output_cred_handle = NULL; handle = calloc(1, sizeof(*handle)); if (handle == NULL) { *minor_status = ENOMEM; return (GSS_S_FAILURE); } principal = (krb5_principal)desired_name; HEIMDAL_MUTEX_init(&handle->cred_id_mutex); kret = krb5_copy_principal(context, principal, &handle->principal); if (kret) goto out; kret = krb5_cc_new_unique(context, NULL, NULL, &ccache); if (kret) goto out; kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto out; krb5_get_init_creds_opt_set_default_flags(context, "gss", krb5_principal_get_realm(context, principal), opt); krb5_get_init_creds_opt_set_forwardable(opt, 1); krb5_get_init_creds_opt_set_proxiable(opt, 1); krb5_get_init_creds_opt_set_renew_life(opt, 3600 * 24 * 30); /* 1 month */ if (hxcert) { char *cert_pool[2] = { "KEYCHAIN:", NULL }; kret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, NULL, "KEYCHAIN:", cert_pool, NULL, 8, NULL, NULL, NULL); if (kret) goto out; } kret = krb5_init_creds_init(context, handle->principal, NULL, NULL, NULL, opt, &ctx); if (kret) goto out; if (passwordstr) { kret = krb5_init_creds_set_password(context, ctx, passwordstr); memset(passwordstr, 0, strlen(passwordstr)); free(passwordstr); passwordstr = NULL; if (kret) goto out; } if (hxcert) { kret = krb5_init_creds_set_pkinit_client_cert(context, ctx, hxcert); if (kret) goto out; } if (lkdc_hostname) { kret = krb5_init_creds_set_kdc_hostname(context, ctx, lkdc_hostname); free(lkdc_hostname); lkdc_hostname = NULL; if (kret) goto out; } kret = krb5_init_creds_get(context, ctx); if (kret) goto out; handle->endtime = _krb5_init_creds_get_cred_endtime(context, ctx); /* * If we where subjected to a referral, update the name of the credential */ new_name = _krb5_init_creds_get_cred_client(context, ctx); if (new_name && !krb5_principal_compare(context, new_name, handle->principal)) { krb5_free_principal(context, handle->principal); kret = krb5_copy_principal(context, new_name, &handle->principal); if (kret) goto out; } /* * Now store the credential */ if (cache_name) { /* check if caller told us to use a specific cache */ kret = krb5_cc_resolve(context, cache_name, &ccachereplace); if (kret) goto out; } else { /* * check if there an existing cache to overwrite before we lay * down the new cache */ (void)krb5_cc_cache_match(context, principal, &ccachereplace); } kret = krb5_init_creds_store(context, ctx, ccache); if (kret == 0) kret = krb5_init_creds_store_config(context, ctx, ccache); if (bundleacl) krb5_cc_set_acl(context, ccache, "kHEIMAttrBundleIdentifierACL", bundleacl); krb5_init_creds_free(context, ctx); ctx = NULL; if (kret) goto out; krb5_get_init_creds_opt_free(context, opt); opt = NULL; /* * If we have a credential with the same naame, lets overwrite it */ if (ccachereplace) { kret = krb5_cc_move(context, ccache, ccachereplace); if (kret) goto out; handle->ccache = ccachereplace; ccachereplace = NULL; } else { handle->ccache = ccache; } handle->usage = cred_usage; *minor_status = 0; *output_cred_handle = (gss_cred_id_t)handle; if (cache_name) free(cache_name); heim_release(bundleacl); return GSS_S_COMPLETE; out: if (bundleacl) heim_release(bundleacl); if (opt) krb5_get_init_creds_opt_free(context, opt); if (ctx) krb5_init_creds_free(context, ctx); if (lkdc_hostname) free(lkdc_hostname); if (cache_name) free(cache_name); if (passwordstr) { memset(passwordstr, 0, strlen(passwordstr)); free(passwordstr); } if (ccachereplace) krb5_cc_close(context, ccachereplace); if (ccache) krb5_cc_destroy(context, ccache); if (handle) { if (handle->principal) krb5_free_principal(context, handle->principal); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); } *minor_status = kret; return GSS_S_FAILURE; }
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 kinit_to_ccache(TALLOC_CTX *parent_ctx, struct cli_credentials *credentials, struct smb_krb5_context *smb_krb5_context, struct tevent_context *event_ctx, krb5_ccache ccache, enum credentials_obtained *obtained, const char **error_string) { krb5_error_code ret; const char *password; #ifdef SAMBA4_USES_HEIMDAL const char *self_service; #endif const char *target_service; time_t kdc_time = 0; krb5_principal princ; krb5_principal impersonate_principal; int tries; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); krb5_get_init_creds_opt *krb_options; if (!mem_ctx) { (*error_string) = strerror(ENOMEM); return ENOMEM; } ret = principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &princ, obtained, error_string); if (ret) { talloc_free(mem_ctx); return ret; } if (princ == NULL) { (*error_string) = talloc_asprintf(credentials, "principal, username or realm was not specified in the credentials"); talloc_free(mem_ctx); return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; } ret = impersonate_principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &impersonate_principal, error_string); if (ret) { talloc_free(mem_ctx); return ret; } #ifdef SAMBA4_USES_HEIMDAL self_service = cli_credentials_get_self_service(credentials); #endif target_service = cli_credentials_get_target_service(credentials); password = cli_credentials_get_password(credentials); /* setup the krb5 options we want */ if ((ret = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context, &krb_options))) { (*error_string) = talloc_asprintf(credentials, "krb5_get_init_creds_opt_alloc failed (%s)\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)); talloc_free(mem_ctx); return ret; } #ifdef SAMBA4_USES_HEIMDAL /* Disable for now MIT reads defaults when needed */ /* get the defaults */ krb5_get_init_creds_opt_set_default_flags(smb_krb5_context->krb5_context, NULL, NULL, krb_options); #endif /* set if we want a forwardable ticket */ switch (cli_credentials_get_krb_forwardable(credentials)) { case CRED_AUTO_KRB_FORWARDABLE: break; case CRED_NO_KRB_FORWARDABLE: krb5_get_init_creds_opt_set_forwardable(krb_options, FALSE); break; case CRED_FORCE_KRB_FORWARDABLE: krb5_get_init_creds_opt_set_forwardable(krb_options, TRUE); break; } #ifdef SAMBA4_USES_HEIMDAL /* FIXME: MIT does not have this yet */ /* * In order to work against windows KDCs even if we use * the netbios domain name as realm, we need to add the following * flags: * KRB5_INIT_CREDS_NO_C_CANON_CHECK; * KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK; * * On MIT: Set pkinit_eku_checking to none */ krb5_get_init_creds_opt_set_win2k(smb_krb5_context->krb5_context, krb_options, true); #else /* MIT */ krb5_get_init_creds_opt_set_canonicalize(krb_options, true); #endif tries = 2; while (tries--) { #ifdef SAMBA4_USES_HEIMDAL struct tevent_context *previous_ev; /* Do this every time, in case we have weird recursive issues here */ ret = smb_krb5_context_set_event_ctx(smb_krb5_context, event_ctx, &previous_ev); if (ret) { talloc_free(mem_ctx); return ret; } #endif if (password) { if (impersonate_principal) { #ifdef SAMBA4_USES_HEIMDAL ret = kerberos_kinit_s4u2_cc( smb_krb5_context->krb5_context, ccache, princ, password, impersonate_principal, self_service, target_service, krb_options, NULL, &kdc_time); #else talloc_free(mem_ctx); (*error_string) = "INTERNAL error: s4u2 ops " "are not supported with MIT build yet"; return EINVAL; #endif } else { ret = kerberos_kinit_password_cc( smb_krb5_context->krb5_context, ccache, princ, password, target_service, krb_options, NULL, &kdc_time); } } else if (impersonate_principal) { talloc_free(mem_ctx); (*error_string) = "INTERNAL error: Cannot impersonate principal with just a keyblock. A password must be specified in the credentials"; return EINVAL; } else { /* No password available, try to use a keyblock instead */ krb5_keyblock keyblock; const struct samr_Password *mach_pwd; mach_pwd = cli_credentials_get_nt_hash(credentials, mem_ctx); if (!mach_pwd) { talloc_free(mem_ctx); (*error_string) = "kinit_to_ccache: No password available for kinit\n"; krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, krb_options); #ifdef SAMBA4_USES_HEIMDAL smb_krb5_context_remove_event_ctx(smb_krb5_context, previous_ev, event_ctx); #endif return EINVAL; } ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, mach_pwd->hash, sizeof(mach_pwd->hash), &keyblock); if (ret == 0) { ret = kerberos_kinit_keyblock_cc(smb_krb5_context->krb5_context, ccache, princ, &keyblock, target_service, krb_options, NULL, &kdc_time); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &keyblock); } } #ifdef SAMBA4_USES_HEIMDAL smb_krb5_context_remove_event_ctx(smb_krb5_context, previous_ev, event_ctx); #endif if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) { /* Perhaps we have been given an invalid skew, so try again without it */ time_t t = time(NULL); krb5_set_real_time(smb_krb5_context->krb5_context, t, 0); } else { /* not a skew problem */ break; } } krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, krb_options); if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) { (*error_string) = talloc_asprintf(credentials, "kinit for %s failed (%s)\n", cli_credentials_get_principal(credentials, mem_ctx), smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)); talloc_free(mem_ctx); return ret; } /* cope with ticket being in the future due to clock skew */ if ((unsigned)kdc_time > time(NULL)) { time_t t = time(NULL); int time_offset =(unsigned)kdc_time-t; DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset)); krb5_set_real_time(smb_krb5_context->krb5_context, t + time_offset + 1, 0); } if (ret == KRB5KDC_ERR_PREAUTH_FAILED && cli_credentials_wrong_password(credentials)) { ret = kinit_to_ccache(parent_ctx, credentials, smb_krb5_context, event_ctx, ccache, obtained, error_string); } if (ret) { (*error_string) = talloc_asprintf(credentials, "kinit for %s failed (%s)\n", cli_credentials_get_principal(credentials, mem_ctx), smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)); talloc_free(mem_ctx); return ret; } DEBUG(10,("kinit for %s succeeded\n", cli_credentials_get_principal(credentials, mem_ctx))); talloc_free(mem_ctx); return 0; }
static krb5_error_code get_init_creds_common(krb5_context context, krb5_principal client, krb5_deltat start_time, krb5_get_init_creds_opt *options, krb5_init_creds_context ctx) { krb5_get_init_creds_opt *default_opt = NULL; krb5_error_code ret; krb5_enctype *etypes; krb5_preauthtype *pre_auth_types; memset(ctx, 0, sizeof(*ctx)); if (options == NULL) { const char *realm = krb5_principal_get_realm(context, client); krb5_get_init_creds_opt_alloc (context, &default_opt); options = default_opt; krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options); } if (options->opt_private) { if (options->opt_private->password) { ret = krb5_init_creds_set_password(context, ctx, options->opt_private->password); if (ret) goto out; } ctx->keyproc = options->opt_private->key_proc; ctx->req_pac = options->opt_private->req_pac; ctx->pk_init_ctx = options->opt_private->pk_init_ctx; ctx->ic_flags = options->opt_private->flags; } else ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET; if (ctx->keyproc == NULL) ctx->keyproc = default_s2k_func; /* Enterprise name implicitly turns on canonicalize */ if ((ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) || krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL) ctx->flags.canonicalize = 1; ctx->pre_auth_types = NULL; ctx->addrs = NULL; ctx->etypes = NULL; ctx->pre_auth_types = NULL; ret = init_cred(context, &ctx->cred, client, start_time, options); if (ret) { if (default_opt) krb5_get_init_creds_opt_free(context, default_opt); return ret; } ret = krb5_init_creds_set_service(context, ctx, NULL); if (ret) goto out; if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE) ctx->flags.forwardable = options->forwardable; if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE) ctx->flags.proxiable = options->proxiable; if (start_time) ctx->flags.postdated = 1; if (ctx->cred.times.renew_till) ctx->flags.renewable = 1; if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) { ctx->addrs = options->address_list; } else if (options->opt_private) { switch (options->opt_private->addressless) { case KRB5_INIT_CREDS_TRISTATE_UNSET: #if KRB5_ADDRESSLESS_DEFAULT == TRUE ctx->addrs = &no_addrs; #else ctx->addrs = NULL; #endif break; case KRB5_INIT_CREDS_TRISTATE_FALSE: ctx->addrs = NULL; break; case KRB5_INIT_CREDS_TRISTATE_TRUE: ctx->addrs = &no_addrs; break; } } if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) { etypes = malloc((options->etype_list_length + 1) * sizeof(krb5_enctype)); if (etypes == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out; } memcpy (etypes, options->etype_list, options->etype_list_length * sizeof(krb5_enctype)); etypes[options->etype_list_length] = ETYPE_NULL; ctx->etypes = etypes; } if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) { pre_auth_types = malloc((options->preauth_list_length + 1) * sizeof(krb5_preauthtype)); if (pre_auth_types == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out; } memcpy (pre_auth_types, options->preauth_list, options->preauth_list_length * sizeof(krb5_preauthtype)); pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE; ctx->pre_auth_types = pre_auth_types; } if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) ctx->flags.request_anonymous = options->anonymous; if (default_opt) krb5_get_init_creds_opt_free(context, default_opt); return 0; out: if (default_opt) krb5_get_init_creds_opt_free(context, default_opt); 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; krb5_init_creds_context icc; krb5_keytab kt = NULL; int will_use_keytab = (use_keytab || keytab_str); krb5_prompter_fct prompter = NULL; int need_prompt; 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'; } #if defined(__APPLE__) && !defined(__APPLE_TARGET_EMBEDDED__) if (passwd[0] == '\0' && !will_use_keytab && home_directory_flag) { 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, (UInt32)strlen(realm), realm, (UInt32)strlen(name), name, &length, &buffer, &passwordItem); free(name); if (osret != noErr) goto nopassword; if (length < sizeof(passwd) - 1) { memcpy(passwd, buffer, length); passwd[length] = '\0'; } SecKeychainItemFreeContent(NULL, buffer); nopassword: do { } while(0); } #endif need_prompt = !(pk_user_id || ent_user_id || anonymous_flag || will_use_keytab || passwd[0] != '\0') && interactive; if (need_prompt) prompter = krb5_prompter_posix; else prompter = krb5_prompter_print_only; 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, interactive ? krb5_prompter_posix : krb5_prompter_print_only, 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_cert(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) krb5_err(context, 1, ret, "unrecognized enctype: %s", etype_str.strings[i]); } krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); } ret = krb5_init_creds_init(context, principal, prompter, NULL, start_time, opt, &icc); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_init"); if (server_str) { ret = krb5_init_creds_set_service(context, icc, server_str); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_set_service"); } if (kdc_hostname) krb5_init_creds_set_kdc_hostname(context, icc, kdc_hostname); if (fast_armor_cache_string) { krb5_ccache fastid; ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); if (ret) krb5_err(context, 1, ret, "krb5_cc_resolve(FAST cache)"); ret = krb5_init_creds_set_fast_ccache(context, icc, fastid); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_fast_ccache"); } if(will_use_keytab) { 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_init_creds_set_keytab(context, icc, kt); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_set_keytab"); } if (passwd[0] == '\0' && need_prompt) { 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)); errx(1, "failed to read password"); } free (prompt); } if (passwd[0]) { ret = krb5_init_creds_set_password(context, icc, passwd); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_password"); } ret = krb5_init_creds_get(context, icc); #ifdef __APPLE__ /* * Save password in Keychain */ if (ret == 0 && keychain_flag && passwordItem == NULL) { krb5_error_code ret2; const char *realm; char *name; realm = krb5_principal_get_realm(context, principal); ret2 = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret2 == 0) { (void)SecKeychainAddGenericPassword(NULL, (UInt32)strlen(realm), realm, (UInt32)strlen(name), name, (UInt32)strlen(passwd), passwd, NULL); free(name); } } #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: case KRB5_GET_IN_TKT_LOOP: #ifdef __APPLE__ if (passwordItem) SecKeychainItemDelete(passwordItem); #endif krb5_errx(context, 1, N_("Password incorrect", "")); case KRB5KRB_AP_ERR_V4_REPLY: krb5_errx(context, 1, N_("Looks like a Kerberos 4 reply", "")); case KRB5KDC_ERR_KEY_EXPIRED: krb5_errx(context, 1, N_("Password expired", "")); default: krb5_err(context, 1, ret, "krb5_get_init_creds"); } ret = krb5_init_creds_get_creds(context, icc, &cred); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_get_creds"); krb5_process_last_request(context, opt, icc); 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_init_creds_store(context, icc, tempccache); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_store"); ret = krb5_init_creds_store_config(context, icc, tempccache); if (ret) krb5_warn(context, ret, "krb5_init_creds_store_config"); ret = krb5_init_creds_warn_user(context, icc); if (ret) krb5_warn(context, ret, "krb5_init_creds_warn_user"); #ifdef __APPLE__ /* * Set for this case, default to * so that all processes can use * this cache. */ { heim_array_t bundleacl = heim_array_create(); heim_string_t ace; if (bundle_acl_strings.num_strings > 0) { int i; for (i = 0; i < bundle_acl_strings.num_strings; i++) { ace = heim_string_create(bundle_acl_strings.strings[i]); heim_array_append_value(bundleacl, ace); heim_release(ace); } } else { ace = heim_string_create("*"); heim_array_append_value(bundleacl, ace); heim_release(ace); } krb5_cc_set_acl(context, tempccache, "kHEIMAttrBundleIdentifierACL", bundleacl); heim_release(bundleacl); } #endif ret = krb5_cc_move(context, tempccache, ccache); if (ret) { (void)krb5_cc_destroy(context, tempccache); krb5_err (context, 1, ret, "krb5_cc_move"); } if (switch_cache_flags) krb5_cc_switch(context, ccache); 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); krb5_init_creds_free(context, icc); krb5_get_init_creds_opt_free(context, opt); if (kt) krb5_kt_close(context, kt); #ifdef __APPLE__ if (passwordItem) CFRelease(passwordItem); #endif return 0; }
/* * Given the plugin options, a Kerberos context, and a pointer to krb5_ccache * storage, initialize a memory cache using the configured keytab to obtain * initial credentials. Returns a Kerberos status code. */ static krb5_error_code get_creds(kadm5_hook_modinfo *config, krb5_context ctx, krb5_ccache *cc) { krb5_error_code code; krb5_keytab kt = NULL; krb5_principal princ = NULL; krb5_get_init_creds_opt *opts = NULL; krb5_creds creds; bool creds_valid = false; const char *realm UNUSED; /* Initialize the credential cache pointer to NULL. */ *cc = NULL; /* Ensure the configuration is sane. */ CHECK_CONFIG(ad_keytab); CHECK_CONFIG(ad_principal); /* Resolve the keytab and principal used to get credentials. */ code = krb5_kt_resolve(ctx, config->ad_keytab, &kt); if (code != 0) goto fail; code = krb5_parse_name(ctx, config->ad_principal, &princ); if (code != 0) goto fail; /* Set our credential acquisition options. */ code = krb5_get_init_creds_opt_alloc(ctx, &opts); if (code != 0) goto fail; realm = krb5_principal_get_realm(ctx, princ); krb5_get_init_creds_opt_set_default_flags(ctx, "krb5-sync", realm, opts); /* Obtain credentials. */ memset(&creds, 0, sizeof(creds)); code = krb5_get_init_creds_keytab(ctx, &creds, princ, kt, 0, NULL, opts); if (code != 0) goto fail; krb5_get_init_creds_opt_free(ctx, opts); opts = NULL; krb5_kt_close(ctx, kt); kt = NULL; creds_valid = true; /* Open and initialize the credential cache. */ code = krb5_cc_resolve(ctx, CACHE_NAME, cc); if (code != 0) goto fail; code = krb5_cc_initialize(ctx, *cc, princ); if (code == 0) code = krb5_cc_store_cred(ctx, *cc, &creds); if (code != 0) { krb5_cc_close(ctx, *cc); *cc = NULL; goto fail; } /* Clean up and return success. */ krb5_free_cred_contents(ctx, &creds); krb5_free_principal(ctx, princ); return 0; fail: if (kt != NULL) krb5_kt_close(ctx, kt); if (princ != NULL) krb5_free_principal(ctx, princ); if (opts != NULL) krb5_get_init_creds_opt_free(ctx, opts); if (creds_valid) krb5_free_cred_contents(ctx, &creds); return code; }
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; char *renewstr = NULL; krb5_enctype *enctype = NULL; struct ntlm_buf ntlmkey; krb5_ccache tempccache; memset(&ntlmkey, 0, sizeof(ntlmkey)); 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'; } 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 != -1) 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_user_id) { ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, pk_x509_anchors, NULL, NULL, pk_use_enckey ? 2 : 0, krb5_prompter_posix, NULL, passwd); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_pkinit"); } 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) { 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); if (ntlm_domain && passwd[0]) heim_ntlm_nt_key(passwd, &ntlmkey); 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 (ntlm_domain && ntlmkey.data) store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey); 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; }