KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_etype (krb5_context context, unsigned *len, krb5_enctype **val, const krb5_enctype *etypes) { unsigned int i; krb5_error_code ret; krb5_enctype *tmp = NULL; ret = 0; if (etypes == NULL) { ret = krb5_get_default_in_tkt_etypes(context, &tmp); if (ret) return ret; etypes = tmp; } for (i = 0; etypes[i]; ++i) ; *len = i; *val = malloc(i * sizeof(**val)); if (i != 0 && *val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto cleanup; } memmove (*val, etypes, i * sizeof(*tmp)); cleanup: if (tmp != NULL) free (tmp); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL _krb5_init_etype(krb5_context context, krb5_pdu pdu_type, unsigned *len, krb5_enctype **val, const krb5_enctype *etypes) { krb5_error_code ret; if (etypes == NULL) ret = krb5_get_default_in_tkt_etypes(context, pdu_type, val); else ret = copy_enctypes(context, etypes, val); if (ret) return ret; if (len) { *len = 0; while ((*val)[*len] != KRB5_ENCTYPE_NULL) (*len)++; } return 0; }
static krb5_error_code change_pw_and_update_keytab(krb5_context context, kcm_ccache ccache) { char newpw[121]; krb5_error_code ret; unsigned kvno; krb5_salt salt; krb5_enctype *etypes = NULL; int i; char *cpn = NULL; char **spns = NULL; krb5_data_zero(&salt.saltvalue); ret = krb5_unparse_name(context, ccache->client, &cpn); if (ret) { kcm_log(0, "Failed to unparse name: %s", krb5_get_err_text(context, ret)); goto out; } ret = krb5_get_default_in_tkt_etypes(context, &etypes); if (ret) { kcm_log(0, "Failed to determine default encryption types: %s", krb5_get_err_text(context, ret)); goto out; } /* Generate a random password (there is no set keys protocol) */ generate_random_pw(context, newpw, sizeof(newpw)); /* Change it */ ret = change_pw(context, ccache, cpn, newpw); if (ret) goto out; /* Do an AS-REQ to determine salt and key version number */ ret = get_salt_and_kvno(context, ccache, etypes, cpn, newpw, &salt, &kvno); if (ret) { kcm_log(0, "Failed to determine salting principal for principal %s: %s", cpn, krb5_get_err_text(context, ret)); goto out; } /* Add canonical name */ ret = update_keytab_entries(context, ccache, etypes, cpn, NULL, newpw, salt, kvno); if (ret) goto out; /* Add SPN aliases, if any */ spns = krb5_config_get_strings(context, NULL, "kcm", "system_ccache", "spn_aliases", NULL); if (spns != NULL) { for (i = 0; spns[i] != NULL; i++) { ret = update_keytab_entries(context, ccache, etypes, cpn, spns[i], newpw, salt, kvno); if (ret) goto out; } } kcm_log(0, "Changed expired password for principal %s in cache %s", cpn, ccache->name); out: if (cpn != NULL) free(cpn); if (spns != NULL) krb5_config_free_strings(spns); if (etypes != NULL) free(etypes); krb5_free_salt(context, salt); memset(newpw, 0, sizeof(newpw)); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_get_permitted_enctypes(krb5_context context, krb5_enctype **etypes) { return krb5_get_default_in_tkt_etypes(context, KRB5_PDU_NONE, etypes); }
krb5_error_code get_kerberos_allowed_etypes(krb5_context context, krb5_enctype **enctypes) { return krb5_get_default_in_tkt_etypes(context, enctypes); }
_PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, struct tevent_context *event_ctx, struct loadparm_context *lp_ctx, struct gssapi_creds_container **_gcc, const char **error_string) { int ret = 0; OM_uint32 maj_stat, min_stat; struct gssapi_creds_container *gcc; struct ccache_container *ccache; gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; krb5_enctype *etypes = NULL; if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold && cred->client_gss_creds_obtained > CRED_UNINITIALISED) { bool expired = false; OM_uint32 lifetime = 0; gss_cred_usage_t usage = 0; maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds, NULL, &lifetime, &usage, NULL); if (maj_stat == GSS_S_CREDENTIALS_EXPIRED) { DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred, cred))); expired = true; } else if (maj_stat == GSS_S_COMPLETE && lifetime < 300) { DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred, cred), lifetime)); expired = true; } else if (maj_stat != GSS_S_COMPLETE) { *error_string = talloc_asprintf(cred, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n", gssapi_error_string(cred, maj_stat, min_stat, NULL)); return EINVAL; } if (expired) { cli_credentials_unconditionally_invalidate_client_gss_creds(cred); } else { DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n", cli_credentials_get_principal(cred, cred), (unsigned int)lifetime)); *_gcc = cred->client_gss_creds; return 0; } } ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, &ccache, error_string); if (ret) { if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) { DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string)); } else { DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string)); } return ret; } gcc = talloc(cred, struct gssapi_creds_container); if (!gcc) { (*error_string) = error_message(ENOMEM); return ENOMEM; } maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, &gcc->creds); if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) { /* This CCACHE is no good. Ensure we don't use it again */ cli_credentials_unconditionally_invalidate_ccache(cred); /* Now try again to get a ccache */ ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, &ccache, error_string); if (ret) { DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret))); return ret; } maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, &gcc->creds); } if (maj_stat) { talloc_free(gcc); if (min_stat) { ret = min_stat; } else { ret = EINVAL; } (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret)); return ret; } /* * transfer the enctypes from the smb_krb5_context to the gssapi layer * * We use 'our' smb_krb5_context to do the AS-REQ and it is possible * to configure the enctypes via the krb5.conf. * * And the gss_init_sec_context() creates it's own krb5_context and * the TGS-REQ had all enctypes in it and only the ones configured * and used for the AS-REQ, so it wasn't possible to disable the usage * of AES keys. */ min_stat = krb5_get_default_in_tkt_etypes(ccache->smb_krb5_context->krb5_context, KRB5_PDU_NONE, &etypes); if (min_stat == 0) { OM_uint32 num_ktypes; for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++); maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds, num_ktypes, (int32_t *) etypes); krb5_xfree (etypes); if (maj_stat) { talloc_free(gcc); if (min_stat) { ret = min_stat; } else { ret = EINVAL; } (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret)); return ret; } } /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */ maj_stat = gss_set_cred_option(&min_stat, &gcc->creds, GSS_KRB5_CRED_NO_CI_FLAGS_X, &empty_buffer); if (maj_stat) { talloc_free(gcc); if (min_stat) { ret = min_stat; } else { ret = EINVAL; } (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret)); return ret; } cred->client_gss_creds_obtained = cred->ccache_obtained; talloc_set_destructor(gcc, free_gssapi_creds); cred->client_gss_creds = gcc; *_gcc = gcc; return 0; }