static void test_get_init_creds(krb5_context context, krb5_principal client) { krb5_error_code ret; krb5_get_init_creds_opt *opt; krb5_creds cred; ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); ret = krb5_get_init_creds_opt_set_process_last_req(context, opt, lr_proc, NULL); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_process_last_req"); ret = krb5_get_init_creds_password(context, &cred, client, password_str, krb5_prompter_posix, NULL, 0, NULL, opt); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_password"); krb5_get_init_creds_opt_free(context, opt); }
static krb5_error_code verify_user_opt_int(krb5_context context, krb5_principal principal, const char *password, krb5_verify_opt *vopt) { krb5_error_code ret; krb5_get_init_creds_opt *opt; krb5_creds cred; ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) return ret; krb5_get_init_creds_opt_set_default_flags(context, NULL, krb5_principal_get_realm(context, principal), opt); ret = krb5_get_init_creds_password (context, &cred, principal, password, krb5_prompter_posix, NULL, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if(ret) return ret; #define OPT(V, D) ((vopt && (vopt->V)) ? (vopt->V) : (D)) return verify_common (context, principal, OPT(ccache, NULL), OPT(keytab, NULL), vopt ? vopt->secure : TRUE, OPT(service, "host"), cred); #undef OPT }
static void get_creds(krb5_context context, const char *keytab_str, krb5_ccache *cache, const char *serverhost) { krb5_keytab keytab; krb5_principal client; krb5_error_code ret; krb5_get_init_creds_opt *init_opts; krb5_creds creds; char *server; char keytab_buf[256]; int aret; if (keytab_str == NULL) { ret = krb5_kt_default_name (context, keytab_buf, sizeof(keytab_buf)); if (ret) krb5_err (context, 1, ret, "krb5_kt_default_name"); keytab_str = keytab_buf; } ret = krb5_kt_resolve(context, keytab_str, &keytab); if(ret) krb5_err(context, 1, ret, "%s", keytab_str); ret = krb5_sname_to_principal (context, slave_str, IPROP_NAME, KRB5_NT_SRV_HST, &client); if (ret) krb5_err(context, 1, ret, "krb5_sname_to_principal"); ret = krb5_get_init_creds_opt_alloc(context, &init_opts); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); aret = asprintf (&server, "%s/%s", IPROP_NAME, serverhost); if (aret == -1 || server == NULL) krb5_errx (context, 1, "malloc: no memory"); ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, server, init_opts); free (server); krb5_get_init_creds_opt_free(context, init_opts); if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); ret = krb5_kt_close(context, keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, cache); if(ret) krb5_err(context, 1, ret, "krb5_cc_new_unique"); ret = krb5_cc_initialize(context, *cache, client); if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_store_cred(context, *cache, &creds); if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); krb5_free_cred_contents(context, &creds); krb5_free_principal(context, client); }
/* * Initialise the krb5_init_creds context for the IAKERB context */ static krb5_error_code iakerb_init_creds_ctx(iakerb_ctx_id_t ctx, krb5_gss_cred_id_t cred, OM_uint32 time_req) { krb5_error_code code; if (cred->iakerb_mech == 0) { code = EINVAL; goto cleanup; } assert(cred->name != NULL); assert(cred->name->princ != NULL); code = krb5_get_init_creds_opt_alloc(ctx->k5c, &ctx->gic_opts); if (code != 0) goto cleanup; if (time_req != 0 && time_req != GSS_C_INDEFINITE) krb5_get_init_creds_opt_set_tkt_life(ctx->gic_opts, time_req); code = krb5_get_init_creds_opt_set_out_ccache(ctx->k5c, ctx->gic_opts, cred->ccache); if (code != 0) goto cleanup; code = krb5_init_creds_init(ctx->k5c, cred->name->princ, NULL, /* prompter */ NULL, /* data */ 0, /* start_time */ ctx->gic_opts, &ctx->icc); if (code != 0) goto cleanup; if (cred->password != NULL) { code = krb5_init_creds_set_password(ctx->k5c, ctx->icc, cred->password); } else if (cred->client_keytab != NULL) { code = krb5_init_creds_set_keytab(ctx->k5c, ctx->icc, cred->client_keytab); } else { code = KRB5_KT_NOTFOUND; } if (code != 0) goto cleanup; cleanup: return code; }
krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_alloc( krb5_context context, krb5_get_init_creds_opt **opt) { #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC return krb5_get_init_creds_opt_alloc(context, opt); #else *opt = calloc(1, sizeof(krb5_get_init_creds_opt)); if (*opt == NULL) { return ENOMEM; } krb5_get_init_creds_opt_init(*opt); return 0; #endif }
int kinit_initialize(void) { Log( LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_initialize\n" ); krb5_error_code rc; struct re_s *task = NULL; kid = ch_calloc(1, sizeof(kinit_data) ); rc = krb5_init_context( &kid->ctx ); if ( !rc ) rc = krb5_cc_default(kid->ctx, &kid->ccache ); if ( !rc ) { if (!principal) { int len=STRLENOF("ldap/")+global_host_bv.bv_len+1; principal=ch_calloc(len, 1); snprintf(principal, len, "ldap/%s", global_host_bv.bv_val); Log(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Principal <%s>\n", principal ); } rc = krb5_parse_name(kid->ctx, principal, &kid->princ); } if ( !rc && kt_name) { rc = krb5_kt_resolve(kid->ctx, kt_name, &kid->keytab); } if ( !rc ) rc = krb5_get_init_creds_opt_alloc(kid->ctx, &kid->opts); if ( !rc ) rc = krb5_get_init_creds_opt_set_out_ccache( kid->ctx, kid->opts, kid->ccache); if ( !rc ) { ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); task = ldap_pvt_runqueue_insert( &slapd_rq, 10, kinit_qtask, (void*)kid, "kinit_qtask", "ldap/[email protected]" ); ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); } if (rc) { log_krb5_errmsg(kid->ctx, "kinit_initialize", rc); rc = -1; } return rc; }
static int HandleOP(AcquireCreds) { char *name, *password; int32_t gsm_error, flags, handle = 0; krb5_principal principal = NULL; krb5_get_init_creds_opt *opt = NULL; krb5_error_code ret; retstring(c, name); retstring(c, password); ret32(c, flags); logmessage(c, __FILE__, __LINE__, 0, "username: %s password: %s", name, password); ret = krb5_parse_name(context, name, &principal); if (ret) { gsm_error = convert_krb5_to_gsm(ret); goto out; } 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_pa_password(context, opt, password, NULL); gsm_error = acquire_cred(c, principal, opt, &handle); out: logmessage(c, __FILE__, __LINE__, 0, "AcquireCreds handle: %d return code: %d", handle, gsm_error); if (opt) krb5_get_init_creds_opt_free (context, opt); if (principal) krb5_free_principal(context, principal); free(name); free(password); put32(c, gsm_error); put32(c, handle); return 0; }
static int k5ping(krb5_context ctx, const char *host, int socktype, krb5_principal princ, int use_kt, const char *passwd, krb5_principal sprinc) { K5BAIL_DECLS; krb5_error_code kerr; krb5_ccache ccache = NULL; krb5_keytab kt; krb5_creds creds; krb5_get_init_creds_opt *opt = NULL; VERBOSE(1, (stderr, "initiating kerberos5/%s ping to %s\n", socktype == SOCK_DGRAM ? "udp" : "tcp", host)); parse_kdc(host); current_socktype = socktype; K5BAIL(krb5_cc_resolve(ctx, "MEMORY:k5ping", &ccache)); K5BAIL(krb5_get_init_creds_opt_alloc(ctx, &opt)); krb5_get_init_creds_opt_set_tkt_life(opt, 15 * 60); if (use_kt) { K5BAIL(krb5_kt_default(ctx, &kt)); K5BAIL(krb5_get_init_creds_keytab(ctx, &creds, princ, kt, 0, NULL, opt)); } else { K5BAIL(krb5_get_init_creds_password(ctx, &creds, princ, passwd, krb5_prompter_posix, NULL, 0, NULL, opt)); } K5BAIL(krb5_cc_store_cred(ctx, ccache, &creds)); kret = kvno5(ctx, host, socktype, princ, sprinc, ccache); done: if (ccache) krb5_cc_destroy(ctx, ccache); /* XXXrcd: free a few more things here... */ /* opt. creds. */ if (croakstr[0]) fail_msg("kerberos5", socktype, host, croakstr); return kret; }
static void get_creds(krb5_context context, krb5_ccache *cache) { krb5_keytab keytab; krb5_principal client; krb5_error_code ret; krb5_get_init_creds_opt *init_opts; krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP; krb5_creds creds; ret = krb5_kt_register(context, &hdb_kt_ops); if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); ret = krb5_kt_resolve(context, ktname, &keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); ret = krb5_make_principal(context, &client, NULL, "kadmin", HPROP_NAME, NULL); if(ret) krb5_err(context, 1, ret, "krb5_make_principal"); ret = krb5_get_init_creds_opt_alloc(context, &init_opts); if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); krb5_get_init_creds_opt_set_preauth_list(init_opts, &preauth, 1); ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, NULL, init_opts); if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); krb5_get_init_creds_opt_free(context, init_opts); ret = krb5_kt_close(context, keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, cache); if(ret) krb5_err(context, 1, ret, "krb5_cc_new_unique"); ret = krb5_cc_initialize(context, *cache, client); if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); krb5_free_principal(context, client); ret = krb5_cc_store_cred(context, *cache, &creds); if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); krb5_free_cred_contents(context, &creds); }
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; }
/* * Test whether anonymous authentication works. If this doesn't, we need to * skip the tests of anonymous FAST. */ static bool anon_fast_works(void) { krb5_context ctx; krb5_error_code retval; krb5_principal princ = NULL; char *realm; krb5_creds creds; krb5_get_init_creds_opt *opts = NULL; /* Construct the anonymous principal name. */ retval = krb5_init_context(&ctx); if (retval != 0) bail("cannot initialize Kerberos"); retval = krb5_get_default_realm(ctx, &realm); if (retval != 0) bail("cannot get default realm"); retval = krb5_build_principal_ext(ctx, &princ, strlen(realm), realm, strlen(KRB5_WELLKNOWN_NAME), KRB5_WELLKNOWN_NAME, strlen(KRB5_ANON_NAME), KRB5_ANON_NAME, NULL); if (retval != 0) bail("cannot construct anonymous principal"); krb5_free_default_realm(ctx, realm); /* Obtain the credentials. */ memset(&creds, 0, sizeof(creds)); retval = krb5_get_init_creds_opt_alloc(ctx, &opts); if (retval != 0) bail("cannot create credential options"); krb5_get_init_creds_opt_set_anonymous(opts, 1); krb5_get_init_creds_opt_set_tkt_life(opts, 60); retval = krb5_get_init_creds_password(ctx, &creds, princ, NULL, NULL, NULL, 0, NULL, opts); /* Clean up. */ if (princ != NULL) krb5_free_principal(ctx, princ); if (opts != NULL) krb5_get_init_creds_opt_free(ctx, opts); krb5_free_cred_contents(ctx, &creds); return (retval == 0); }
krb5_error_code smb_krb5_get_init_creds_opt_alloc(krb5_context context, krb5_get_init_creds_opt **opt) { #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC /* Heimdal or modern MIT version */ return krb5_get_init_creds_opt_alloc(context, opt); #else /* Historical MIT version */ krb5_get_init_creds_opt *my_opt; *opt = NULL; if ((my_opt = SMB_MALLOC(sizeof(krb5_get_init_creds_opt))) == NULL) { return ENOMEM; } krb5_get_init_creds_opt_init(my_opt); *opt = my_opt; return 0; #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC */ }
int main(int argc, char **argv) { krb5_context ctx; krb5_get_init_creds_opt *opt; char *user, *password, *service = NULL; krb5_boolean use_cb; krb5_principal client; krb5_creds creds; if (argc < 4) { fprintf(stderr, "Usage: %s username password {1|0} [service]\n", argv[0]); return 1; } user = argv[1]; password = argv[2]; use_cb = atoi(argv[3]); if (argc >= 5) service = argv[4]; assert(krb5_init_context(&ctx) == 0); assert(krb5_get_init_creds_opt_alloc(ctx, &opt) == 0); if (use_cb) { assert(krb5_get_init_creds_opt_set_expire_callback(ctx, opt, expire_cb, &exp_dummy) == 0); } assert(krb5_parse_name(ctx, user, &client) == 0); assert(krb5_get_init_creds_password(ctx, &creds, client, password, prompter_cb, &prompt_dummy, 0, service, opt) == 0); krb5_get_init_creds_opt_free(ctx, opt); krb5_free_principal(ctx, client); krb5_free_cred_contents(ctx, &creds); return 0; }
/* * Acquires an initiator credential from a ccache or using a keytab. */ static OM_uint32 acquire_initiator_cred(OM_uint32 *minor_status, krb5_context context, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gsskrb5_cred handle) { OM_uint32 ret = GSS_S_FAILURE; krb5_creds cred; krb5_get_init_creds_opt *opt; krb5_principal def_princ = NULL; krb5_ccache def_ccache = NULL; krb5_ccache ccache = NULL; /* we may store into this ccache */ krb5_keytab keytab = NULL; krb5_error_code kret = 0; OM_uint32 left; time_t lifetime = 0; time_t now; memset(&cred, 0, sizeof(cred)); /* * Get current time early so we can set handle->endtime to a value that * cannot accidentally be past the real endtime. We need a variant of * krb5_cc_get_lifetime() that returns absolute endtime. */ krb5_timeofday(context, &now); /* * First look for a ccache that has the desired_name (which may be * the default credential name). * * If we don't have an unexpired credential, acquire one with a * keytab. * * If we acquire one with a keytab, save it in the ccache we found * with the expired credential, if any. * * If we don't have any such ccache, then use a MEMORY ccache. */ if (handle->principal != NULL) { /* * Not default credential case. See if we can find a ccache in * the cccol for the desired_name. */ kret = krb5_cc_cache_match(context, handle->principal, &ccache); if (kret == 0) { kret = krb5_cc_get_lifetime(context, ccache, &lifetime); if (kret == 0) { if (lifetime > 0) goto found; else goto try_keytab; } } /* * Fall through. We shouldn't find this in the default ccache * either, but we'll give it a try, then we'll try using a keytab. */ } /* * Either desired_name was GSS_C_NO_NAME (default cred) or * krb5_cc_cache_match() failed (or found expired). */ kret = krb5_cc_default(context, &def_ccache); if (kret != 0) goto try_keytab; kret = krb5_cc_get_lifetime(context, def_ccache, &lifetime); if (kret != 0) lifetime = 0; kret = krb5_cc_get_principal(context, def_ccache, &def_princ); if (kret != 0) goto try_keytab; /* * Have a default ccache; see if it matches desired_name. */ if (handle->principal == NULL || krb5_principal_compare(context, handle->principal, def_princ) == TRUE) { /* * It matches. * * If we end up trying a keytab then we can write the result to * the default ccache. */ if (handle->principal == NULL) { kret = krb5_copy_principal(context, def_princ, &handle->principal); if (kret) goto end; } if (ccache != NULL) krb5_cc_close(context, ccache); ccache = def_ccache; def_ccache = NULL; if (lifetime > 0) goto found; /* else we fall through and try using a keytab */ } try_keytab: if (handle->principal == NULL) { /* We need to know what client principal to use */ kret = krb5_get_default_principal(context, &handle->principal); if (kret) goto end; } kret = get_keytab(context, &keytab); if (kret) goto end; kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; krb5_timeofday(context, &now); kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, keytab, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; /* * We got a credential with a keytab. Save it if we can. */ if (ccache == NULL) { /* * There's no ccache we can overwrite with the credentials we acquired * with a keytab. We'll use a MEMORY ccache then. * * Note that an application that falls into this repeatedly will do an * AS exchange every time it acquires a credential handle. Hopefully * this doesn't happen much. A workaround is to kinit -k once so that * we always re-initialize the matched/default ccache here. I.e., once * there's a FILE/DIR ccache, we'll keep it frash automatically if we * have a keytab, but if there's no FILE/DIR ccache, then we'll * get a fresh credential *every* time we're asked. */ kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if (kret) goto end; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; } /* else we'll re-initialize whichever ccache we matched above */ kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) goto end; kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) goto end; found: assert(handle->principal != NULL); ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &left); if (ret != GSS_S_COMPLETE) goto end; handle->endtime = now + left; handle->ccache = ccache; ccache = NULL; ret = GSS_S_COMPLETE; kret = 0; end: if (ccache != NULL) { if ((handle->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) != 0) krb5_cc_destroy(context, ccache); else krb5_cc_close(context, ccache); } if (def_ccache != NULL) krb5_cc_close(context, def_ccache); if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (def_princ != NULL) krb5_free_principal(context, def_princ); if (keytab != NULL) krb5_kt_close(context, keytab); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }
krb5_error_code kcm_ccache_acquire(krb5_context context, kcm_ccache ccache, time_t *expire) { krb5_error_code ret = 0; krb5_creds cred; krb5_const_realm realm; krb5_get_init_creds_opt *opt = NULL; krb5_ccache_data ccdata; char *in_tkt_service = NULL; *expire = 0; memset(&cred, 0, sizeof(cred)); KCM_ASSERT_VALID(ccache); /* We need a cached key or keytab to acquire credentials */ if (ccache->flags & KCM_FLAGS_USE_PASSWORD) { if (ccache->password == NULL) krb5_abortx(context, "kcm_ccache_acquire: KCM_FLAGS_USE_PASSWORD without password"); } else if (ccache->flags & KCM_FLAGS_USE_KEYTAB) { if (ccache->keytab == NULL) krb5_abortx(context, "kcm_ccache_acquire: KCM_FLAGS_USE_KEYTAB without keytab"); } else { kcm_log(0, "Cannot acquire initial credentials for cache %s without key", ccache->name); return KRB5_FCC_INTERNAL; } /* Fake up an internal ccache */ kcm_internal_ccache(context, ccache, &ccdata); /* Now, actually acquire the creds */ if (ccache->server != NULL) { ret = krb5_unparse_name(context, ccache->server, &in_tkt_service); if (ret) { kcm_log(0, "Failed to unparse service name for cache %s", ccache->name); return ret; } } realm = krb5_principal_get_realm(context, ccache->client); ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) goto out; krb5_get_init_creds_opt_set_default_flags(context, "kcm", realm, opt); if (ccache->tkt_life != 0) krb5_get_init_creds_opt_set_tkt_life(opt, ccache->tkt_life); if (ccache->renew_life != 0) krb5_get_init_creds_opt_set_renew_life(opt, ccache->renew_life); krb5_get_init_creds_opt_set_forwardable(opt, 1); if (ccache->flags & KCM_FLAGS_USE_PASSWORD) { ret = krb5_get_init_creds_password(context, &cred, ccache->client, ccache->password, NULL, NULL, 0, in_tkt_service, opt); } else { ret = krb5_get_init_creds_keytab(context, &cred, ccache->client, ccache->keytab, 0, in_tkt_service, opt); } if (ret) { const char *msg = krb5_get_error_message(context, ret); kcm_log(0, "Failed to acquire credentials for cache %s: %s", ccache->name, msg); krb5_free_error_message(context, msg); if (in_tkt_service != NULL) free(in_tkt_service); goto out; } if (in_tkt_service != NULL) free(in_tkt_service); /* Swap them in */ kcm_ccache_remove_creds_internal(context, ccache); ret = kcm_ccache_store_cred_internal(context, ccache, &cred, NULL, 0); if (ret) { const char *msg = krb5_get_error_message(context, ret); kcm_log(0, "Failed to store credentials for cache %s: %s", ccache->name, msg); krb5_free_error_message(context, msg); krb5_free_cred_contents(context, &cred); goto out; } *expire = cred.times.endtime; out: if (opt) krb5_get_init_creds_opt_free(context, opt); return ret; }
static krb5_error_code get_new_cache(krb5_context context, krb5_principal client, const char *password, krb5_prompter_fct prompter, const char *keytab, const char *server_name, krb5_ccache *ret_cache) { krb5_error_code ret; krb5_creds cred; krb5_get_init_creds_opt *opt; krb5_ccache id; ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) return ret; krb5_get_init_creds_opt_set_default_flags(context, "kadmin", krb5_principal_get_realm(context, client), opt); krb5_get_init_creds_opt_set_forwardable (opt, FALSE); krb5_get_init_creds_opt_set_proxiable (opt, FALSE); if(password == NULL && prompter == NULL) { krb5_keytab kt; if(keytab == NULL) ret = krb5_kt_default(context, &kt); else ret = krb5_kt_resolve(context, keytab, &kt); if(ret) { krb5_get_init_creds_opt_free(context, opt); return ret; } ret = krb5_get_init_creds_keytab (context, &cred, client, kt, 0, server_name, opt); krb5_kt_close(context, kt); } else { ret = krb5_get_init_creds_password (context, &cred, client, password, prompter, NULL, 0, server_name, opt); } krb5_get_init_creds_opt_free(context, opt); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: return KADM5_BAD_PASSWORD; default: return ret; } ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); if(ret) return ret; ret = krb5_cc_initialize (context, id, cred.client); if (ret) return ret; ret = krb5_cc_store_cred (context, id, &cred); if (ret) return ret; krb5_free_cred_contents (context, &cred); *ret_cache = id; return 0; }
DWORD VMCALoginUserPrivate( PCSTR pszUserName, const char* pszPassword ) /* VMCALoginUser Creates a TGT cache for the Process to communicate with the VMCA */ { 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 }; krb5_error_code err_code = 0; #ifdef DEBUG_KRB PSTR pszErrstr = NULL; #endif err_code = krb5_init_context(&context); BAIL_ON_ERROR(err_code); // it is assumed that pszUserName is in user@REALM format. err_code = krb5_parse_name_flags( context, pszUserName, KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal); BAIL_ON_ERROR(err_code); // Find the default cred cache err_code = krb5_cc_default(context, &ccache); BAIL_ON_ERROR(err_code); #ifdef DEBUG_KRB printf("Default Cache Name is : %s\n", krb5_cc_default_name(context)); #endif err_code = krb5_get_init_creds_opt_alloc(context, &opt); BAIL_ON_ERROR(err_code); krb5_get_init_creds_opt_set_tkt_life(opt, 2 * 60 * 60); //2 hours ticket krb5_get_init_creds_opt_set_forwardable(opt, 1); // Let us get the Creds from the Kerberos Server err_code = krb5_get_init_creds_password( context, &creds, principal, (PSTR) pszPassword, NULL, NULL, 0, NULL, opt); BAIL_ON_ERROR(err_code); err_code = krb5_cc_store_cred(context, ccache, &creds); if ( err_code == KRB5_FCC_NOFILE){ krb5_cc_initialize(context, ccache, principal); err_code = krb5_cc_store_cred(context, ccache, &creds); BAIL_ON_ERROR(err_code); } BAIL_ON_ERROR(err_code); cleanup: if(principal != NULL) { krb5_free_principal(context, principal); } if(opt != NULL){ krb5_get_init_creds_opt_free(context,opt); } if ( ccache != NULL) { krb5_cc_close(context, ccache); } krb5_free_cred_contents(context, &creds); if(context != NULL){ krb5_free_context(context); } return dwError; error : #ifdef DEBUG_KRB pszErrstr = (PSTR) krb5_get_error_message(context, err_code); printf("Error code : %d\n", err_code); printf("Error Message : %s\n", pszErrstr); krb5_free_error_message(context, (const char *)pszErrstr); #endif dwError = err_code; goto cleanup; }
/* call-seq: * krb5.get_init_creds_keytab(principal = nil, keytab = nil, service = nil, ccache = nil) * * Acquire credentials for +principal+ from +keytab+ using +service+. If * no principal is specified, then a principal is derived from the service * name. If no service name is specified, kerberos defaults to "host". * * If no keytab file is provided, the default keytab file is used. This is * typically /etc/krb5.keytab. * * If +ccache+ is supplied and is a Kerberos::Krb5::CredentialsCache, the * resulting credentials will be stored in the credential cache. */ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){ RUBY_KRB5* ptr; VALUE v_user, v_keytab_name, v_service, v_ccache; char* user; char* service; char keytab_name[MAX_KEYTAB_NAME_LEN]; krb5_error_code kerror; krb5_get_init_creds_opt* opt; krb5_creds cred; Data_Get_Struct(self, RUBY_KRB5, ptr); if(!ptr->ctx) rb_raise(cKrb5Exception, "no context has been established"); kerror = krb5_get_init_creds_opt_alloc(ptr->ctx, &opt); if(kerror) rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_alloc: %s", error_message(kerror)); rb_scan_args(argc, argv, "04", &v_user, &v_keytab_name, &v_service, &v_ccache); // We need the service information for later. if(NIL_P(v_service)){ service = NULL; } else{ Check_Type(v_service, T_STRING); service = StringValueCStr(v_service); } // Convert the name (or service name) to a kerberos principal. if(NIL_P(v_user)){ kerror = krb5_sname_to_principal( ptr->ctx, NULL, service, KRB5_NT_SRV_HST, &ptr->princ ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_sname_to_principal: %s", error_message(kerror)); } } else{ Check_Type(v_user, T_STRING); user = StringValueCStr(v_user); kerror = krb5_parse_name(ptr->ctx, user, &ptr->princ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror)); } } // Use the default keytab if none is specified. if(NIL_P(v_keytab_name)){ kerror = krb5_kt_default_name(ptr->ctx, keytab_name, MAX_KEYTAB_NAME_LEN); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_kt_default_name: %s", error_message(kerror)); } } else{ Check_Type(v_keytab_name, T_STRING); strncpy(keytab_name, StringValueCStr(v_keytab_name), MAX_KEYTAB_NAME_LEN); } kerror = krb5_kt_resolve( ptr->ctx, keytab_name, &ptr->keytab ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_kt_resolve: %s", error_message(kerror)); } // Set the credential cache from the supplied Kerberos::Krb5::CredentialsCache if(!NIL_P(v_ccache)){ RUBY_KRB5_CCACHE* ccptr; Data_Get_Struct(v_ccache, RUBY_KRB5_CCACHE, ccptr); kerror = krb5_get_init_creds_opt_set_out_ccache(ptr->ctx, opt, ccptr->ccache); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_set_out_ccache: %s", error_message(kerror)); } } kerror = krb5_get_init_creds_keytab( ptr->ctx, &cred, ptr->princ, ptr->keytab, 0, service, opt ); if(kerror) { krb5_get_init_creds_opt_free(ptr->ctx, opt); rb_raise(cKrb5Exception, "krb5_get_init_creds_keytab: %s", error_message(kerror)); } krb5_get_init_creds_opt_free(ptr->ctx, opt); return self; }
/* 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; }
krb5_error_code kinit_to_ccache(TALLOC_CTX *parent_ctx, struct cli_credentials *credentials, struct smb_krb5_context *smb_krb5_context, struct tevent_context *event_ctx, krb5_ccache ccache, enum credentials_obtained *obtained, const char **error_string) { krb5_error_code ret; const char *password; #ifdef SAMBA4_USES_HEIMDAL const char *self_service; #endif const char *target_service; time_t kdc_time = 0; krb5_principal princ; krb5_principal impersonate_principal; int tries; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); krb5_get_init_creds_opt *krb_options; if (!mem_ctx) { (*error_string) = strerror(ENOMEM); return ENOMEM; } ret = principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &princ, obtained, error_string); if (ret) { talloc_free(mem_ctx); return ret; } if (princ == NULL) { (*error_string) = talloc_asprintf(credentials, "principal, username or realm was not specified in the credentials"); talloc_free(mem_ctx); return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; } ret = impersonate_principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &impersonate_principal, error_string); if (ret) { talloc_free(mem_ctx); return ret; } #ifdef SAMBA4_USES_HEIMDAL self_service = cli_credentials_get_self_service(credentials); #endif target_service = cli_credentials_get_target_service(credentials); password = cli_credentials_get_password(credentials); /* setup the krb5 options we want */ if ((ret = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context, &krb_options))) { (*error_string) = talloc_asprintf(credentials, "krb5_get_init_creds_opt_alloc failed (%s)\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)); talloc_free(mem_ctx); return ret; } #ifdef SAMBA4_USES_HEIMDAL /* Disable for now MIT reads defaults when needed */ /* get the defaults */ krb5_get_init_creds_opt_set_default_flags(smb_krb5_context->krb5_context, NULL, NULL, krb_options); #endif /* set if we want a forwardable ticket */ switch (cli_credentials_get_krb_forwardable(credentials)) { case CRED_AUTO_KRB_FORWARDABLE: break; case CRED_NO_KRB_FORWARDABLE: krb5_get_init_creds_opt_set_forwardable(krb_options, FALSE); break; case CRED_FORCE_KRB_FORWARDABLE: krb5_get_init_creds_opt_set_forwardable(krb_options, TRUE); break; } #ifdef SAMBA4_USES_HEIMDAL /* FIXME: MIT does not have this yet */ /* * In order to work against windows KDCs even if we use * the netbios domain name as realm, we need to add the following * flags: * KRB5_INIT_CREDS_NO_C_CANON_CHECK; * KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK; * * On MIT: Set pkinit_eku_checking to none */ krb5_get_init_creds_opt_set_win2k(smb_krb5_context->krb5_context, krb_options, true); #else /* MIT */ krb5_get_init_creds_opt_set_canonicalize(krb_options, true); #endif tries = 2; while (tries--) { #ifdef SAMBA4_USES_HEIMDAL struct tevent_context *previous_ev; /* Do this every time, in case we have weird recursive issues here */ ret = smb_krb5_context_set_event_ctx(smb_krb5_context, event_ctx, &previous_ev); if (ret) { talloc_free(mem_ctx); return ret; } #endif if (password) { if (impersonate_principal) { #ifdef SAMBA4_USES_HEIMDAL ret = kerberos_kinit_s4u2_cc( smb_krb5_context->krb5_context, ccache, princ, password, impersonate_principal, self_service, target_service, krb_options, NULL, &kdc_time); #else talloc_free(mem_ctx); (*error_string) = "INTERNAL error: s4u2 ops " "are not supported with MIT build yet"; return EINVAL; #endif } else { ret = kerberos_kinit_password_cc( smb_krb5_context->krb5_context, ccache, princ, password, target_service, krb_options, NULL, &kdc_time); } } else if (impersonate_principal) { talloc_free(mem_ctx); (*error_string) = "INTERNAL error: Cannot impersonate principal with just a keyblock. A password must be specified in the credentials"; return EINVAL; } else { /* No password available, try to use a keyblock instead */ krb5_keyblock keyblock; const struct samr_Password *mach_pwd; mach_pwd = cli_credentials_get_nt_hash(credentials, mem_ctx); if (!mach_pwd) { talloc_free(mem_ctx); (*error_string) = "kinit_to_ccache: No password available for kinit\n"; krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, krb_options); #ifdef SAMBA4_USES_HEIMDAL smb_krb5_context_remove_event_ctx(smb_krb5_context, previous_ev, event_ctx); #endif return EINVAL; } ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, mach_pwd->hash, sizeof(mach_pwd->hash), &keyblock); if (ret == 0) { ret = kerberos_kinit_keyblock_cc(smb_krb5_context->krb5_context, ccache, princ, &keyblock, target_service, krb_options, NULL, &kdc_time); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &keyblock); } } #ifdef SAMBA4_USES_HEIMDAL smb_krb5_context_remove_event_ctx(smb_krb5_context, previous_ev, event_ctx); #endif if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) { /* Perhaps we have been given an invalid skew, so try again without it */ time_t t = time(NULL); krb5_set_real_time(smb_krb5_context->krb5_context, t, 0); } else { /* not a skew problem */ break; } } krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, krb_options); if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) { (*error_string) = talloc_asprintf(credentials, "kinit for %s failed (%s)\n", cli_credentials_get_principal(credentials, mem_ctx), smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)); talloc_free(mem_ctx); return ret; } /* cope with ticket being in the future due to clock skew */ if ((unsigned)kdc_time > time(NULL)) { time_t t = time(NULL); int time_offset =(unsigned)kdc_time-t; DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset)); krb5_set_real_time(smb_krb5_context->krb5_context, t + time_offset + 1, 0); } if (ret == KRB5KDC_ERR_PREAUTH_FAILED && cli_credentials_wrong_password(credentials)) { ret = kinit_to_ccache(parent_ctx, credentials, smb_krb5_context, event_ctx, ccache, obtained, error_string); } if (ret) { (*error_string) = talloc_asprintf(credentials, "kinit for %s failed (%s)\n", cli_credentials_get_principal(credentials, mem_ctx), smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)); talloc_free(mem_ctx); return ret; } DEBUG(10,("kinit for %s succeeded\n", cli_credentials_get_principal(credentials, mem_ctx))); talloc_free(mem_ctx); return 0; }
int main(int argc, char **argv) { krb5_context context; krb5_error_code ret; krb5_creds cred; krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP}; krb5_get_init_creds_opt *get_options; krb5_verify_init_creds_opt verify_options; krb5_principal principal = NULL; int optidx = 0; setprogname (argv[0]); if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) usage (0); if(version_flag) { print_version(NULL); exit(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, &get_options); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); krb5_get_init_creds_opt_set_preauth_list (get_options, pre_auth_types, 1); krb5_verify_init_creds_opt_init (&verify_options); if (argc) { ret = krb5_parse_name(context, argv[0], &principal); if (ret) krb5_err(context, 1, ret, "krb5_parse_name: %s", argv[0]); } else { ret = krb5_get_default_principal(context, &principal); if (ret) krb5_err(context, 1, ret, "krb5_get_default_principal"); } ret = krb5_get_init_creds_password (context, &cred, principal, NULL, krb5_prompter_posix, NULL, 0, NULL, get_options); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); ret = krb5_verify_init_creds (context, &cred, NULL, NULL, NULL, &verify_options); if (ret) krb5_err(context, 1, ret, "krb5_verify_init_creds"); krb5_free_cred_contents (context, &cred); krb5_free_context (context); 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); }
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 bool torture_krb5_as_req_creds(struct torture_context *tctx, struct cli_credentials *credentials, enum torture_krb5_test test) { krb5_error_code k5ret; bool ok; krb5_creds my_creds; krb5_principal principal; struct smb_krb5_context *smb_krb5_context; enum credentials_obtained obtained; const char *error_string; const char *password = cli_credentials_get_password(credentials); krb5_get_init_creds_opt *krb_options = NULL; ok = torture_krb5_init_context(tctx, test, &smb_krb5_context); torture_assert(tctx, ok, "torture_krb5_init_context failed"); k5ret = principal_from_credentials(tctx, credentials, smb_krb5_context, &principal, &obtained, &error_string); torture_assert_int_equal(tctx, k5ret, 0, error_string); switch (test) { case TORTURE_KRB5_TEST_PLAIN: break; case TORTURE_KRB5_TEST_PAC_REQUEST: torture_assert_int_equal(tctx, krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context, &krb_options), 0, "krb5_get_init_creds_opt_alloc failed"); torture_assert_int_equal(tctx, krb5_get_init_creds_opt_set_pac_request(smb_krb5_context->krb5_context, krb_options, true), 0, "krb5_get_init_creds_opt_set_pac_request failed"); break; case TORTURE_KRB5_TEST_BREAK_PW: password = "******"; break; case TORTURE_KRB5_TEST_CLOCK_SKEW: torture_assert_int_equal(tctx, krb5_set_real_time(smb_krb5_context->krb5_context, time(NULL) + 3600, 0), 0, "krb5_set_real_time failed"); break; break; } k5ret = krb5_get_init_creds_password(smb_krb5_context->krb5_context, &my_creds, principal, password, NULL, NULL, 0, NULL, krb_options); krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, krb_options); switch (test) { case TORTURE_KRB5_TEST_PLAIN: case TORTURE_KRB5_TEST_PAC_REQUEST: torture_assert_int_equal(tctx, k5ret, 0, "krb5_get_init_creds_password failed"); break; case TORTURE_KRB5_TEST_BREAK_PW: torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_PREAUTH_FAILED, "krb5_get_init_creds_password should have failed"); return true; case TORTURE_KRB5_TEST_CLOCK_SKEW: torture_assert_int_equal(tctx, k5ret, KRB5KRB_AP_ERR_SKEW, "krb5_get_init_creds_password should have failed"); return true; } k5ret = krb5_free_cred_contents(smb_krb5_context->krb5_context, &my_creds); torture_assert_int_equal(tctx, k5ret, 0, "krb5_free_creds failed"); return true; }
/* * This function produces a cred with a MEMORY ccache containing a TGT * acquired with a password. */ static OM_uint32 acquire_cred_with_password(OM_uint32 *minor_status, krb5_context context, const char *password, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gsskrb5_cred handle) { OM_uint32 ret = GSS_S_FAILURE; krb5_creds cred; krb5_get_init_creds_opt *opt; krb5_ccache ccache = NULL; krb5_error_code kret; time_t now; OM_uint32 left; if (cred_usage == GSS_C_ACCEPT) { /* * TODO: Here we should eventually support user2user (when we get * support for that via an extension to the mechanism * allowing for more than two security context tokens), * and/or new unique MEMORY keytabs (we have MEMORY keytab * support, but we don't have a keytab equivalent of * krb5_cc_new_unique()). Either way, for now we can't * support this. */ *minor_status = ENOTSUP; /* XXX Better error? */ return GSS_S_FAILURE; } memset(&cred, 0, sizeof(cred)); 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; /* * Get the current time before the AS exchange so we don't * accidentally end up returning a value that puts advertised * expiration past the real expiration. * * We need to do this because krb5_cc_get_lifetime() returns a * relative time that we need to add to the current time. We ought * to have a version of krb5_cc_get_lifetime() that returns absolute * time... */ krb5_timeofday(context, &now); kret = krb5_get_init_creds_password(context, &cred, handle->principal, password, NULL, NULL, 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) goto end; kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) goto end; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &left); if (ret != GSS_S_COMPLETE) goto end; handle->endtime = now + left; handle->ccache = ccache; ccache = NULL; ret = GSS_S_COMPLETE; kret = 0; end: if (ccache != NULL) krb5_cc_destroy(context, ccache); if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }
static void generate_requests (const char *filename, unsigned nreq) { krb5_context context; krb5_error_code ret; int i; char **words; unsigned nwords; 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); } }
static void kerberos_kinit(void) { char *name, *krbtgt; krb5_error_code code; krb5_context ctx; krb5_ccache ccache; krb5_principal kprinc; krb5_keytab keytab; krb5_get_init_creds_opt *opts; krb5_creds creds; const char *realm; /* * Determine the principal corresponding to that keytab. We copy the * memory to ensure that it's allocated in the right memory domain on * systems where that may matter (like Windows). */ code = krb5_init_context(&ctx); if (code != 0) bail_krb5(ctx, code, "error initializing Kerberos"); kprinc = kerberos_keytab_principal(ctx, config->keytab); code = krb5_unparse_name(ctx, kprinc, &name); if (code != 0) bail_krb5(ctx, code, "error unparsing name"); krb5_free_principal(ctx, kprinc); config->principal = bstrdup(name); krb5_free_unparsed_name(ctx, name); /* Now do the Kerberos initialization. */ code = krb5_cc_default(ctx, &ccache); if (code != 0) bail_krb5(ctx, code, "error setting ticket cache"); code = krb5_parse_name(ctx, config->principal, &kprinc); if (code != 0) bail_krb5(ctx, code, "error parsing principal %s", config->principal); realm = krb5_principal_get_realm(ctx, kprinc); basprintf(&krbtgt, "krbtgt/%s@%s", realm, realm); code = krb5_kt_resolve(ctx, config->keytab, &keytab); if (code != 0) bail_krb5(ctx, code, "cannot open keytab %s", config->keytab); code = krb5_get_init_creds_opt_alloc(ctx, &opts); if (code != 0) bail_krb5(ctx, code, "cannot allocate credential options"); krb5_get_init_creds_opt_set_default_flags(ctx, NULL, realm, opts); krb5_get_init_creds_opt_set_forwardable(opts, 0); krb5_get_init_creds_opt_set_proxiable(opts, 0); code = krb5_get_init_creds_keytab(ctx, &creds, kprinc, keytab, 0, krbtgt, opts); if (code != 0) bail_krb5(ctx, code, "cannot get Kerberos tickets"); code = krb5_cc_initialize(ctx, ccache, kprinc); if (code != 0) bail_krb5(ctx, code, "error initializing ticket cache"); code = krb5_cc_store_cred(ctx, ccache, &creds); if (code != 0) bail_krb5(ctx, code, "error storing credentials"); krb5_cc_close(ctx, ccache); krb5_free_cred_contents(ctx, &creds); krb5_kt_close(ctx, keytab); krb5_free_principal(ctx, kprinc); krb5_get_init_creds_opt_free(ctx, opts); krb5_free_context(ctx); free(krbtgt); }
static int CommandProc(struct cmd_syndesc *as, void *arock) { krb5_principal princ = 0; char *cell, *pname, **hrealms, *service; char service_temp[MAXKTCREALMLEN + 20]; krb5_creds incred[1], mcred[1], *outcred = 0, *afscred; krb5_ccache cc = 0; #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC krb5_get_init_creds_opt *gic_opts; #else krb5_get_init_creds_opt gic_opts[1]; #endif char *tofree = NULL, *outname; int code; char *what; int i, dosetpag, evil, noprdb, id; #ifdef AFS_RXK5 int authtype; #endif krb5_data enc_part[1]; krb5_prompter_fct pf = NULL; char *pass = 0; void *pa = 0; struct kp_arg klog_arg[1]; char passwd[BUFSIZ]; struct afsconf_cell cellconfig[1]; static char rn[] = "klog"; /*Routine name */ static int Pipe = 0; /* reading from a pipe */ static int Silent = 0; /* Don't want error messages */ int writeTicketFile = 0; /* write ticket file to /tmp */ service = 0; memset(incred, 0, sizeof *incred); /* blow away command line arguments */ for (i = 1; i < zero_argc; i++) memset(zero_argv[i], 0, strlen(zero_argv[i])); zero_argc = 0; memset(klog_arg, 0, sizeof *klog_arg); /* first determine quiet flag based on -silent switch */ Silent = (as->parms[aSILENT].items ? 1 : 0); if (Silent) { afs_set_com_err_hook(silent_errors); } if ((code = krb5_init_context(&k5context))) { afs_com_err(rn, code, "while initializing Kerberos 5 library"); KLOGEXIT(code); } if ((code = rx_Init(0))) { afs_com_err(rn, code, "while initializing rx"); KLOGEXIT(code); } initialize_U_error_table(); /*initialize_krb5_error_table();*/ initialize_RXK_error_table(); initialize_KTC_error_table(); initialize_ACFG_error_table(); /* initialize_rx_error_table(); */ if (!(tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))) { afs_com_err(rn, 0, "can't get afs configuration (afsconf_Open(%s))", AFSDIR_CLIENT_ETC_DIRPATH); KLOGEXIT(1); } /* * Enable DES enctypes, which are currently still required for AFS. * krb5_allow_weak_crypto is MIT Kerberos 1.8. krb5_enctype_enable is * Heimdal. */ #if defined(HAVE_KRB5_ENCTYPE_ENABLE) i = krb5_enctype_valid(k5context, ETYPE_DES_CBC_CRC); if (i) krb5_enctype_enable(k5context, ETYPE_DES_CBC_CRC); #elif defined(HAVE_KRB5_ALLOW_WEAK_CRYPTO) krb5_allow_weak_crypto(k5context, 1); #endif /* Parse remaining arguments. */ dosetpag = !! as->parms[aSETPAG].items; Pipe = !! as->parms[aPIPE].items; writeTicketFile = !! as->parms[aTMP].items; noprdb = !! as->parms[aNOPRDB].items; evil = (always_evil&1) || !! as->parms[aUNWRAP].items; #ifdef AFS_RXK5 authtype = 0; if (as->parms[aK5].items) authtype |= FORCE_RXK5; if (as->parms[aK4].items) authtype |= FORCE_RXKAD; if (!authtype) authtype |= env_afs_rxk5_default(); #endif cell = as->parms[aCELL].items ? as->parms[aCELL].items->data : 0; if ((code = afsconf_GetCellInfo(tdir, cell, "afsprot", cellconfig))) { if (cell) afs_com_err(rn, code, "Can't get cell information for '%s'", cell); else afs_com_err(rn, code, "Can't get determine local cell!"); KLOGEXIT(code); } if (as->parms[aKRBREALM].items) { code = krb5_set_default_realm(k5context, as->parms[aKRBREALM].items->data); if (code) { afs_com_err(rn, code, "Can't make <%s> the default realm", as->parms[aKRBREALM].items->data); KLOGEXIT(code); } } else if ((code = krb5_get_host_realm(k5context, cellconfig->hostName[0], &hrealms))) { afs_com_err(rn, code, "Can't get realm for host <%s> in cell <%s>\n", cellconfig->hostName[0], cellconfig->name); KLOGEXIT(code); } else { if (hrealms && *hrealms) { code = krb5_set_default_realm(k5context, *hrealms); if (code) { afs_com_err(rn, code, "Can't make <%s> the default realm", *hrealms); KLOGEXIT(code); } } if (hrealms) krb5_free_host_realm(k5context, hrealms); } id = getuid(); if (as->parms[aPRINCIPAL].items) { pname = as->parms[aPRINCIPAL].items->data; } else { /* No explicit name provided: use Unix uid. */ struct passwd *pw; pw = getpwuid(id); if (pw == 0) { afs_com_err(rn, 0, "Can't figure out your name from your user id (%d).", id); if (!Silent) fprintf(stderr, "%s: Try providing the user name.\n", rn); KLOGEXIT(1); } pname = pw->pw_name; } code = krb5_parse_name(k5context, pname, &princ); if (code) { afs_com_err(rn, code, "Can't parse principal <%s>", pname); KLOGEXIT(code); } if (as->parms[aPASSWORD].items) { /* * Current argument is the desired password string. Remember it in * our local buffer, and zero out the argument string - anyone can * see it there with ps! */ strncpy(passwd, as->parms[aPASSWORD].items->data, sizeof(passwd)); memset(as->parms[aPASSWORD].items->data, 0, strlen(as->parms[aPASSWORD].items->data)); pass = passwd; } /* Get the password if it wasn't provided. */ if (!pass) { if (Pipe) { strncpy(passwd, getpipepass(), sizeof(passwd)); pass = passwd; } else { pf = klog_prompter; pa = klog_arg; } } service = 0; #ifdef AFS_RXK5 if (authtype & FORCE_RXK5) { tofree = get_afs_krb5_svc_princ(cellconfig); snprintf(service_temp, sizeof service_temp, "%s", tofree); } else #endif snprintf (service_temp, sizeof service_temp, "afs/%s", cellconfig->name); klog_arg->pp = &pass; klog_arg->pstore = passwd; klog_arg->allocated = sizeof(passwd); /* XXX should allow k5 to prompt in most cases -- what about expired pw?*/ #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC code = krb5_get_init_creds_opt_alloc(k5context, &gic_opts); if (code) { afs_com_err(rn, code, "Can't allocate get_init_creds options"); KLOGEXIT(code); } #else krb5_get_init_creds_opt_init(gic_opts); #endif for (;;) { code = krb5_get_init_creds_password(k5context, incred, princ, pass, pf, /* prompter */ pa, /* data */ 0, /* start_time */ 0, /* in_tkt_service */ gic_opts); if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) break; } memset(passwd, 0, sizeof(passwd)); if (code) { char *r = 0; if (krb5_get_default_realm(k5context, &r)) r = 0; if (r) afs_com_err(rn, code, "Unable to authenticate in realm %s", r); else afs_com_err(rn, code, "Unable to authenticate to use cell %s", cellconfig->name); if (r) free(r); KLOGEXIT(code); } for (;;writeTicketFile = 0) { if (writeTicketFile) { what = "getting default ccache"; code = krb5_cc_default(k5context, &cc); } else { what = "krb5_cc_resolve"; code = krb5_cc_resolve(k5context, "MEMORY:core", &cc); if (code) goto Failed; } what = "initializing ccache"; code = krb5_cc_initialize(k5context, cc, princ); if (code) goto Failed; what = "writing Kerberos ticket file"; code = krb5_cc_store_cred(k5context, cc, incred); if (code) goto Failed; if (writeTicketFile) fprintf(stderr, "Wrote ticket file to %s\n", krb5_cc_get_name(k5context, cc)); break; Failed: if (code) afs_com_err(rn, code, "%s", what); if (writeTicketFile) { if (cc) { krb5_cc_close(k5context, cc); cc = 0; } continue; } KLOGEXIT(code); } for (service = service_temp;;service = "afs") { memset(mcred, 0, sizeof *mcred); mcred->client = princ; code = krb5_parse_name(k5context, service, &mcred->server); if (code) { afs_com_err(rn, code, "Unable to parse service <%s>\n", service); KLOGEXIT(code); } if (tofree) { free(tofree); tofree = 0; } if (!(code = krb5_unparse_name(k5context, mcred->server, &outname))) tofree = outname; else outname = service; code = krb5_get_credentials(k5context, 0, cc, mcred, &outcred); krb5_free_principal(k5context, mcred->server); if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || service != service_temp) break; #ifdef AFS_RXK5 if (authtype & FORCE_RXK5) break; #endif } afscred = outcred; if (code) { afs_com_err(rn, code, "Unable to get credentials to use %s", outname); KLOGEXIT(code); } #ifdef AFS_RXK5 if (authtype & FORCE_RXK5) { struct ktc_principal aserver[1]; int viceid = 555; memset(aserver, 0, sizeof *aserver); strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1); code = ktc_SetK5Token(k5context, aserver, afscred, viceid, dosetpag); if (code) { afs_com_err(rn, code, "Unable to store tokens for cell %s\n", cellconfig->name); KLOGEXIT(1); } } else #endif { struct ktc_principal aserver[1], aclient[1]; struct ktc_token atoken[1]; memset(atoken, 0, sizeof *atoken); if (evil) { size_t elen = enc_part->length; atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY; if (afs_krb5_skip_ticket_wrapper(afscred->ticket.data, afscred->ticket.length, (char **) &enc_part->data, &elen)) { afs_com_err(rn, 0, "Can't unwrap %s AFS credential", cellconfig->name); KLOGEXIT(1); } } else { atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5; *enc_part = afscred->ticket; } atoken->startTime = afscred->times.starttime; atoken->endTime = afscred->times.endtime; if (tkt_DeriveDesKey(get_creds_enctype(afscred), get_cred_keydata(afscred), get_cred_keylen(afscred), &atoken->sessionKey)) { afs_com_err(rn, 0, "Cannot derive DES key from enctype %i of length %u", get_creds_enctype(afscred), (unsigned)get_cred_keylen(afscred)); KLOGEXIT(1); } memcpy(atoken->ticket, enc_part->data, atoken->ticketLen = enc_part->length); memset(aserver, 0, sizeof *aserver); strncpy(aserver->name, "afs", 4); strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1); memset(aclient, 0, sizeof *aclient); i = realm_len(k5context, afscred->client); if (i > MAXKTCREALMLEN-1) i = MAXKTCREALMLEN-1; memcpy(aclient->cell, realm_data(k5context, afscred->client), i); if (!noprdb) { int viceid = 0; k5_to_k4_name(k5context, afscred->client, aclient); code = whoami(atoken, cellconfig, aclient, &viceid); if (code) { afs_com_err(rn, code, "Can't get your viceid for cell %s", cellconfig->name); *aclient->name = 0; } else snprintf(aclient->name, MAXKTCNAMELEN-1, "AFS ID %d", viceid); } if (!*aclient->name) k5_to_k4_name(k5context, afscred->client, aclient); code = ktc_SetToken(aserver, atoken, aclient, dosetpag); if (code) { afs_com_err(rn, code, "Unable to store tokens for cell %s\n", cellconfig->name); KLOGEXIT(1); } } krb5_free_principal(k5context, princ); krb5_free_cred_contents(k5context, incred); if (outcred) krb5_free_creds(k5context, outcred); if (cc) krb5_cc_close(k5context, cc); if (tofree) free(tofree); return 0; }
static krb5_error_code get_new_tickets(krb5_context context, krb5_principal principal, krb5_ccache ccache, krb5_deltat ticket_life, int interactive) { krb5_error_code ret; krb5_creds cred; char passwd[256]; krb5_deltat start_time = 0; krb5_deltat renew = 0; const char *renewstr = NULL; krb5_enctype *enctype = NULL; krb5_ccache tempccache = NULL; krb5_init_creds_context ctx = NULL; krb5_get_init_creds_opt *opt = NULL; krb5_prompter_fct prompter = krb5_prompter_posix; #ifndef NO_NTLM struct ntlm_buf ntlmkey; memset(&ntlmkey, 0, sizeof(ntlmkey)); #endif passwd[0] = '\0'; if (!interactive) prompter = NULL; if (password_file) { FILE *f; if (strcasecmp("STDIN", password_file) == 0) f = stdin; else f = fopen(password_file, "r"); if (f == NULL) { krb5_warnx(context, "Failed to open the password file %s", password_file); return errno; } if (fgets(passwd, sizeof(passwd), f) == NULL) { krb5_warnx(context, N_("Failed to read password from file %s", ""), password_file); fclose(f); return EINVAL; /* XXX Need a better error */ } if (f != stdin) fclose(f); passwd[strcspn(passwd, "\n")] = '\0'; } #ifdef __APPLE__ if (passwd[0] == '\0') { const char *realm; OSStatus osret; UInt32 length; void *buffer; char *name; realm = krb5_principal_get_realm(context, principal); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret) goto nopassword; osret = SecKeychainFindGenericPassword(NULL, strlen(realm), realm, strlen(name), name, &length, &buffer, NULL); free(name); if (osret == noErr && length < sizeof(passwd) - 1) { memcpy(passwd, buffer, length); passwd[length] = '\0'; } nopassword: do { } while(0); } #endif memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) { krb5_warn(context, ret, "krb5_get_init_creds_opt_alloc"); goto out; } krb5_get_init_creds_opt_set_default_flags(context, "kinit", krb5_principal_get_realm(context, principal), opt); if (forwardable_flag != -1) krb5_get_init_creds_opt_set_forwardable(opt, forwardable_flag); if (proxiable_flag != -1) krb5_get_init_creds_opt_set_proxiable(opt, proxiable_flag); if (anonymous_flag) krb5_get_init_creds_opt_set_anonymous(opt, anonymous_flag); if (pac_flag != -1) krb5_get_init_creds_opt_set_pac_request(context, opt, pac_flag ? TRUE : FALSE); if (canonicalize_flag) krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag) krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); if (pk_user_id || ent_user_id || anonymous_flag) { ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, pk_x509_anchors, NULL, NULL, pk_use_enckey ? 2 : 0 | anonymous_flag ? 4 : 0, prompter, NULL, passwd); if (ret) { krb5_warn(context, ret, "krb5_get_init_creds_opt_set_pkinit"); goto out; } if (ent_user_id) krb5_get_init_creds_opt_set_pkinit_user_certs(context, opt, ent_user_id); } if (addrs_flag != -1) krb5_get_init_creds_opt_set_addressless(context, opt, addrs_flag ? FALSE : TRUE); if (renew_life == NULL && renewable_flag) renewstr = "1 month"; if (renew_life) renewstr = renew_life; if (renewstr) { renew = parse_time(renewstr, "s"); if (renew < 0) errx(1, "unparsable time: %s", renewstr); krb5_get_init_creds_opt_set_renew_life(opt, renew); } if (ticket_life != 0) krb5_get_init_creds_opt_set_tkt_life(opt, ticket_life); if (start_str) { int tmp = parse_time(start_str, "s"); if (tmp < 0) errx(1, N_("unparsable time: %s", ""), start_str); start_time = tmp; } if (etype_str.num_strings) { int i; enctype = malloc(etype_str.num_strings * sizeof(*enctype)); if (enctype == NULL) errx(1, "out of memory"); for(i = 0; i < etype_str.num_strings; i++) { ret = krb5_string_to_enctype(context, etype_str.strings[i], &enctype[i]); if (ret) errx(1, "unrecognized enctype: %s", etype_str.strings[i]); } krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); } ret = krb5_init_creds_init(context, principal, prompter, NULL, start_time, opt, &ctx); if (ret) { krb5_warn(context, ret, "krb5_init_creds_init"); goto out; } if (server_str) { ret = krb5_init_creds_set_service(context, ctx, server_str); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_service"); goto out; } } if (fast_armor_cache_string) { krb5_ccache fastid; ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); if (ret) { krb5_warn(context, ret, "krb5_cc_resolve(FAST cache)"); goto out; } ret = krb5_init_creds_set_fast_ccache(context, ctx, fastid); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_fast_ccache"); goto out; } } if (use_keytab || keytab_str) { ret = krb5_init_creds_set_keytab(context, ctx, kt); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_keytab"); goto out; } } else if (pk_user_id || ent_user_id || anonymous_flag) { } else if (!interactive && passwd[0] == '\0') { static int already_warned = 0; if (!already_warned) krb5_warnx(context, "Not interactive, failed to get " "initial ticket"); krb5_get_init_creds_opt_free(context, opt); already_warned = 1; return 0; } else { if (passwd[0] == '\0') { char *p, *prompt; int aret = 0; ret = krb5_unparse_name(context, principal, &p); if (ret) errx(1, "failed to generate passwd prompt: not enough memory"); aret = asprintf(&prompt, N_("%s's Password: "******""), p); free(p); if (aret == -1) errx(1, "failed to generate passwd prompt: not enough memory"); if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ memset(passwd, 0, sizeof(passwd)); errx(1, "failed to read password"); } free(prompt); } if (passwd[0]) { ret = krb5_init_creds_set_password(context, ctx, passwd); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_password"); goto out; } } } ret = krb5_init_creds_get(context, ctx); #ifndef NO_NTLM if (ntlm_domain && passwd[0]) heim_ntlm_nt_key(passwd, &ntlmkey); #endif memset(passwd, 0, sizeof(passwd)); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ exit(1); case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5_GET_IN_TKT_LOOP: krb5_warnx(context, N_("Password incorrect", "")); goto out; case KRB5KRB_AP_ERR_V4_REPLY: krb5_warnx(context, N_("Looks like a Kerberos 4 reply", "")); goto out; case KRB5KDC_ERR_KEY_EXPIRED: krb5_warnx(context, N_("Password expired", "")); goto out; default: krb5_warn(context, ret, "krb5_get_init_creds"); goto out; } krb5_process_last_request(context, opt, ctx); ret = krb5_init_creds_get_creds(context, ctx, &cred); if (ret) { krb5_warn(context, ret, "krb5_init_creds_get_creds"); goto out; } if (ticket_life != 0) { if (abs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) { char life[64]; unparse_time_approx(cred.times.endtime - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket lifetime is %s", ""), life); } } if (renew_life) { if (abs(cred.times.renew_till - cred.times.starttime - renew) > 30) { char life[64]; unparse_time_approx(cred.times.renew_till - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket renewable lifetime is %s", ""), life); } } krb5_free_cred_contents(context, &cred); ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), NULL, &tempccache); if (ret) { krb5_warn(context, ret, "krb5_cc_new_unique"); goto out; } ret = krb5_init_creds_store(context, ctx, tempccache); if (ret) { krb5_warn(context, ret, "krb5_init_creds_store"); goto out; } krb5_init_creds_free(context, ctx); ctx = NULL; ret = krb5_cc_move(context, tempccache, ccache); if (ret) { krb5_warn(context, ret, "krb5_cc_move"); goto out; } tempccache = NULL; if (switch_cache_flags) krb5_cc_switch(context, ccache); #ifndef NO_NTLM if (ntlm_domain && ntlmkey.data) store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey); #endif if (ok_as_delegate_flag || windows_flag || use_referrals_flag) { unsigned char d = 0; krb5_data data; if (ok_as_delegate_flag || windows_flag) d |= 1; if (use_referrals_flag || windows_flag) d |= 2; data.length = 1; data.data = &d; krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); } out: krb5_get_init_creds_opt_free(context, opt); if (ctx) krb5_init_creds_free(context, ctx); if (tempccache) krb5_cc_close(context, tempccache); if (enctype) free(enctype); return ret; }
static OM_uint32 acquire_initiator_cred (OM_uint32 * minor_status, krb5_context context, const gss_name_t desired_name, OM_uint32 time_req, gss_cred_usage_t cred_usage, gsskrb5_cred handle ) { OM_uint32 ret = GSS_S_FAILURE; krb5_creds cred; krb5_principal def_princ = NULL; krb5_get_init_creds_opt *opt; krb5_ccache ccache = NULL; krb5_error_code kret; memset(&cred, 0, sizeof(cred)); /* * If we have a preferred principal, lets try to find it in all * caches, otherwise, fall back to default cache, ignore all * errors while searching. */ if (handle->principal) { kret = krb5_cc_cache_match (context, handle->principal, &ccache); if (kret == 0) { goto found; } } if (ccache == NULL) { kret = krb5_cc_default(context, &ccache); if (kret) goto end; } kret = krb5_cc_get_principal(context, ccache, &def_princ); if (kret != 0) { /* we'll try to use a keytab below */ krb5_cc_close(context, ccache); def_princ = NULL; kret = 0; } else if (handle->principal == NULL) { kret = krb5_copy_principal(context, def_princ, &handle->principal); if (kret) goto end; } else if (handle->principal != NULL && krb5_principal_compare(context, handle->principal, def_princ) == FALSE) { krb5_free_principal(context, def_princ); def_princ = NULL; krb5_cc_close(context, ccache); ccache = NULL; } if (def_princ == NULL) { /* We have no existing credentials cache, * so attempt to get a TGT using a keytab. */ if (handle->principal == NULL) { kret = krb5_get_default_principal(context, &handle->principal); if (kret) goto end; } /* * Require user is in the keytab before trying to talk to * the KDC. */ kret = get_keytab(context, handle, 0); if (kret) goto end; /* since the name might have changed, let double check the credential cache */ kret = krb5_cc_cache_match(context, handle->principal, &ccache); if (kret == 0) goto found; kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, handle->keytab, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if (kret) goto end; kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) { krb5_cc_destroy(context, ccache); goto end; } kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) { krb5_cc_destroy(context, ccache); goto end; } handle->endtime = cred.times.endtime; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; } else { found: ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &handle->endtime); if (ret != GSS_S_COMPLETE) { krb5_cc_close(context, ccache); goto end; } kret = 0; } handle->ccache = ccache; ret = GSS_S_COMPLETE; end: if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (def_princ != NULL) krb5_free_principal(context, def_princ); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }