OM_uint32 _gsskrb5_appl_change_password(OM_uint32 *minor_status, gss_name_t name, const char *oldpw, const char *newpw) { krb5_data result_code_string, result_string; krb5_get_init_creds_opt *opt = NULL; krb5_context context; krb5_principal principal = (krb5_principal)name; krb5_creds kcred; krb5_error_code ret; int result_code; GSSAPI_KRB5_INIT (&context); memset(&kcred, 0, sizeof(kcred)); ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) goto out; krb5_get_init_creds_opt_set_tkt_life(opt, 300); krb5_get_init_creds_opt_set_forwardable(opt, FALSE); krb5_get_init_creds_opt_set_proxiable(opt, FALSE); ret = krb5_get_init_creds_password(context, &kcred, principal, oldpw, NULL, NULL, 0, "kadmin/changepw", opt); if (ret) goto out; ret = krb5_set_password(context, &kcred, newpw, NULL, &result_code, &result_code_string, &result_string); if (ret) goto out; krb5_data_free(&result_string); krb5_data_free(&result_code_string); if (result_code) { krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY, "Failed to change invalid password: %d", result_code); ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; goto out; } out: if (opt) krb5_get_init_creds_opt_free(context, opt); krb5_free_cred_contents(context, &kcred); *minor_status = ret; return ret ? GSS_S_FAILURE : GSS_S_COMPLETE; }
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); }
/* * 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; }
/* call-seq: * krb5.get_init_creds_keytab(principal = nil, keytab = nil, service = nil, ccache = nil) * * Acquire credentials for +principal+ from +keytab+ using +service+. If * no principal is specified, then a principal is derived from the service * name. If no service name is specified, kerberos defaults to "host". * * If no keytab file is provided, the default keytab file is used. This is * typically /etc/krb5.keytab. * * If +ccache+ is supplied and is a Kerberos::Krb5::CredentialsCache, the * resulting credentials will be stored in the credential cache. */ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){ RUBY_KRB5* ptr; VALUE v_user, v_keytab_name, v_service, v_ccache; char* user; char* service; char keytab_name[MAX_KEYTAB_NAME_LEN]; krb5_error_code kerror; krb5_get_init_creds_opt* opt; krb5_creds cred; Data_Get_Struct(self, RUBY_KRB5, ptr); if(!ptr->ctx) rb_raise(cKrb5Exception, "no context has been established"); kerror = krb5_get_init_creds_opt_alloc(ptr->ctx, &opt); if(kerror) rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_alloc: %s", error_message(kerror)); rb_scan_args(argc, argv, "04", &v_user, &v_keytab_name, &v_service, &v_ccache); // We need the service information for later. if(NIL_P(v_service)){ service = NULL; } else{ Check_Type(v_service, T_STRING); service = StringValuePtr(v_service); } // Convert the name (or service name) to a kerberos principal. if(NIL_P(v_user)){ kerror = krb5_sname_to_principal( ptr->ctx, NULL, service, KRB5_NT_SRV_HST, &ptr->princ ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_sname_to_principal: %s", error_message(kerror)); } } else{ Check_Type(v_user, T_STRING); user = StringValuePtr(v_user); kerror = krb5_parse_name(ptr->ctx, user, &ptr->princ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror)); } } // Use the default keytab if none is specified. if(NIL_P(v_keytab_name)){ kerror = krb5_kt_default_name(ptr->ctx, keytab_name, MAX_KEYTAB_NAME_LEN); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_kt_default_name: %s", error_message(kerror)); } } else{ Check_Type(v_keytab_name, T_STRING); strncpy(keytab_name, StringValuePtr(v_keytab_name), MAX_KEYTAB_NAME_LEN); } kerror = krb5_kt_resolve( ptr->ctx, keytab_name, &ptr->keytab ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_kt_resolve: %s", error_message(kerror)); } // Set the credential cache from the supplied Kerberos::Krb5::CredentialsCache if(!NIL_P(v_ccache)){ RUBY_KRB5_CCACHE* ccptr; Data_Get_Struct(v_ccache, RUBY_KRB5_CCACHE, ccptr); kerror = krb5_get_init_creds_opt_set_out_ccache(ptr->ctx, opt, ccptr->ccache); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_set_out_ccache: %s", error_message(kerror)); } } kerror = krb5_get_init_creds_keytab( ptr->ctx, &cred, ptr->princ, ptr->keytab, 0, service, opt ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_get_init_creds_keytab: %s", error_message(kerror)); } krb5_get_init_creds_opt_free(ptr->ctx, opt); return self; }
static krb5_error_code login_perform_kinit (krb5_context k5, const gchar *realm, const gchar *login, const gchar *password, const gchar *filename) { krb5_get_init_creds_opt *opts; krb5_error_code code; krb5_principal principal; krb5_ccache ccache; krb5_creds creds; gchar *name; name = g_strdup_printf ("%s@%s", login, realm); code = krb5_parse_name (k5, name, &principal); if (code != 0) { g_debug ("Couldn't parse principal name: %s: %s", name, krb5_get_error_message (k5, code)); g_free (name); return code; } g_debug ("Using principal name to kinit: %s", name); g_free (name); if (filename == NULL) code = krb5_cc_default (k5, &ccache); else code = krb5_cc_resolve (k5, filename, &ccache); if (code != 0) { krb5_free_principal (k5, principal); g_debug ("Couldn't open credential cache: %s: %s", filename ? filename : "<default>", krb5_get_error_message (k5, code)); return code; } code = krb5_get_init_creds_opt_alloc (k5, &opts); g_return_val_if_fail (code == 0, code); code = krb5_get_init_creds_opt_set_out_ccache (k5, opts, ccache); g_return_val_if_fail (code == 0, code); code = krb5_get_init_creds_password (k5, &creds, principal, (char *)password, NULL, 0, 0, NULL, opts); krb5_get_init_creds_opt_free (k5, opts); krb5_cc_close (k5, ccache); krb5_free_principal (k5, principal); if (code == 0) { g_debug ("kinit succeeded"); krb5_free_cred_contents (k5, &creds); } else { g_debug ("kinit failed: %s", krb5_get_error_message (k5, code)); } 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; const char *renewstr = NULL; krb5_enctype *enctype = NULL; krb5_ccache tempccache; krb5_keytab kt = NULL; krb5_init_creds_context ctx; #ifndef NO_NTLM struct ntlm_buf ntlmkey; memset(&ntlmkey, 0, sizeof(ntlmkey)); #endif passwd[0] = '\0'; if (password_file) { FILE *f; if (strcasecmp("STDIN", password_file) == 0) f = stdin; else f = fopen(password_file, "r"); if (f == NULL) krb5_errx(context, 1, "Failed to open the password file %s", password_file); if (fgets(passwd, sizeof(passwd), f) == NULL) krb5_errx(context, 1, N_("Failed to read password from file %s", ""), password_file); if (f != stdin) fclose(f); passwd[strcspn(passwd, "\n")] = '\0'; } #ifdef __APPLE__ if (passwd[0] == '\0') { const char *realm; OSStatus osret; UInt32 length; void *buffer; char *name; realm = krb5_principal_get_realm(context, principal); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret) goto nopassword; osret = SecKeychainFindGenericPassword(NULL, strlen(realm), realm, strlen(name), name, &length, &buffer, NULL); free(name); if (osret == noErr && length < sizeof(passwd) - 1) { memcpy(passwd, buffer, length); passwd[length] = '\0'; } nopassword: do { } while(0); } #endif memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); krb5_get_init_creds_opt_set_default_flags(context, "kinit", krb5_principal_get_realm(context, principal), opt); if(forwardable_flag != -1) krb5_get_init_creds_opt_set_forwardable (opt, forwardable_flag); if(proxiable_flag != -1) krb5_get_init_creds_opt_set_proxiable (opt, proxiable_flag); if(anonymous_flag) krb5_get_init_creds_opt_set_anonymous (opt, anonymous_flag); if (pac_flag != -1) krb5_get_init_creds_opt_set_pac_request(context, opt, pac_flag ? TRUE : FALSE); if (canonicalize_flag) krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag) krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); if (pk_user_id || ent_user_id || anonymous_flag) { ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, pk_x509_anchors, NULL, NULL, pk_use_enckey ? 2 : 0 | anonymous_flag ? 4 : 0, krb5_prompter_posix, NULL, passwd); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_pkinit"); if (ent_user_id) krb5_get_init_creds_opt_set_pkinit_user_certs(context, opt, ent_user_id); } if (addrs_flag != -1) krb5_get_init_creds_opt_set_addressless(context, opt, addrs_flag ? FALSE : TRUE); if (renew_life == NULL && renewable_flag) renewstr = "1 month"; if (renew_life) renewstr = renew_life; if (renewstr) { renew = parse_time (renewstr, "s"); if (renew < 0) errx (1, "unparsable time: %s", renewstr); krb5_get_init_creds_opt_set_renew_life (opt, renew); } if(ticket_life != 0) krb5_get_init_creds_opt_set_tkt_life (opt, ticket_life); if(start_str) { int tmp = parse_time (start_str, "s"); if (tmp < 0) errx (1, N_("unparsable time: %s", ""), start_str); start_time = tmp; } if(etype_str.num_strings) { int i; enctype = malloc(etype_str.num_strings * sizeof(*enctype)); if(enctype == NULL) errx(1, "out of memory"); for(i = 0; i < etype_str.num_strings; i++) { ret = krb5_string_to_enctype(context, etype_str.strings[i], &enctype[i]); if(ret) errx(1, "unrecognized enctype: %s", etype_str.strings[i]); } krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); } ret = krb5_init_creds_init(context, principal, krb5_prompter_posix, NULL, start_time, opt, &ctx); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_init"); if (server_str) { ret = krb5_init_creds_set_service(context, ctx, server_str); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_service"); } 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, ctx, fastid); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_fast_ccache"); } if(use_keytab || keytab_str) { 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, ctx, kt); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_keytab"); } else if (pk_user_id || ent_user_id || anonymous_flag) { } 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)); errx(1, "failed to read password"); } free (prompt); } if (passwd[0]) { ret = krb5_init_creds_set_password(context, ctx, passwd); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_password"); } } 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: 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"); } krb5_process_last_request(context, opt, ctx); 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_init_creds_store(context, ctx, tempccache); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_store"); krb5_init_creds_free(context, ctx); ret = krb5_cc_move(context, tempccache, ccache); if (ret) krb5_err (context, 1, ret, "krb5_cc_move"); if (switch_cache_flags) krb5_cc_switch(context, ccache); #ifndef NO_NTLM if (ntlm_domain && ntlmkey.data) store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey); #endif if (ok_as_delegate_flag || windows_flag || use_referrals_flag) { unsigned char d = 0; krb5_data data; if (ok_as_delegate_flag || windows_flag) d |= 1; if (use_referrals_flag || windows_flag) d |= 2; data.length = 1; data.data = &d; krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); } krb5_get_init_creds_opt_free(context, opt); if (kt) krb5_kt_close(context, kt); if (enctype) free(enctype); return 0; }
static OM_uint32 acquire_initiator_cred (OM_uint32 * minor_status, krb5_context context, gss_const_OID credential_type, const void *credential_data, gss_const_name_t desired_name, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gsskrb5_cred handle ) { OM_uint32 ret; krb5_creds cred; krb5_principal def_princ; krb5_get_init_creds_opt *opt; krb5_ccache ccache; krb5_keytab keytab; krb5_error_code kret; keytab = NULL; ccache = NULL; def_princ = NULL; ret = GSS_S_FAILURE; memset(&cred, 0, sizeof(cred)); /* * If we have a preferred principal, lets try to find it in all * caches, otherwise, fall back to default cache, ignore all * errors while searching. */ if (credential_type != GSS_C_NO_OID && !gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { kret = KRB5_NOCREDS_SUPPLIED; /* XXX */ goto end; } if (handle->principal) { kret = krb5_cc_cache_match (context, handle->principal, &ccache); if (kret == 0) { ret = GSS_S_COMPLETE; goto found; } } if (ccache == NULL) { kret = krb5_cc_default(context, &ccache); if (kret) goto end; } kret = krb5_cc_get_principal(context, ccache, &def_princ); if (kret != 0) { /* we'll try to use a keytab below */ krb5_cc_close(context, ccache); def_princ = NULL; kret = 0; } else if (handle->principal == NULL) { kret = krb5_copy_principal(context, def_princ, &handle->principal); if (kret) goto end; } else if (handle->principal != NULL && krb5_principal_compare(context, handle->principal, def_princ) == FALSE) { krb5_free_principal(context, def_princ); def_princ = NULL; krb5_cc_close(context, ccache); ccache = NULL; } if (def_princ == NULL) { /* We have no existing credentials cache, * so attempt to get a TGT using a keytab. */ if (handle->principal == NULL) { kret = krb5_get_default_principal(context, &handle->principal); if (kret) goto end; } kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; if (credential_type != GSS_C_NO_OID && gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { gss_buffer_t password = (gss_buffer_t)credential_data; /* XXX are we requiring password to be NUL terminated? */ kret = krb5_get_init_creds_password(context, &cred, handle->principal, password->value, NULL, NULL, 0, NULL, opt); } else { kret = get_keytab(context, &keytab); if (kret) { krb5_get_init_creds_opt_free(context, opt); goto end; } kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, keytab, 0, NULL, opt); } krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if (kret) goto end; kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) { krb5_cc_destroy(context, ccache); goto end; } kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) { krb5_cc_destroy(context, ccache); goto end; } handle->lifetime = cred.times.endtime; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; } else { ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &handle->lifetime); if (ret != GSS_S_COMPLETE) { krb5_cc_close(context, ccache); goto end; } kret = 0; } found: handle->ccache = ccache; ret = GSS_S_COMPLETE; end: if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (def_princ != NULL) krb5_free_principal(context, def_princ); if (keytab != NULL) krb5_kt_close(context, keytab); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }
ngx_int_t ngx_http_auth_spnego_basic( ngx_http_request_t * r, ngx_http_auth_spnego_ctx_t * ctx, ngx_http_auth_spnego_loc_conf_t * alcf) { ngx_str_t host_name; ngx_str_t service; ngx_str_t user; user.data = NULL; ngx_str_t new_user; ngx_int_t ret = NGX_DECLINED; krb5_context kcontext = NULL; krb5_error_code code; krb5_principal client = NULL; krb5_principal server = NULL; krb5_creds creds; krb5_get_init_creds_opt *gic_options = NULL; int kret = 0; char *name = NULL; char *p = NULL; code = krb5_init_context(&kcontext); if (code) { spnego_debug0("Kerberos error: Cannot initialize kerberos context"); return NGX_ERROR; } host_name = r->headers_in.host->value; service.len = alcf->srvcname.len + alcf->realm.len + 3; if (ngx_strchr(alcf->srvcname.data, '/')) { service.data = ngx_palloc(r->pool, service.len); if (NULL == service.data) { spnego_error(NGX_ERROR); } ngx_snprintf(service.data, service.len, "%V@%V%Z", &alcf->srvcname, &alcf->realm); } else { service.len += host_name.len; service.data = ngx_palloc(r->pool, service.len); if (NULL == service.data) { spnego_error(NGX_ERROR); } ngx_snprintf(service.data, service.len, "%V/%V@%V%Z", &alcf->srvcname, &host_name, &alcf->realm); } kret = krb5_parse_name(kcontext, (const char *) service.data, &server); if (kret) { spnego_log_error("Kerberos error: Unable to parse service name"); spnego_log_krb5_error(kcontext, code); spnego_error(NGX_ERROR); } code = krb5_unparse_name(kcontext, server, &name); if (code) { spnego_log_error("Kerberos error: Cannot unparse servicename"); spnego_log_krb5_error(kcontext, code); spnego_error(NGX_ERROR); } free(name); name = NULL; p = ngx_strchr(r->headers_in.user.data, '@'); user.len = r->headers_in.user.len + 1; if (NULL == p) { if (alcf->force_realm && alcf->realm.len && alcf->realm.data ) { user.len += alcf->realm.len + 1; /* +1 for @ */ user.data = ngx_palloc(r->pool, user.len); if (NULL == user.data) { spnego_log_error("Not enough memory"); spnego_error(NGX_ERROR); } ngx_snprintf(user.data, user.len, "%V@%V%Z", &r->headers_in.user, &alcf->realm); } else { user.data = ngx_palloc(r->pool, user.len); if (NULL == user.data) { spnego_log_error("Not enough memory"); spnego_error(NGX_ERROR); } ngx_snprintf(user.data, user.len, "%V%Z", &r->headers_in.user); } } else { if (alcf->realm.len && alcf->realm.data && ngx_strncmp(p + 1, alcf->realm.data, alcf->realm.len) == 0) { user.data = ngx_palloc(r->pool, user.len); if (NULL == user.data) { spnego_log_error("Not enough memory"); spnego_error(NGX_ERROR); } ngx_snprintf(user.data, user.len, "%V%Z", &r->headers_in.user); if (alcf->fqun == 0) { /* * Specified realm is identical to configured realm. * Truncate $remote_user to strip @REALM. */ r->headers_in.user.len -= alcf->realm.len + 1; } } else if (alcf->force_realm) { *p = '\0'; user.len = ngx_strlen(r->headers_in.user.data) + 1; if (alcf->realm.len && alcf->realm.data) user.len += alcf->realm.len + 1; user.data = ngx_pcalloc(r->pool, user.len); if (NULL == user.data) { spnego_log_error("Not enough memory"); spnego_error(NGX_ERROR); } if (alcf->realm.len && alcf->realm.data) ngx_snprintf(user.data, user.len, "%s@%V%Z", r->headers_in.user.data, &alcf->realm); else ngx_snprintf(user.data, user.len, "%s%Z", r->headers_in.user.data); /* * Rewrite $remote_user with the forced realm. * If the forced realm is shorter than the * specified realm, we can reuse the original * buffer. */ if (r->headers_in.user.len >= user.len - 1) r->headers_in.user.len = user.len - 1; else { new_user.len = user.len - 1; new_user.data = ngx_palloc(r->pool, new_user.len); if (NULL == new_user.data) { spnego_log_error("Not enough memory"); spnego_error(NGX_ERROR); } ngx_pfree(r->pool, r->headers_in.user.data); r->headers_in.user.data = new_user.data; r->headers_in.user.len = new_user.len; } ngx_memcpy(r->headers_in.user.data, user.data, r->headers_in.user.len); } else { user.data = ngx_palloc(r->pool, user.len); if (NULL == user.data) { spnego_log_error("Not enough memory"); spnego_error(NGX_ERROR); } ngx_snprintf(user.data, user.len, "%V%Z", &r->headers_in.user); } } spnego_debug1("Attempting authentication with principal %s", (const char *)user.data); code = krb5_parse_name(kcontext, (const char *) user.data, &client); if (code) { spnego_log_error("Kerberos error: Unable to parse username"); spnego_debug1("username is %s.", (const char *) user.data); spnego_log_krb5_error(kcontext, code); spnego_error(NGX_ERROR); } memset(&creds, 0, sizeof(creds)); code = krb5_unparse_name(kcontext, client, &name); if (code) { spnego_log_error("Kerberos error: Cannot unparse username"); spnego_log_krb5_error(kcontext, code); spnego_error(NGX_ERROR); } krb5_get_init_creds_opt_alloc(kcontext, &gic_options); code = krb5_get_init_creds_password(kcontext, &creds, client, (char *) r->headers_in.passwd.data, NULL, NULL, 0, NULL, gic_options); krb5_free_cred_contents(kcontext, &creds); if (code) { spnego_log_error("Kerberos error: Credentials failed"); spnego_log_krb5_error(kcontext, code); spnego_error(NGX_DECLINED); } /* Try to add the system realm to $remote_user if needed. */ if (alcf->fqun && !ngx_strchr(r->headers_in.user.data, '@')) { #ifdef krb5_princ_realm /* * MIT does not have krb5_principal_get_realm() but its * krb5_princ_realm() is a macro that effectively points * to a char *. */ const char *realm = krb5_princ_realm(kcontext, client)->data; #else const char *realm = krb5_principal_get_realm(kcontext, client); #endif if (realm) { new_user.len = r->headers_in.user.len + 1 + ngx_strlen(realm); new_user.data = ngx_palloc(r->pool, new_user.len); if (NULL == new_user.data) { spnego_log_error("Not enough memory"); spnego_error(NGX_ERROR); } ngx_snprintf(new_user.data, new_user.len, "%V@%s", &r->headers_in.user, realm); ngx_pfree(r->pool, r->headers_in.user.data); r->headers_in.user.data = new_user.data; r->headers_in.user.len = new_user.len; } } spnego_debug1("Setting $remote_user to %V", &r->headers_in.user); if (ngx_http_auth_spnego_set_bogus_authorization(r) != NGX_OK) spnego_log_error("Failed to set $remote_user"); spnego_debug0("ngx_http_auth_spnego_basic: returning NGX_OK"); ret = NGX_OK; end: if (name) free(name); if (client) krb5_free_principal(kcontext, client); if (server) krb5_free_principal(kcontext, server); if (service.data) ngx_pfree(r->pool, service.data); if (user.data) ngx_pfree(r->pool, user.data); krb5_get_init_creds_opt_free(kcontext, gic_options); krb5_free_context(kcontext); 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; }
/* Perform one iteration of attempting to get credentials. This includes * searching existing ccache for requested service if INIT_CREDS. */ static kadm5_ret_t gic_iter(kadm5_server_handle_t handle, enum init_type init_type, krb5_ccache ccache, krb5_principal client, char *pass, char *svcname, char *realm, krb5_principal *server_out) { kadm5_ret_t code; krb5_context ctx; krb5_keytab kt; krb5_get_init_creds_opt *opt = NULL; krb5_creds mcreds, outcreds; *server_out = NULL; ctx = handle->context; kt = NULL; memset(&opt, 0, sizeof(opt)); memset(&mcreds, 0, sizeof(mcreds)); memset(&outcreds, 0, sizeof(outcreds)); /* Credentials for kadmin don't need to be forwardable or proxiable. */ if (init_type != INIT_CREDS) { code = krb5_get_init_creds_opt_alloc(ctx, &opt); krb5_get_init_creds_opt_set_forwardable(opt, 0); krb5_get_init_creds_opt_set_proxiable(opt, 0); krb5_get_init_creds_opt_set_out_ccache(ctx, opt, ccache); if (init_type == INIT_ANONYMOUS) krb5_get_init_creds_opt_set_anonymous(opt, 1); } if (init_type == INIT_PASS || init_type == INIT_ANONYMOUS) { code = krb5_get_init_creds_password(ctx, &outcreds, client, pass, krb5_prompter_posix, NULL, 0, svcname, opt); if (code) goto error; } else if (init_type == INIT_SKEY) { if (pass) { code = krb5_kt_resolve(ctx, pass, &kt); if (code) goto error; } code = krb5_get_init_creds_keytab(ctx, &outcreds, client, kt, 0, svcname, opt); if (pass) krb5_kt_close(ctx, kt); if (code) goto error; } else if (init_type == INIT_CREDS) { mcreds.client = client; code = krb5_parse_name_flags(ctx, svcname, KRB5_PRINCIPAL_PARSE_IGNORE_REALM, &mcreds.server); if (code) goto error; code = krb5_set_principal_realm(ctx, mcreds.server, realm); if (code) goto error; code = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcreds, &outcreds); krb5_free_principal(ctx, mcreds.server); if (code) goto error; } else { code = EINVAL; goto error; } /* Steal the server principal of the creds we acquired and return it to the * caller, which needs to knows what service to authenticate to. */ *server_out = outcreds.server; outcreds.server = NULL; error: krb5_free_cred_contents(ctx, &outcreds); if (opt) krb5_get_init_creds_opt_free(ctx, opt); return code; }
/* * VmDirLoginUser Creates a TGT cache for the Process to * communicate with the VmDir */ DWORD VmDirKrb5LoginUser( PCSTR pszUserName, PCSTR pszPassword, PCSTR pszKrb5ConfPath /* Optional */ ) { DWORD dwError = 0; krb5_context context = NULL; krb5_get_init_creds_opt *opt = NULL; krb5_principal principal = NULL; krb5_ccache ccache = NULL; krb5_creds creds = { 0 }; PSTR pszCacheName = NULL; if (!IsNullOrEmptyString(pszKrb5ConfPath)) { setenv(KRB5_CONF_PATH, pszKrb5ConfPath, 1); } dwError = VmDirMapKrbError( krb5_init_context(&context) ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirMapKrbError( krb5_get_init_creds_opt_alloc(context, &opt) ); BAIL_ON_VMDIR_ERROR(dwError); krb5_get_init_creds_opt_set_tkt_life(opt, 8 * 60 * 60); //8 hours ticket krb5_get_init_creds_opt_set_forwardable(opt, 1); // Creates a File based Credential cache based on defaults dwError = VmDirMapKrbError( krb5_cc_new_unique( context, "FILE", "hint", &ccache) ); BAIL_ON_VMDIR_ERROR(dwError); // it is assumed that pszUserName is in user@REALM format. dwError = VmDirMapKrbError( krb5_parse_name(context, pszUserName, &principal) ); BAIL_ON_VMDIR_ERROR(dwError); // Let us get the Creds from the Kerberos Server dwError = VmDirMapKrbError( krb5_get_init_creds_password( context, &creds, principal, (PSTR) pszPassword, NULL, NULL, 0, NULL, opt) ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirMapKrbError( krb5_cc_initialize(context, ccache, principal) ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirMapKrbError( krb5_cc_store_cred(context, ccache, &creds) ); BAIL_ON_VMDIR_ERROR(dwError); pszCacheName = (PSTR)krb5_cc_get_name(context, ccache); if ( pszCacheName == NULL) { dwError = ERROR_NO_CRED_CACHE_NAME; BAIL_ON_VMDIR_ERROR(dwError); } // let us set the Value to the Env. Variable so GSSAPI can find it. setenv(KRB5_CC_NAME, pszCacheName, 1); krb5_cc_set_default_name(context, pszCacheName); error: if (principal != NULL) { krb5_free_principal(context, principal); } if (opt != NULL) { krb5_get_init_creds_opt_free(context,opt); } krb5_free_cred_contents(context, &creds); if (context != NULL) { krb5_free_context(context); } return dwError; }
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 = NULL; krb5_ccache_data ccdata; char *in_tkt_service = NULL; 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); 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); 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 */ ret = krb5_get_init_creds_keytab(context, &cred, ccache->client, ccache->key.keytab, 0, in_tkt_service, opt); } 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: if (opt) krb5_get_init_creds_opt_free(context, opt); HEIMDAL_MUTEX_unlock(&ccache->mutex); return ret; }
int main(int argc, char **argv) { krb5_context ctx; krb5_ccache in_ccache, out_ccache, armor_ccache; krb5_get_init_creds_opt *opt; char *user, *password, *armor_ccname = NULL, *in_ccname = NULL, *perr; const char *err; krb5_principal client; krb5_creds creds; krb5_flags fast_flags; krb5_error_code ret; int c; while ((c = getopt(argc, argv, "I:A:")) != -1) { switch (c) { case 'A': armor_ccname = optarg; break; case 'I': in_ccname = optarg; break; } } if (argc - optind < 2) { fprintf(stderr, "Usage: %s [-A armor_ccache] [-I in_ccache] " "username password\n", argv[0]); return 1; } user = argv[optind]; password = argv[optind + 1]; bail_on_err(NULL, "Error initializing Kerberos", krb5_init_context(&ctx)); bail_on_err(ctx, "Error allocating space for get_init_creds options", krb5_get_init_creds_opt_alloc(ctx, &opt)); if (in_ccname != NULL) { bail_on_err(ctx, "Error resolving input ccache", krb5_cc_resolve(ctx, in_ccname, &in_ccache)); bail_on_err(ctx, "Error setting input_ccache option", krb5_get_init_creds_opt_set_in_ccache(ctx, opt, in_ccache)); } else { in_ccache = NULL; } if (armor_ccname != NULL) { bail_on_err(ctx, "Error resolving armor ccache", krb5_cc_resolve(ctx, armor_ccname, &armor_ccache)); bail_on_err(ctx, "Error setting fast_ccache option", krb5_get_init_creds_opt_set_fast_ccache(ctx, opt, armor_ccache)); fast_flags = KRB5_FAST_REQUIRED; bail_on_err(ctx, "Error setting option to force use of FAST", krb5_get_init_creds_opt_set_fast_flags(ctx, opt, fast_flags)); } else { armor_ccache = NULL; } bail_on_err(ctx, "Error resolving output (default) ccache", krb5_cc_default(ctx, &out_ccache)); bail_on_err(ctx, "Error setting output ccache option", krb5_get_init_creds_opt_set_out_ccache(ctx, opt, out_ccache)); if (asprintf(&perr, "Error parsing principal name \"%s\"", user) < 0) abort(); bail_on_err(ctx, perr, krb5_parse_name(ctx, user, &client)); ret = krb5_get_init_creds_password(ctx, &creds, client, password, prompter_cb, NULL, 0, NULL, opt); if (ret) { err = krb5_get_error_message(ctx, ret); printf("%s\n", err); krb5_free_error_message(ctx, err); } else { krb5_free_cred_contents(ctx, &creds); } krb5_get_init_creds_opt_free(ctx, opt); krb5_free_principal(ctx, client); krb5_cc_close(ctx, out_ccache); if (armor_ccache != NULL) krb5_cc_close(ctx, armor_ccache); if (in_ccache != NULL) krb5_cc_close(ctx, in_ccache); krb5_free_context(ctx); free(perr); return ret ? (ret - KRB5KDC_ERR_NONE) : 0; }
int main(int argc, char **argv) { krb5_context context; krb5_keytab kt; krb5_keytab_entry ktent; krb5_encrypt_block eblock; krb5_creds my_creds; krb5_get_init_creds_opt *opt; kadm5_principal_ent_rec princ_ent; krb5_principal princ, server; char pw[16]; char *whoami, *principal, *authprinc, *authpwd; krb5_data pwdata; void *handle; int ret, test, encnum; unsigned int i; whoami = argv[0]; if (argc < 2 || argc > 4) { fprintf(stderr, "Usage: %s principal [authuser] [authpwd]\n", whoami); exit(1); } principal = argv[1]; authprinc = (argc > 2) ? argv[2] : argv[0]; authpwd = (argc > 3) ? argv[3] : NULL; /* * Setup. Initialize data structures, open keytab, open connection * to kadm5 server. */ memset(&context, 0, sizeof(context)); kadm5_init_krb5_context(&context); ret = krb5_parse_name(context, principal, &princ); if (ret) { com_err(whoami, ret, "while parsing principal name %s", principal); exit(1); } if((ret = krb5_build_principal_ext(context, &server, krb5_princ_realm(kcontext, princ)->length, krb5_princ_realm(kcontext, princ)->data, tgtname.length, tgtname.data, krb5_princ_realm(kcontext, princ)->length, krb5_princ_realm(kcontext, princ)->data, 0))) { com_err(whoami, ret, "while building server name"); exit(1); } ret = krb5_kt_default(context, &kt); if (ret) { com_err(whoami, ret, "while opening keytab"); exit(1); } ret = kadm5_init(context, authprinc, authpwd, KADM5_ADMIN_SERVICE, NULL, KADM5_STRUCT_VERSION, KADM5_API_VERSION_4, NULL, &handle); if (ret) { com_err(whoami, ret, "while initializing connection"); exit(1); } /* these pw's don't need to be secure, just different every time */ SRAND((RAND_TYPE)time((void *) NULL)); pwdata.data = pw; pwdata.length = sizeof(pw); /* * For each test: * * For each enctype in the test, construct a random password/key. * Assign all keys to principal with kadm5_setkey_principal. Add * each key to the keytab, and acquire an initial ticket with the * keytab (XXX can I specify the kvno explicitly?). If * krb5_get_init_creds_keytab succeeds, then the keys were set * successfully. */ for (test = 0; tests[test] != NULL; test++) { krb5_keyblock *testp = tests[test]; kadm5_key_data *extracted; int n_extracted, match; printf("+ Test %d:\n", test); for (encnum = 0; testp[encnum].magic != -1; encnum++) { for (i = 0; i < sizeof(pw); i++) pw[i] = (RAND() % 26) + '0'; /* XXX */ krb5_use_enctype(context, &eblock, testp[encnum].enctype); ret = krb5_string_to_key(context, &eblock, &testp[encnum], &pwdata, NULL); if (ret) { com_err(whoami, ret, "while converting string to key"); exit(1); } } /* now, encnum == # of keyblocks in testp */ ret = kadm5_setkey_principal(handle, princ, testp, encnum); if (ret) { com_err(whoami, ret, "while setting keys"); exit(1); } ret = kadm5_get_principal(handle, princ, &princ_ent, KADM5_KVNO); if (ret) { com_err(whoami, ret, "while retrieving principal"); exit(1); } ret = kadm5_get_principal_keys(handle, princ, 0, &extracted, &n_extracted); if (ret) { com_err(whoami, ret, "while extracting keys"); exit(1); } for (encnum = 0; testp[encnum].magic != -1; encnum++) { printf("+ enctype %d\n", testp[encnum].enctype); for (match = 0; match < n_extracted; match++) { if (extracted[match].key.enctype == testp[encnum].enctype) break; } if (match >= n_extracted) { com_err(whoami, KRB5_WRONG_ETYPE, "while matching enctypes"); exit(1); } if (extracted[match].key.length != testp[encnum].length || memcmp(extracted[match].key.contents, testp[encnum].contents, testp[encnum].length) != 0) { com_err(whoami, KRB5_KDB_NO_MATCHING_KEY, "verifying keys"); exit(1); } memset(&ktent, 0, sizeof(ktent)); ktent.principal = princ; ktent.key = testp[encnum]; ktent.vno = princ_ent.kvno; ret = krb5_kt_add_entry(context, kt, &ktent); if (ret) { com_err(whoami, ret, "while adding keytab entry"); exit(1); } memset(&my_creds, 0, sizeof(my_creds)); my_creds.client = princ; my_creds.server = server; ktypes[0] = testp[encnum].enctype; ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) { com_err(whoami, ret, "while allocating gic opts"); exit(1); } krb5_get_init_creds_opt_set_etype_list(opt, ktypes, 1); ret = krb5_get_init_creds_keytab(context, &my_creds, princ, kt, 0, NULL /* in_tkt_service */, opt); krb5_get_init_creds_opt_free(context, opt); if (ret) { com_err(whoami, ret, "while acquiring initial ticket"); exit(1); } krb5_free_cred_contents(context, &my_creds); /* since I can't specify enctype explicitly ... */ ret = krb5_kt_remove_entry(context, kt, &ktent); if (ret) { com_err(whoami, ret, "while removing keytab entry"); exit(1); } } (void)kadm5_free_kadm5_key_data(context, n_extracted, extracted); } ret = krb5_kt_close(context, kt); if (ret) { com_err(whoami, ret, "while closing keytab"); exit(1); } ret = kadm5_destroy(handle); if (ret) { com_err(whoami, ret, "while closing kadmin connection"); exit(1); } krb5_free_principal(context, princ); krb5_free_principal(context, server); krb5_free_context(context); return 0; }
static int krb5_verify_password (POP *p) { krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP}; krb5_get_init_creds_opt *get_options; krb5_verify_init_creds_opt verify_options; krb5_error_code ret; krb5_principal client, server; krb5_creds creds; ret = krb5_get_init_creds_opt_alloc (p->context, &get_options); if (ret) { pop_log(p, POP_PRIORITY, "krb5_get_init_creds_opt_alloc: %s", krb5_get_err_text (p->context, ret)); return 1; } krb5_get_init_creds_opt_set_preauth_list (get_options, pre_auth_types, 1); krb5_verify_init_creds_opt_init (&verify_options); ret = krb5_parse_name (p->context, p->user, &client); if (ret) { krb5_get_init_creds_opt_free(p->context, get_options); pop_log(p, POP_PRIORITY, "krb5_parse_name: %s", krb5_get_err_text (p->context, ret)); return 1; } ret = krb5_get_init_creds_password (p->context, &creds, client, p->pop_parm[1], NULL, NULL, 0, NULL, get_options); krb5_get_init_creds_opt_free(p->context, get_options); if (ret) { pop_log(p, POP_PRIORITY, "krb5_get_init_creds_password: %s", krb5_get_err_text (p->context, ret)); return 1; } ret = krb5_sname_to_principal (p->context, p->myhost, "pop", KRB5_NT_SRV_HST, &server); if (ret) { pop_log(p, POP_PRIORITY, "krb5_get_init_creds_password: %s", krb5_get_err_text (p->context, ret)); return 1; } ret = krb5_verify_init_creds (p->context, &creds, server, NULL, NULL, &verify_options); krb5_free_principal (p->context, client); krb5_free_principal (p->context, server); krb5_free_cred_contents (p->context, &creds); return ret; }
int main(int argc, char **argv) { krb5_context context; krb5_ccache ccache; krb5_get_init_creds_opt *opts; krb5_principal principal; krb5_creds creds; krb5_error_code err; const char *errmsg; char *opt, *val; struct responder_data response; int c; err = krb5_init_context(&context); if (err != 0) { fprintf(stderr, "error starting Kerberos: %s\n", error_message(err)); return err; } err = krb5_get_init_creds_opt_alloc(context, &opts); if (err != 0) { fprintf(stderr, "error initializing options: %s\n", error_message(err)); return err; } err = krb5_cc_default(context, &ccache); if (err != 0) { fprintf(stderr, "error resolving default ccache: %s\n", error_message(err)); return err; } err = krb5_get_init_creds_opt_set_out_ccache(context, opts, ccache); if (err != 0) { fprintf(stderr, "error setting output ccache: %s\n", error_message(err)); return err; } memset(&response, 0, sizeof(response)); while ((c = getopt(argc, argv, "X:x:cr:p:")) != -1) { switch (c) { case 'X': /* Like kinit, set a generic preauth option. */ opt = strdup(optarg); val = opt + strcspn(opt, "="); if (*val != '\0') { *val++ = '\0'; } err = krb5_get_init_creds_opt_set_pa(context, opts, opt, val); if (err != 0) { fprintf(stderr, "error setting option \"%s\": %s\n", opt, error_message(err)); return err; } free(opt); break; case 'x': /* Check that a particular question has a specific challenge. */ response.challenge = optarg; break; case 'c': /* Note that we want a dump of the PKINIT challenge structure. */ response.print_pkinit_challenge = TRUE; break; case 'r': /* Set a verbatim response for a verbatim challenge. */ response.response = optarg; break; case 'p': /* Set a PKINIT answer for a specific PKINIT identity. */ response.pkinit_answer = optarg; break; case 'o': /* Set an OTP answer for a specific OTP tokeninfo. */ response.otp_answer = optarg; break; } } if (argc > optind) { err = krb5_parse_name(context, argv[optind], &principal); if (err != 0) { fprintf(stderr, "error parsing name \"%s\": %s", argv[optind], error_message(err)); return err; } } else { fprintf(stderr, "error: no principal name provided\n"); return -1; } err = krb5_get_init_creds_opt_set_responder(context, opts, responder, &response); if (err != 0) { fprintf(stderr, "error setting responder: %s\n", error_message(err)); return err; } memset(&creds, 0, sizeof(creds)); err = krb5_get_init_creds_password(context, &creds, principal, NULL, NULL, NULL, 0, NULL, opts); if (err == 0) krb5_free_cred_contents(context, &creds); krb5_free_principal(context, principal); krb5_get_init_creds_opt_free(context, opts); krb5_cc_close(context, ccache); if (!response.called) { fprintf(stderr, "error: responder callback wasn't called\n"); err = 1; } else if (err) { errmsg = krb5_get_error_message(context, err); fprintf(stderr, "error: krb5_get_init_creds_password failed: %s\n", errmsg); krb5_free_error_message(context, errmsg); err = 2; } krb5_free_context(context); return err; }
/* * Obtain credentials via a key in the keytab given * a keytab handle and a gssd_k5_kt_princ structure. * Checks to see if current credentials are expired, * if not, uses the keytab to obtain new credentials. * * Returns: * 0 => success (or credentials have not expired) * nonzero => error */ static int gssd_get_single_krb5_cred(krb5_context context, krb5_keytab kt, struct gssd_k5_kt_princ *ple, int nocache) { #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS krb5_get_init_creds_opt *init_opts = NULL; #else krb5_get_init_creds_opt options; #endif krb5_get_init_creds_opt *opts; krb5_creds my_creds; krb5_ccache ccache = NULL; char kt_name[BUFSIZ]; char cc_name[BUFSIZ]; int code; time_t now = time(0); char *cache_type; char *pname = NULL; char *k5err = NULL; memset(&my_creds, 0, sizeof(my_creds)); if (ple->ccname && ple->endtime > now && !nocache) { printerr(2, "INFO: Credentials in CC '%s' are good until %d\n", ple->ccname, ple->endtime); code = 0; goto out; } code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ); if (code != 0) { printerr(0, "ERROR: Unable to get keytab name in " "gssd_get_single_krb5_cred\n"); goto out; } if ((krb5_unparse_name(context, ple->princ, &pname))) pname = NULL; #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS code = krb5_get_init_creds_opt_alloc(context, &init_opts); if (code) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s allocating gic options\n", k5err); goto out; } if (krb5_get_init_creds_opt_set_addressless(context, init_opts, 1)) printerr(1, "WARNING: Unable to set option for addressless " "tickets. May have problems behind a NAT.\n"); #ifdef TEST_SHORT_LIFETIME /* set a short lifetime (for debugging only!) */ printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); krb5_get_init_creds_opt_set_tkt_life(init_opts, 5 * 60); #endif opts = init_opts; #else /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS */ krb5_get_init_creds_opt_init(&options); krb5_get_init_creds_opt_set_address_list(&options, NULL); #ifdef TEST_SHORT_LIFETIME /* set a short lifetime (for debugging only!) */ printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); krb5_get_init_creds_opt_set_tkt_life(&options, 5 * 60); #endif opts = &options; #endif code = krb5_get_init_creds_keytab(context, &my_creds, ple->princ, kt, 0, NULL, opts); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(1, "WARNING: %s while getting initial ticket for " "principal '%s' using keytab '%s'\n", k5err, pname ? pname : "<unparsable>", kt_name); goto out; } /* * Initialize cache file which we're going to be using */ if (use_memcache) cache_type = "MEMORY"; else cache_type = "FILE"; snprintf(cc_name, sizeof(cc_name), "%s:%s/%s%s_%s", cache_type, ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX, GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm); ple->endtime = my_creds.times.endtime; if (ple->ccname != NULL) gsh_free(ple->ccname); ple->ccname = gsh_strdup(cc_name); if (ple->ccname == NULL) { printerr(0, "ERROR: no storage to duplicate credentials " "cache name '%s'\n", cc_name); code = ENOMEM; goto out; } code = krb5_cc_resolve(context, cc_name, &ccache); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s while opening credential cache '%s'\n", k5err, cc_name); goto out; } code = krb5_cc_initialize(context, ccache, ple->princ); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s while initializing credential " "cache '%s'\n", k5err, cc_name); } code = krb5_cc_store_cred(context, ccache, &my_creds); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s while storing credentials in '%s'\n", k5err, cc_name); goto out; } /* if we get this far, let gss mech know */ gssd_set_krb5_ccache_name(cc_name); code = 0; printerr(2, "Successfully obtained machine credentials for " "principal '%s' stored in ccache '%s'\n", pname, cc_name); out: #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS if (init_opts) krb5_get_init_creds_opt_free(context, init_opts); #endif if (pname) k5_free_unparsed_name(context, pname); if (ccache) krb5_cc_close(context, ccache); krb5_free_cred_contents(context, &my_creds); gsh_free(k5err); return code; }
static 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 kbrccache_t userinitcontext( const char * user, const char * domain, const char * passwd, const char * cachename, int initialize, int * outError ) { krb5_context kcontext = 0; krb5_ccache kcache = 0; krb5_creds kcreds; krb5_principal kme = 0; krb5_error_code kres; char * pPass = strdup( passwd ); char * pName = NULL; char * pCacheName = NULL; int numCreds = 0; memset( &kcreds, 0, sizeof(kcreds) ); kres = krb5_init_context( &kcontext ); if( kres ) goto return_error; if( domain ) kres = krb5_build_principal( kcontext, &kme, strlen(domain), domain, user, (char *) 0 ); else kres = krb5_parse_name( kcontext, user, &kme ); if( kres ) goto fail; krb5_unparse_name( kcontext, kme, &pName ); if( cachename ) { if (asprintf(&pCacheName, "%s%s", cachename, pName) < 0) { kres = KRB5_CC_NOMEM; goto fail; } kres = krb5_cc_resolve( kcontext, pCacheName, &kcache ); if( kres ) { kres = krb5_cc_resolve( kcontext, CCACHE_PREFIX_DEFAULT, &kcache ); if( kres == 0 ) pCacheName = strdup(CCACHE_PREFIX_DEFAULT); } } else { kres = krb5_cc_default( kcontext, &kcache ); pCacheName = strdup( krb5_cc_get_name( kcontext, kcache ) ); } if( kres ) { krb5_free_context(kcontext); goto return_error; } if( initialize ) krb5_cc_initialize( kcontext, kcache, kme ); if( kres == 0 && user && passwd ) { long timeneeded = time(0L) +TKTTIMELEFT; int have_credentials = 0; krb5_cc_cursor cc_curs = NULL; numCreds = 0; if( (kres=krb5_cc_start_seq_get(kcontext, kcache, &cc_curs)) >= 0 ) { while( (kres=krb5_cc_next_cred(kcontext, kcache, &cc_curs, &kcreds))== 0) { numCreds++; if( krb5_principal_compare( kcontext, kme, kcreds.client ) ) { if( kcreds.ticket_flags & TKT_FLG_INITIAL && kcreds.times.endtime>timeneeded ) have_credentials = 1; } krb5_free_cred_contents( kcontext, &kcreds ); if( have_credentials ) break; } krb5_cc_end_seq_get( kcontext, kcache, &cc_curs ); } else { const char * errmsg = error_message(kres); fprintf( stderr, "%s user init(%s): %s\n", "setpass", pName, errmsg ); } if( kres != 0 || have_credentials == 0 ) { krb5_get_init_creds_opt *options = NULL; kres = krb5_get_init_creds_opt_alloc(kcontext, &options); if ( kres == 0 ) { get_init_creds_opt_init(options); /* ** no valid credentials - get new ones */ kres = krb5_get_init_creds_password( kcontext, &kcreds, kme, pPass, NULL /*prompter*/, NULL /*data*/, 0 /*starttime*/, 0 /*in_tkt_service*/, options /*options*/ ); } if( kres == 0 ) { if( numCreds <= 0 ) kres = krb5_cc_initialize( kcontext, kcache, kme ); if( kres == 0 ) kres = krb5_cc_store_cred( kcontext, kcache, &kcreds ); if( kres == 0 ) have_credentials = 1; } krb5_get_init_creds_opt_free(kcontext, options); } #ifdef NOTUSED if( have_credentials ) { int mstat; kres = gss_krb5_ccache_name( &mstat, pCacheName, NULL ); if( getenv( ENV_DEBUG_LDAPKERB ) ) fprintf( stderr, "gss credentials cache set to %s(%d)\n", pCacheName, kres ); } #endif krb5_cc_close( kcontext, kcache ); } fail: if( kres ) { const char * errmsg = error_message(kres); fprintf( stderr, "%s user init(%s): %s\n", "setpass", pName, errmsg ); } krb5_free_principal( kcontext, kme ); krb5_free_cred_contents( kcontext, &kcreds ); if( pName ) free( pName ); free(pPass); krb5_free_context(kcontext); return_error: if( kres ) { if( pCacheName ) { free(pCacheName); pCacheName = NULL; } } if( outError ) *outError = kres; return pCacheName; }
static krb5_error_code change_password (krb5_context context, krb5_principal client, const char *password, char *newpw, size_t newpw_sz, krb5_prompter_fct prompter, void *data, krb5_get_init_creds_opt *old_options) { krb5_prompt prompts[2]; krb5_error_code ret; krb5_creds cpw_cred; char buf1[BUFSIZ], buf2[BUFSIZ]; krb5_data password_data[2]; int result_code; krb5_data result_code_string; krb5_data result_string; char *p; krb5_get_init_creds_opt *options; memset (&cpw_cred, 0, sizeof(cpw_cred)); ret = krb5_get_init_creds_opt_alloc(context, &options); if (ret) return ret; krb5_get_init_creds_opt_set_tkt_life (options, 60); krb5_get_init_creds_opt_set_forwardable (options, FALSE); krb5_get_init_creds_opt_set_proxiable (options, FALSE); if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) krb5_get_init_creds_opt_set_preauth_list (options, old_options->preauth_list, old_options->preauth_list_length); krb5_data_zero (&result_code_string); krb5_data_zero (&result_string); ret = krb5_get_init_creds_password (context, &cpw_cred, client, password, prompter, data, 0, "kadmin/changepw", options); krb5_get_init_creds_opt_free(context, options); if (ret) goto out; for(;;) { password_data[0].data = buf1; password_data[0].length = sizeof(buf1); prompts[0].hidden = 1; prompts[0].prompt = "New password: "******"Repeat new password: "******"Changing password", 2, prompts); if (ret) { memset (buf1, 0, sizeof(buf1)); memset (buf2, 0, sizeof(buf2)); goto out; } if (strcmp (buf1, buf2) == 0) break; memset (buf1, 0, sizeof(buf1)); memset (buf2, 0, sizeof(buf2)); } ret = krb5_set_password (context, &cpw_cred, buf1, client, &result_code, &result_code_string, &result_string); if (ret) goto out; asprintf (&p, "%s: %.*s\n", result_code ? "Error" : "Success", (int)result_string.length, result_string.length > 0 ? (char*)result_string.data : ""); /* return the result */ (*prompter) (context, data, NULL, p, 0, NULL); free (p); if (result_code == 0) { strlcpy (newpw, buf1, newpw_sz); ret = 0; } else { ret = ENOTTY; krb5_set_error_message(context, ret, N_("failed changing password", "")); } out: memset (buf1, 0, sizeof(buf1)); memset (buf2, 0, sizeof(buf2)); krb5_data_free (&result_string); krb5_data_free (&result_code_string); krb5_free_cred_contents (context, &cpw_cred); return ret; }
int main (int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_principal principal; krb5_get_init_creds_opt *opt; krb5_ccache id = NULL; int exit_value; int optidx = 0; setprogname(argv[0]); if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1, args, sizeof(args) / sizeof(args[0])); if (help_flag) usage(0, args, sizeof(args) / sizeof(args[0])); if (version_flag) { print_version(NULL); return 0; } argc -= optidx; argv += optidx; ret = krb5_init_context (&context); if (ret) errx (1, "krb5_init_context failed: %d", ret); 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_tkt_life (opt, 300); krb5_get_init_creds_opt_set_forwardable (opt, FALSE); krb5_get_init_creds_opt_set_proxiable (opt, FALSE); if (cred_cache_str) { ret = krb5_cc_resolve(context, cred_cache_str, &id); if (ret) krb5_err (context, 1, ret, "krb5_cc_resolve"); } else { ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); if (ret) krb5_err (context, 1, ret, "krb5_cc_new_unique"); } if (cred_cache_str == NULL) { krb5_principal admin_principal = NULL; krb5_creds cred; if (admin_principal_str) { ret = krb5_parse_name (context, admin_principal_str, &admin_principal); if (ret) krb5_err (context, 1, ret, "krb5_parse_name"); } else if (argc == 1) { ret = krb5_parse_name (context, argv[0], &admin_principal); if (ret) krb5_err (context, 1, ret, "krb5_parse_name"); } else { ret = krb5_get_default_principal (context, &admin_principal); if (ret) krb5_err (context, 1, ret, "krb5_get_default_principal"); } ret = krb5_get_init_creds_password (context, &cred, admin_principal, NULL, krb5_prompter_posix, NULL, 0, "kadmin/changepw", opt); switch (ret) { case 0: break; case KRB5_LIBOS_PWDINTR : return 1; case KRB5KRB_AP_ERR_BAD_INTEGRITY : case KRB5KRB_AP_ERR_MODIFIED : krb5_errx(context, 1, "Password incorrect"); break; default: krb5_err(context, 1, ret, "krb5_get_init_creds"); } krb5_get_init_creds_opt_free(context, opt); ret = krb5_cc_initialize(context, id, admin_principal); krb5_free_principal(context, admin_principal); 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); } if (argc == 0) { exit_value = change_password(context, NULL, id); } else { exit_value = 0; while (argc-- > 0) { ret = krb5_parse_name (context, argv[0], &principal); if (ret) krb5_err (context, 1, ret, "krb5_parse_name"); ret = change_password(context, principal, id); if (ret) exit_value = 1; krb5_free_principal(context, principal); argv++; } } if (cred_cache_str == NULL) { ret = krb5_cc_destroy(context, id); if (ret) krb5_err (context, 1, ret, "krb5_cc_destroy"); } else { ret = krb5_cc_close(context, id); if (ret) krb5_err (context, 1, ret, "krb5_cc_close"); } krb5_free_context (context); return exit_value; }
static krb5_error_code get_new_cache(krb5_context context, krb5_principal client, const char *password, krb5_prompter_fct prompter, const char *keytab, const char *server_name, krb5_ccache *ret_cache) { krb5_error_code ret; krb5_creds cred; krb5_get_init_creds_opt *opt; krb5_ccache id; ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) return ret; krb5_get_init_creds_opt_set_default_flags(context, "kadmin", krb5_principal_get_realm(context, client), opt); krb5_get_init_creds_opt_set_forwardable (opt, FALSE); krb5_get_init_creds_opt_set_proxiable (opt, FALSE); if(password == NULL && prompter == NULL) { krb5_keytab kt; if(keytab == NULL) ret = krb5_kt_default(context, &kt); else ret = krb5_kt_resolve(context, keytab, &kt); if(ret) { krb5_get_init_creds_opt_free(context, opt); return ret; } ret = krb5_get_init_creds_keytab (context, &cred, client, kt, 0, server_name, opt); krb5_kt_close(context, kt); } else { ret = krb5_get_init_creds_password (context, &cred, client, password, prompter, NULL, 0, server_name, opt); } krb5_get_init_creds_opt_free(context, opt); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: return KADM5_BAD_PASSWORD; default: return ret; } ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); if(ret) return ret; ret = krb5_cc_initialize (context, id, cred.client); if (ret) return ret; ret = krb5_cc_store_cred (context, id, &cred); if (ret) return ret; krb5_free_cred_contents (context, &cred); *ret_cache = id; return 0; }
static void generate_requests(const char *filename, unsigned nreq) { krb5_context context; krb5_error_code ret; int i; char **words; unsigned nwords, k; ret = krb5_init_context(&context); if (ret) errx (1, "krb5_init_context failed: %d", ret); nwords = read_words(filename, &words); for (i = 0; i < nreq; ++i) { char *name = words[rand() % nwords]; krb5_get_init_creds_opt *opt; krb5_creds cred; krb5_principal principal; int result_code; krb5_data result_code_string, result_string; char *old_pwd, *new_pwd; int aret; krb5_get_init_creds_opt_alloc(context, &opt); krb5_get_init_creds_opt_set_tkt_life (opt, 300); krb5_get_init_creds_opt_set_forwardable (opt, FALSE); krb5_get_init_creds_opt_set_proxiable (opt, FALSE); ret = krb5_parse_name(context, name, &principal); if (ret) krb5_err(context, 1, ret, "krb5_parse_name %s", name); aret = asprintf(&old_pwd, "%s", name); if (aret == -1) krb5_errx(context, 1, "out of memory"); aret = asprintf(&new_pwd, "%s2", name); if (aret == -1) krb5_errx(context, 1, "out of memory"); ret = krb5_get_init_creds_password(context, &cred, principal, old_pwd, nop_prompter, NULL, 0, "kadmin/changepw", opt); if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY || ret == KRB5KRB_AP_ERR_MODIFIED) { char *tmp; tmp = new_pwd; new_pwd = old_pwd; old_pwd = tmp; ret = krb5_get_init_creds_password(context, &cred, principal, old_pwd, nop_prompter, NULL, 0, "kadmin/changepw", opt); } if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_password"); krb5_free_principal(context, principal); ret = krb5_set_password(context, &cred, new_pwd, NULL, &result_code, &result_code_string, &result_string); if (ret) krb5_err(context, 1, ret, "krb5_change_password"); free(old_pwd); free(new_pwd); krb5_free_cred_contents(context, &cred); krb5_get_init_creds_opt_free(context, opt); } for (k = 0; k < nwords; k++) free(words[k]); free(words); }
int main(int argc, char *argv[]) { const char *principal, *password; krb5_principal client; krb5_get_init_creds_opt *opts; krb5_creds creds; krb5_error_code ret, test_return_code; if (argc != 3) { fprintf(stderr, "Usage: %s princname password\n", argv[0]); exit(1); } principal = argv[1]; password = argv[2]; check(krb5_init_context(&ctx)); check(krb5_parse_name(ctx, principal, &client)); /* Use a send hook to modify an outgoing AS-REQ. The library will detect * the modification in the reply. */ check(krb5_get_init_creds_opt_alloc(ctx, &opts)); krb5_get_init_creds_opt_set_canonicalize(opts, 1); krb5_set_kdc_send_hook(ctx, test_send_as_req, NULL); krb5_set_kdc_recv_hook(ctx, test_recv_as_rep, NULL); ret = krb5_get_init_creds_password(ctx, &creds, client, password, NULL, NULL, 0, NULL, opts); assert(ret == KRB5_KDCREP_MODIFIED); krb5_get_init_creds_opt_free(ctx, opts); /* Use a send hook to synthesize a KRB-ERROR reply. */ krb5_set_kdc_send_hook(ctx, test_send_error, NULL); krb5_set_kdc_recv_hook(ctx, test_recv_error, NULL); ret = krb5_get_init_creds_password(ctx, &creds, client, password, NULL, NULL, 0, NULL, NULL); assert(ret == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN); /* Use a recv hook to modify a KDC reply. */ krb5_set_kdc_send_hook(ctx, NULL, NULL); krb5_set_kdc_recv_hook(ctx, test_recv_modify_reply, NULL); ret = krb5_get_init_creds_password(ctx, &creds, client, password, NULL, NULL, 0, NULL, NULL); assert(ret == KRB5KRB_AP_ERR_MSG_TYPE); /* Verify that the user data pointer works in the send hook. */ test_return_code = KRB5KDC_ERR_PREAUTH_FAILED; krb5_set_kdc_send_hook(ctx, test_send_return_value, &test_return_code); krb5_set_kdc_recv_hook(ctx, NULL, NULL); ret = krb5_get_init_creds_password(ctx, &creds, client, password, NULL, NULL, 0, NULL, NULL); assert(ret == KRB5KDC_ERR_PREAUTH_FAILED); /* Verify that the user data pointer works in the recv hook. */ test_return_code = KRB5KDC_ERR_NULL_KEY; krb5_set_kdc_send_hook(ctx, NULL, NULL); krb5_set_kdc_recv_hook(ctx, test_recv_return_value, &test_return_code); ret = krb5_get_init_creds_password(ctx, &creds, client, password, NULL, NULL, 0, NULL, NULL); assert(ret == KRB5KDC_ERR_NULL_KEY); krb5_free_principal(ctx, client); krb5_free_context(ctx); return 0; }
Krb5InitCredsOpt::~Krb5InitCredsOpt() { if (options_) { krb5_get_init_creds_opt_free(context_, options_); } }
krb5_error_code KRB5_CALLCONV krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_keytab arg_keytab, krb5_deltat start_time, char *in_tkt_service, krb5_get_init_creds_opt *options) { krb5_error_code ret, ret2; int use_master; krb5_keytab keytab; krb5_gic_opt_ext *opte = NULL; if (arg_keytab == NULL) { if ((ret = krb5_kt_default(context, &keytab))) return ret; } else { keytab = arg_keytab; } ret = krb5int_gic_opt_to_opte(context, options, &opte, 1, "krb5_get_init_creds_keytab"); if (ret) return ret; /* * Solaris Kerberos: * If "client" was constructed from krb5_sname_to_princ() it may * have a referral realm. This happens when there is no applicable * domain-to-realm mapping in the Kerberos configuration file. * If that is the case then the realm of the first principal found * in the keytab which matches the client can be used for the client's * realm. */ if (krb5_is_referral_realm(&client->realm)) { krb5_data realm; ret = krb5_kt_find_realm(context, keytab, client, &realm); if (ret == 0) { krb5_free_data_contents(context, &client->realm); client->realm.length = realm.length; client->realm.data = realm.data; } else { /* Try to set a useful error message */ char *princ = NULL; krb5_unparse_name(context, client, &princ); krb5_set_error_message(context, ret, gettext("Failed to find realm for %s in keytab"), princ ? princ : "<unknown>"); if (princ) krb5_free_unparsed_name(context, princ); } } if (ret != 0) goto cleanup; use_master = 0; /* first try: get the requested tkt from any kdc */ ret = krb5_get_init_creds(context, creds, client, NULL, NULL, start_time, in_tkt_service, opte, krb5_get_as_key_keytab, (void *) keytab, &use_master,NULL); /* check for success */ if (ret == 0) goto cleanup; /* If all the kdc's are unavailable fail */ if ((ret == KRB5_KDC_UNREACH) || (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) { use_master = 1; ret2 = krb5_get_init_creds(context, creds, client, NULL, NULL, start_time, in_tkt_service, opte, krb5_get_as_key_keytab, (void *) keytab, &use_master, NULL); if (ret2 == 0) { ret = 0; goto cleanup; } /* if the master is unreachable, return the error from the slave we were able to contact */ if ((ret2 == KRB5_KDC_UNREACH) || (ret2 == KRB5_REALM_CANT_RESOLVE) || (ret2 == KRB5_REALM_UNKNOWN)) goto cleanup; ret = ret2; } /* at this point, we have a response from the master. Since we don't do any prompting or changing for keytabs, that's it. */ cleanup: if (opte && krb5_gic_opt_is_shadowed(opte)) krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte); if (arg_keytab == NULL) (void) krb5_kt_close(context, keytab); /* Solaris Kerberos */ return(ret); }
static krb5_error_code get_ccache(krb5_context context, int *destroy, krb5_ccache *id) { krb5_principal principal = NULL; krb5_error_code ret; krb5_keytab kt = NULL; *id = NULL; if (!issuid()) { const char *cache; cache = getenv("NTLM_ACCEPTOR_CCACHE"); if (cache) { ret = krb5_cc_resolve(context, cache, id); if (ret) goto out; return 0; } } ret = krb5_sname_to_principal(context, NULL, "host", KRB5_NT_SRV_HST, &principal); if (ret) goto out; ret = krb5_cc_cache_match(context, principal, id); if (ret == 0) return 0; /* did not find in default credcache, lets try default keytab */ ret = krb5_kt_default(context, &kt); if (ret) goto out; /* XXX check in keytab */ { krb5_get_init_creds_opt *opt; krb5_creds cred; memset(&cred, 0, sizeof(cred)); ret = krb5_cc_new_unique(context, "MEMORY", NULL, id); if (ret) goto out; *destroy = 1; ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) goto out; ret = krb5_get_init_creds_keytab (context, &cred, principal, kt, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if (ret) goto out; ret = krb5_cc_initialize (context, *id, cred.client); if (ret) { krb5_free_cred_contents (context, &cred); goto out; } ret = krb5_cc_store_cred (context, *id, &cred); krb5_free_cred_contents (context, &cred); if (ret) goto out; } krb5_kt_close(context, kt); return 0; out: if (*id) { if (*destroy) krb5_cc_destroy(context, *id); else krb5_cc_close(context, *id); *id = NULL; } if (kt) krb5_kt_close(context, kt); if (principal) krb5_free_principal(context, principal); return ret; }
/* * username, password: Credentials to validate. Null not allowed * service: Service principal (e.g. HTTP/somehost.example.org) of key * stored in default keytab which will be used to verify KDC. * Empty string (*not* NULL) will bypass KDC verification * return: response->return_code will be * -1 (AUTH_GSS_ERROR) for error, see response->message * 0 for auth fail * 1 for auth ok */ gss_client_response *authenticate_user_krb5_password(const char *username, const char *password, const char *service) { krb5_context context = NULL; krb5_error_code problem; krb5_principal user_principal = NULL; krb5_get_init_creds_opt *opt = NULL; krb5_creds creds; bool auth_ok = false; gss_client_response *response = NULL; if (username == NULL || password == NULL || service == NULL) { return other_error("username, password and service must all be non-null"); } memset(&creds, 0, sizeof(creds)); problem = krb5_init_context(&context); if (problem) { // can't call krb5_ctx_error without a context... response = other_error("unable to initialize krb5 context (%d)", (int)problem); goto out; } problem = krb5_parse_name(context, username, &user_principal); if (problem) { response = krb5_ctx_error(context, problem); goto out; } problem = krb5_get_init_creds_opt_alloc(context, &opt); if (problem) { response = krb5_ctx_error(context, problem); goto out; } problem = krb5_get_init_creds_password(context, &creds, user_principal, (char *)password, NULL, NULL, 0, NULL, opt); switch (problem) { case 0: auth_ok = true; break; case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: /* "expected" error */ auth_ok = false; break; default: /* unexpected error */ response = krb5_ctx_error(context, problem); break; } if (auth_ok && strlen(service) > 0) { response = verify_krb5_kdc(context, &creds, service); } out: krb5_free_cred_contents(context, &creds); if (opt != NULL) { krb5_get_init_creds_opt_free(context, opt); } if (user_principal != NULL) { krb5_free_principal(context, user_principal); } if (context != NULL) { krb5_free_context(context); } if (response == NULL) { response = calloc(1, sizeof(gss_client_response)); if(response == NULL) die1("Memory allocation failed"); response->return_code = auth_ok ? 1 : 0; } return response; }