static E2kKerberosResult get_init_cred (krb5_context ctx, const char *usr_name, const char *passwd, const char *in_tkt_service, krb5_creds *cred) { krb5_principal principal; krb5_get_init_creds_opt opt; krb5_error_code result; result = krb5_parse_name (ctx, usr_name, &principal); if (result) return E2K_KERBEROS_USER_UNKNOWN; krb5_get_init_creds_opt_init (&opt); krb5_get_init_creds_opt_set_tkt_life (&opt, 5*60); krb5_get_init_creds_opt_set_renew_life (&opt, 0); krb5_get_init_creds_opt_set_forwardable (&opt, 0); krb5_get_init_creds_opt_set_proxiable (&opt, 0); result = krb5_get_init_creds_password (ctx, cred, principal, (char *) passwd, NULL, NULL, 0, (char *) in_tkt_service, &opt); krb5_free_principal (ctx, principal); return krb5_result_to_e2k_kerberos_result (result); }
static PyObject * k5_change_password(PyObject *self, PyObject *args) { int result_code; char *name, *oldpass, *newpass; krb5_context ctx; krb5_error_code code; krb5_principal principal; krb5_get_init_creds_opt options; krb5_creds creds; krb5_data result_code_string, result_string; if (!PyArg_ParseTuple(args, "sss", &name, &oldpass, &newpass)) 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); /* Get credentials using the password. */ krb5_get_init_creds_opt_init(&options); krb5_get_init_creds_opt_set_tkt_life(&options, 5*60); krb5_get_init_creds_opt_set_renew_life(&options, 0); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); memset(&creds, 0, sizeof (creds)); code = krb5_get_init_creds_password(ctx, &creds, principal, oldpass, NULL, NULL, 0, "kadmin/changepw", &options); RETURN_ON_ERROR("krb5_get_init_creds_password()", code); code = krb5_change_password(ctx, &creds, newpass, &result_code, &result_code_string, &result_string); RETURN_ON_ERROR("krb5_change_password()", code); /* Any other error? */ if (result_code != 0) { _k5_set_password_error(&result_code_string, &result_string); return NULL; } /* Free up results. */ if (result_code_string.data != NULL) free(result_code_string.data); if (result_string.data != NULL) free(result_string.data); Py_INCREF(Py_None); return Py_None; }
KRB5_LIB_FUNCTION void KRB5_LIB_CALL krb5_get_init_creds_opt_set_default_flags(krb5_context context, const char *appname, krb5_const_realm realm, krb5_get_init_creds_opt *opt) { krb5_boolean b; time_t t; b = get_config_bool (context, KRB5_FORWARDABLE_DEFAULT, realm, "forwardable"); krb5_appdefault_boolean(context, appname, realm, "forwardable", b, &b); krb5_get_init_creds_opt_set_forwardable(opt, b); b = get_config_bool (context, FALSE, realm, "proxiable"); krb5_appdefault_boolean(context, appname, realm, "proxiable", b, &b); krb5_get_init_creds_opt_set_proxiable (opt, b); krb5_appdefault_time(context, appname, realm, "ticket_lifetime", 0, &t); if (t == 0) t = get_config_time (context, realm, "ticket_lifetime", 0); if(t != 0) krb5_get_init_creds_opt_set_tkt_life(opt, t); krb5_appdefault_time(context, appname, realm, "renew_lifetime", 0, &t); if (t == 0) t = get_config_time (context, realm, "renew_lifetime", 0); if(t != 0) krb5_get_init_creds_opt_set_renew_life(opt, t); krb5_appdefault_boolean(context, appname, realm, "no-addresses", KRB5_ADDRESSLESS_DEFAULT, &b); krb5_get_init_creds_opt_set_addressless (context, opt, b); #if 0 krb5_appdefault_boolean(context, appname, realm, "anonymous", FALSE, &b); krb5_get_init_creds_opt_set_anonymous (opt, b); krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt, krb5_data *salt); krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt, krb5_preauthtype *preauth_list, int preauth_list_length); #endif }
krb5_get_init_creds_opt *kim_options_init_cred_options (kim_options in_options) { kim_error err = KIM_NO_ERROR; krb5_address **addresses = NULL; if (!err && !in_options) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && !in_options->init_cred_context) { err = krb5_error (NULL, krb5_init_context (&in_options->init_cred_context)); } if (!err && !in_options->addressless) { err = krb5_error (in_options->init_cred_context, krb5_os_localaddr (in_options->init_cred_context, &addresses)); } if (!err && !in_options->init_cred_options) { err = krb5_error (in_options->init_cred_context, krb5_get_init_creds_opt_alloc (in_options->init_cred_context, &in_options->init_cred_options)); } if (!err) { krb5_get_init_creds_opt_set_tkt_life (in_options->init_cred_options, in_options->lifetime); if (in_options->renewal_lifetime || in_options->renewable) krb5_get_init_creds_opt_set_renew_life (in_options->init_cred_options, in_options->renewal_lifetime); krb5_get_init_creds_opt_set_forwardable (in_options->init_cred_options, in_options->forwardable); krb5_get_init_creds_opt_set_proxiable (in_options->init_cred_options, in_options->proxiable); krb5_get_init_creds_opt_set_address_list (in_options->init_cred_options, addresses); addresses = NULL; } if (addresses) { krb5_free_addresses (in_options->init_cred_context, addresses); } return !check_error (err) ? in_options->init_cred_options : NULL; }
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; }
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 int32_t acquire_cred(struct client *c, krb5_principal principal, krb5_get_init_creds_opt *opt, int32_t *handle) { krb5_error_code ret; krb5_creds cred; krb5_ccache id; gss_cred_id_t gcred; OM_uint32 maj_stat, min_stat; *handle = 0; krb5_get_init_creds_opt_set_forwardable (opt, 1); krb5_get_init_creds_opt_set_renew_life (opt, 3600 * 24 * 30); memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_password (context, &cred, principal, NULL, NULL, NULL, 0, NULL, opt); if (ret) { logmessage(c, __FILE__, __LINE__, 0, "krb5_get_init_creds failed: %d", ret); return convert_krb5_to_gsm(ret); } ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id); if (ret) krb5_err (context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_initialize (context, id, cred.client); if (ret) krb5_err (context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_store_cred (context, id, &cred); if (ret) krb5_err (context, 1, ret, "krb5_cc_store_cred"); krb5_free_cred_contents (context, &cred); maj_stat = gss_krb5_import_cred(&min_stat, id, NULL, NULL, &gcred); krb5_cc_close(context, id); if (maj_stat) { logmessage(c, __FILE__, __LINE__, 0, "krb5 import creds failed with: %d", maj_stat); return convert_gss_to_gsm(maj_stat); } *handle = add_handle(c, handle_cred, gcred); return 0; }
/* 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; }
static ADS_STATUS ads_krb5_chg_password(const char *kdc_host, const char *principal, const char *oldpw, const char *newpw, int time_offset) { ADS_STATUS aret; krb5_error_code ret; krb5_context context = NULL; krb5_principal princ; krb5_get_init_creds_opt opts; krb5_creds creds; char *chpw_princ = NULL, *password; const char *realm = NULL; initialize_krb5_error_table(); ret = krb5_init_context(&context); if (ret) { DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret))); return ADS_ERROR_KRB5(ret); } if ((ret = smb_krb5_parse_name(context, principal, &princ))) { krb5_free_context(context); DEBUG(1,("Failed to parse %s (%s)\n", principal, error_message(ret))); return ADS_ERROR_KRB5(ret); } krb5_get_init_creds_opt_init(&opts); krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60); krb5_get_init_creds_opt_set_renew_life(&opts, 0); krb5_get_init_creds_opt_set_forwardable(&opts, 0); krb5_get_init_creds_opt_set_proxiable(&opts, 0); realm = smb_krb5_principal_get_realm(context, princ); /* We have to obtain an INITIAL changepw ticket for changing password */ if (asprintf(&chpw_princ, "kadmin/changepw@%s", realm) == -1) { krb5_free_context(context); DEBUG(1,("ads_krb5_chg_password: asprintf fail\n")); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } password = SMB_STRDUP(oldpw); ret = krb5_get_init_creds_password(context, &creds, princ, password, kerb_prompter, NULL, 0, chpw_princ, &opts); SAFE_FREE(chpw_princ); SAFE_FREE(password); if (ret) { if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) DEBUG(1,("Password incorrect while getting initial ticket")); else DEBUG(1,("krb5_get_init_creds_password failed (%s)\n", error_message(ret))); krb5_free_principal(context, princ); krb5_free_context(context); return ADS_ERROR_KRB5(ret); } aret = do_krb5_kpasswd_request(context, kdc_host, KRB5_KPASSWD_VERS_CHANGEPW, &creds, principal, newpw); krb5_free_principal(context, princ); krb5_free_context(context); return aret; }
int cosign_login_krb5( struct connlist *head, char *cosignname, char *id, char *realm, char *passwd, char *ip_addr, char *cookie, struct subparams *sp, char **msg ) { krb5_error_code kerror = 0; krb5_context kcontext; krb5_principal kprinc; krb5_principal sprinc; krb5_get_init_creds_opt kopts; krb5_verify_init_creds_opt kvic_opts[ 1 ]; krb5_creds kcreds; krb5_ccache kccache; krb5_keytab keytab = 0; char *tmpl = ERROR_HTML; char *sprinc_name = NULL; char ktbuf[ MAX_KEYTAB_NAME_LEN + 1 ]; char tmpkrb[ 16 ], krbpath [ MAXPATHLEN ]; int i; lcgi_configure(); if (( kerror = krb5_init_context( &kcontext ))) { sl[ SL_ERROR ].sl_data = (char *)error_message( kerror ); sl[ SL_TITLE ].sl_data = "Authentication Required ( kerberos error )"; subfile( tmpl, sl, 0 ); exit( 0 ); } if (( kerror = krb5_parse_name( kcontext, id, &kprinc ))) { sl[ SL_ERROR ].sl_data = (char *)error_message( kerror ); sl[ SL_TITLE ].sl_data = "Authentication Required ( kerberos error )"; subfile( tmpl, sl, 0 ); exit( 0 ); } /* need to get realm out */ if ( realm == NULL || *realm == '\0' ) { if (( kerror = krb5_get_default_realm( kcontext, &realm )) != 0 ) { sl[ SL_ERROR ].sl_data = (char *)error_message( kerror ); sl[ SL_TITLE ].sl_data = "Authentication Required " "( krb realm error )"; subfile( tmpl, sl, 0 ); exit( 0 ); } } if ( store_tickets ) { if ( mkcookie( sizeof( tmpkrb ), tmpkrb ) != 0 ) { sl[ SL_ERROR ].sl_data = "An unknown error occurred."; sl[ SL_TITLE ].sl_data = "Authentication Required (kerberos error)"; subfile( tmpl, sl, 0 ); exit( 0 ); } if ( snprintf( krbpath, sizeof( krbpath ), "%s/%s", ticket_path, tmpkrb ) >= sizeof( krbpath )) { sl[ SL_ERROR ].sl_data = "An unknown error occurred."; sl[ SL_TITLE ].sl_data = "Authentication Required (krbpath error)"; subfile( tmpl, sl, 0 ); exit( 0 ); } if (( kerror = krb5_cc_resolve( kcontext, krbpath, &kccache )) != 0 ) { sl[ SL_ERROR ].sl_data = (char *)error_message( kerror ); sl[ SL_TITLE ].sl_data = "Authentication Required (kerberos error)"; subfile( tmpl, sl, 0 ); exit( 0 ); } } krb5_get_init_creds_opt_init( &kopts ); krb5_get_init_creds_opt_set_tkt_life( &kopts, tkt_life ); krb5_get_init_creds_opt_set_renew_life( &kopts, 0 ); krb5_get_init_creds_opt_set_forwardable( &kopts, 1 ); krb5_get_init_creds_opt_set_proxiable( &kopts, 0 ); if (( kerror = krb5_get_init_creds_password( kcontext, &kcreds, kprinc, passwd, NULL, NULL, 0, NULL /*keytab */, &kopts ))) { if (( kerror == KRB5KRB_AP_ERR_BAD_INTEGRITY ) || ( kerror == KRB5KDC_ERR_PREAUTH_FAILED ) || ( kerror == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN )) { return( COSIGN_CGI_ERROR ); /* draw login or reauth page */ } else if ( kerror == KRB5KDC_ERR_KEY_EXP ) { *msg = (char *)error_message( kerror ); return( COSIGN_CGI_PASSWORD_EXPIRED ); } else { sl[ SL_ERROR ].sl_data = (char *)error_message( kerror ); sl[ SL_TITLE ].sl_data = "Error"; subfile( tmpl, sl, 0 ); exit( 0 ); } } /* verify no KDC spoofing */ if ( *keytab_path != '\0' ) { if ( strlen( keytab_path ) > MAX_KEYTAB_NAME_LEN ) { sl[ SL_ERROR ].sl_data = "server configuration error"; sl[ SL_TITLE ].sl_data = "Ticket Verification Error"; subfile( tmpl, sl, 0 ); exit( 0 ); } strcpy( ktbuf, keytab_path ); /* from mdw */ krb5_verify_init_creds_opt_init( kvic_opts ); krb5_verify_init_creds_opt_set_ap_req_nofail( kvic_opts, 1 ); if (( kerror = krb5_kt_resolve( kcontext, ktbuf, &keytab )) != 0 ) { sl[ SL_ERROR ].sl_data = (char *)error_message( kerror ); sl[ SL_TITLE ].sl_data = "KT Resolve Error"; subfile( tmpl, sl, 0 ); exit( 0 ); } if ( cosign_princ ) { kerror = krb5_parse_name( kcontext, cosign_princ, &sprinc ); } else { kerror = krb5_sname_to_principal( kcontext, NULL, "cosign", KRB5_NT_SRV_HST, &sprinc ); } if ( kerror != 0 ) { sl[ SL_ERROR ].sl_data = (char *)error_message( kerror ); sl[ SL_TITLE ].sl_data = "Server Principal Error"; subfile( tmpl, sl, 0 ); exit( 0 ); } if (( kerror = krb5_verify_init_creds( kcontext, &kcreds, sprinc, keytab, NULL, kvic_opts )) != 0 ) { if ( krb5_unparse_name( kcontext, sprinc, &sprinc_name ) == 0 ) { fprintf( stderr, "ticket verify error for " "user %s, keytab principal %s", id, sprinc_name ); free( sprinc_name ); } else { fprintf( stderr, "ticket verify error for user %s", id ); } sl[ SL_ERROR ].sl_data = (char *)error_message( kerror ); sl[ SL_TITLE ].sl_data = "Ticket Verify Error"; subfile( tmpl, sl, 0 ); krb5_free_principal( kcontext, sprinc ); exit( 0 ); } (void)krb5_kt_close( kcontext, keytab ); krb5_free_principal( kcontext, sprinc ); } for ( i = 0; i < COSIGN_MAXFACTORS - 1; i++ ) { if ( new_factors[ i ] == NULL ) { new_factors[ i ] = strdup( realm ); new_factors[ i + 1 ] = NULL; break; } if ( strcmp( new_factors[ i ], realm ) == 0 ) { break; } } if ( sp->sp_reauth && sp->sp_ipchanged == 0 ) { return( COSIGN_CGI_OK ); } if ( store_tickets ) { if (( kerror = krb5_cc_initialize( kcontext, kccache, kprinc )) != 0 ) { sl[ SL_ERROR ].sl_data = (char *)error_message( kerror ); sl[ SL_TITLE ].sl_data = "CC Initialize Error"; subfile( tmpl, sl, 0 ); exit( 0 ); } if (( kerror = krb5_cc_store_cred( kcontext, kccache, &kcreds )) != 0 ) { sl[ SL_ERROR ].sl_data = (char *)error_message( kerror ); sl[ SL_TITLE ].sl_data = "CC Storing Error"; subfile( tmpl, sl, 0 ); exit( 0 ); } krb5_cc_close( kcontext, kccache ); } krb5_free_cred_contents( kcontext, &kcreds ); krb5_free_principal( kcontext, kprinc ); krb5_free_context( kcontext ); /* password has been accepted, tell cosignd */ if ( cosign_login( head, cookie, ip_addr, cosignname, realm, ( store_tickets ? krbpath : NULL )) < 0 ) { fprintf( stderr, "cosign_login_krb5: login failed\n") ; sl[ SL_ERROR ].sl_data = "We were unable to contact the " "authentication server. Please try again later."; sl[ SL_TITLE ].sl_data = "Error: Please try later"; subfile( tmpl, sl, 0 ); exit( 0 ); } return( COSIGN_CGI_OK ); }
krb5_error_code KRB5_CALLCONV krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_principal client, const char *password, krb5_prompter_fct prompter, void *data, krb5_deltat start_time, const char *in_tkt_service, krb5_get_init_creds_opt *options) { krb5_error_code ret, ret2; int use_master; krb5_kdc_rep *as_reply; int tries; krb5_creds chpw_creds; krb5_get_init_creds_opt *chpw_opts = NULL; krb5_data pw0, pw1; char banner[1024], pw0array[1024], pw1array[1024]; krb5_prompt prompt[2]; krb5_prompt_type prompt_types[sizeof(prompt)/sizeof(prompt[0])]; char *message; use_master = 0; as_reply = NULL; memset(&chpw_creds, 0, sizeof(chpw_creds)); pw0.data = pw0array; if (password && password[0]) { if (strlcpy(pw0.data, password, sizeof(pw0array)) >= sizeof(pw0array)) { ret = EINVAL; goto cleanup; } pw0.length = strlen(password); } else { pw0.data[0] = '\0'; pw0.length = sizeof(pw0array); } pw1.data = pw1array; pw1.data[0] = '\0'; pw1.length = sizeof(pw1array); /* first try: get the requested tkt from any kdc */ ret = krb5int_get_init_creds(context, creds, client, prompter, data, start_time, in_tkt_service, options, krb5_get_as_key_password, (void *) &pw0, &use_master, &as_reply); /* check for success */ if (ret == 0) goto cleanup; /* If all the kdc's are unavailable, or if the error was due to a user interrupt, fail */ if ((ret == KRB5_KDC_UNREACH) || (ret == KRB5_LIBOS_PWDINTR) || (ret == KRB5_REALM_CANT_RESOLVE)) goto cleanup; /* if the reply did not come from the master kdc, try again with the master kdc */ if (!use_master) { TRACE_GIC_PWD_MASTER(context); use_master = 1; if (as_reply) { krb5_free_kdc_rep( context, as_reply); as_reply = NULL; } ret2 = krb5int_get_init_creds(context, creds, client, prompter, data, start_time, in_tkt_service, options, krb5_get_as_key_password, (void *) &pw0, &use_master, &as_reply); if (ret2 == 0) { ret = 0; goto cleanup; } /* if the master is unreachable, return the error from the slave we were able to contact or reset the use_master flag */ if ((ret2 != KRB5_KDC_UNREACH) && (ret2 != KRB5_REALM_CANT_RESOLVE) && (ret2 != KRB5_REALM_UNKNOWN)) ret = ret2; else use_master = 0; } /* at this point, we have an error from the master. if the error is not password expired, or if it is but there's no prompter, return this error */ if ((ret != KRB5KDC_ERR_KEY_EXP) || (prompter == NULL)) goto cleanup; /* historically the default has been to prompt for password change. * if the change password prompt option has not been set, we continue * to prompt. Prompting is only disabled if the option has been set * and the value has been set to false. */ if (options && !(options->flags & KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT)) goto cleanup; TRACE_GIC_PWD_EXPIRED(context); /* ok, we have an expired password. Give the user a few chances to change it */ /* use a minimal set of options */ ret = krb5_get_init_creds_opt_alloc(context, &chpw_opts); if (ret) goto cleanup; krb5_get_init_creds_opt_set_tkt_life(chpw_opts, 5*60); krb5_get_init_creds_opt_set_renew_life(chpw_opts, 0); krb5_get_init_creds_opt_set_forwardable(chpw_opts, 0); krb5_get_init_creds_opt_set_proxiable(chpw_opts, 0); if ((ret = krb5int_get_init_creds(context, &chpw_creds, client, prompter, data, start_time, "kadmin/changepw", chpw_opts, krb5_get_as_key_password, (void *) &pw0, &use_master, NULL))) goto cleanup; prompt[0].prompt = _("Enter new password"); prompt[0].hidden = 1; prompt[0].reply = &pw0; prompt_types[0] = KRB5_PROMPT_TYPE_NEW_PASSWORD; prompt[1].prompt = _("Enter it again"); prompt[1].hidden = 1; prompt[1].reply = &pw1; prompt_types[1] = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN; strlcpy(banner, _("Password expired. You must change it now."), sizeof(banner)); for (tries = 3; tries; tries--) { TRACE_GIC_PWD_CHANGEPW(context, tries); pw0.length = sizeof(pw0array); pw1.length = sizeof(pw1array); /* PROMPTER_INVOCATION */ krb5int_set_prompt_types(context, prompt_types); ret = (*prompter)(context, data, 0, banner, sizeof(prompt)/sizeof(prompt[0]), prompt); krb5int_set_prompt_types(context, 0); if (ret) goto cleanup; if (strcmp(pw0.data, pw1.data) != 0) { ret = KRB5_LIBOS_BADPWDMATCH; snprintf(banner, sizeof(banner), _("%s. Please try again."), error_message(ret)); } else if (pw0.length == 0) { ret = KRB5_CHPW_PWDNULL; snprintf(banner, sizeof(banner), _("%s. Please try again."), error_message(ret)); } else { int result_code; krb5_data code_string; krb5_data result_string; if ((ret = krb5_change_password(context, &chpw_creds, pw0array, &result_code, &code_string, &result_string))) goto cleanup; /* the change succeeded. go on */ if (result_code == 0) { free(result_string.data); break; } /* set this in case the retry loop falls through */ ret = KRB5_CHPW_FAIL; if (result_code != KRB5_KPASSWD_SOFTERROR) { free(result_string.data); goto cleanup; } /* the error was soft, so try again */ if (krb5_chpw_message(context, &result_string, &message) != 0) message = NULL; /* 100 is I happen to know that no code_string will be longer than 100 chars */ if (message != NULL && strlen(message) > (sizeof(banner) - 100)) message[sizeof(banner) - 100] = '\0'; snprintf(banner, sizeof(banner), _("%.*s%s%s. Please try again.\n"), (int) code_string.length, code_string.data, message ? ": " : "", message ? message : ""); free(message); free(code_string.data); free(result_string.data); } } if (ret) goto cleanup; /* the password change was successful. Get an initial ticket from the master. this is the last try. the return from this is final. */ TRACE_GIC_PWD_CHANGED(context); ret = krb5int_get_init_creds(context, creds, client, prompter, data, start_time, in_tkt_service, options, krb5_get_as_key_password, (void *) &pw0, &use_master, &as_reply); if (ret) goto cleanup; cleanup: if (ret == 0) warn_pw_expiry(context, options, prompter, data, in_tkt_service, as_reply); if (chpw_opts) krb5_get_init_creds_opt_free(context, chpw_opts); memset(pw0array, 0, sizeof(pw0array)); memset(pw1array, 0, sizeof(pw1array)); krb5_free_cred_contents(context, &chpw_creds); if (as_reply) krb5_free_kdc_rep(context, as_reply); return(ret); }
static ADS_STATUS ads_krb5_chg_password(const char *kdc_host, const char *principal, const char *oldpw, const char *newpw, int time_offset) { ADS_STATUS aret; krb5_error_code ret; krb5_context context = NULL; krb5_principal princ; krb5_get_init_creds_opt opts; krb5_creds creds; char *chpw_princ = NULL, *password; char *realm = NULL; int result_code; krb5_data result_code_string = { 0 }; krb5_data result_string = { 0 }; smb_krb5_addresses *addr = NULL; initialize_krb5_error_table(); ret = krb5_init_context(&context); if (ret) { DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret))); return ADS_ERROR_KRB5(ret); } if ((ret = smb_krb5_parse_name(context, principal, &princ))) { krb5_free_context(context); DEBUG(1,("Failed to parse %s (%s)\n", principal, error_message(ret))); return ADS_ERROR_KRB5(ret); } krb5_get_init_creds_opt_init(&opts); krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60); krb5_get_init_creds_opt_set_renew_life(&opts, 0); krb5_get_init_creds_opt_set_forwardable(&opts, 0); krb5_get_init_creds_opt_set_proxiable(&opts, 0); /* note that heimdal will fill in the local addresses if the addresses * in the creds_init_opt are all empty and then later fail with invalid * address, sending our local netbios krb5 address - just like windows * - avoids this - gd */ ret = smb_krb5_gen_netbios_krb5_address(&addr, lp_netbios_name()); if (ret) { krb5_free_principal(context, princ); krb5_free_context(context); return ADS_ERROR_KRB5(ret); } krb5_get_init_creds_opt_set_address_list(&opts, addr->addrs); realm = smb_krb5_principal_get_realm(context, princ); /* We have to obtain an INITIAL changepw ticket for changing password */ if (asprintf(&chpw_princ, "kadmin/changepw@%s", realm) == -1) { krb5_free_context(context); free(realm); DEBUG(1,("ads_krb5_chg_password: asprintf fail\n")); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } free(realm); password = SMB_STRDUP(oldpw); ret = krb5_get_init_creds_password(context, &creds, princ, password, kerb_prompter, NULL, 0, chpw_princ, &opts); SAFE_FREE(chpw_princ); SAFE_FREE(password); if (ret) { if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) DEBUG(1,("Password incorrect while getting initial ticket")); else DEBUG(1,("krb5_get_init_creds_password failed (%s)\n", error_message(ret))); krb5_free_principal(context, princ); krb5_free_context(context); return ADS_ERROR_KRB5(ret); } ret = krb5_change_password(context, &creds, discard_const_p(char, newpw), &result_code, &result_code_string, &result_string); if (ret) { DEBUG(1, ("krb5_change_password failed (%s)\n", error_message(ret))); aret = ADS_ERROR_KRB5(ret); goto done; } if (result_code != KRB5_KPASSWD_SUCCESS) { ret = kpasswd_err_to_krb5_err(result_code); DEBUG(1, ("krb5_change_password failed (%s)\n", error_message(ret))); aret = ADS_ERROR_KRB5(ret); goto done; } aret = ADS_SUCCESS; done: kerberos_free_data_contents(context, &result_code_string); kerberos_free_data_contents(context, &result_string); krb5_free_principal(context, princ); krb5_free_context(context); return aret; }
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; }
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; }