#define MAX_TIME ((time_t)((1U << 31) - 1))
+#undef __attribute__
+#define __attribute__(X)
+
void
_kdc_fix_time(time_t **t)
{
return TRUE;
}
+
+krb5_boolean
+_kdc_is_anon_request(const KDC_REQ *req)
+{
+ const KDC_REQ_BODY *b = &req->req_body;
+
+ /*
+ * Versions of Heimdal from 0.9rc1 through 1.50 use bit 14 instead
+ * of 16 for request_anonymous, as indicated in the anonymous draft
+ * prior to version 11. Bit 14 is assigned to S4U2Proxy, but S4U2Proxy
+ * requests are only sent to the TGS and, in any case, would have an
+ * additional ticket present.
+ */
+ return b->kdc_options.request_anonymous ||
+ (b->kdc_options.cname_in_addl_tkt && !b->additional_tickets);
+}
+
/*
* return the first appropriate key of `princ' in `ret_key'. Look for
* all the etypes in (`etypes', `len'), stopping as soon as we find
*/
krb5_error_code
-_kdc_find_etype(krb5_context context, krb5_boolean use_strongest_session_key,
- krb5_boolean is_preauth, hdb_entry_ex *princ,
+_kdc_find_etype(astgs_request_t r, uint32_t flags,
krb5_enctype *etypes, unsigned len,
- krb5_enctype *ret_enctype, Key **ret_key)
+ krb5_enctype *ret_enctype, Key **ret_key,
+ krb5_boolean *ret_default_salt)
{
+ krb5_context context = r->context;
+ krb5_boolean use_strongest_session_key;
+ krb5_boolean is_preauth = flags & KFE_IS_PREAUTH;
+ krb5_boolean is_tgs = flags & KFE_IS_TGS;
+ hdb_entry_ex *princ;
+ krb5_principal request_princ;
krb5_error_code ret;
krb5_salt def_salt;
krb5_enctype enctype = (krb5_enctype)ETYPE_NULL;
Key *key = NULL;
int i, k;
+ if (flags & KFE_USE_CLIENT) {
+ princ = r->client;
+ request_princ = r->client_princ;
+ } else {
+ princ = r->server;
+ request_princ = r->server->entry.principal;
+ }
+
+ use_strongest_session_key =
+ is_preauth ? r->config->preauth_use_strongest_session_key
+ : (is_tgs ? r->config->tgt_use_strongest_session_key :
+ r->config->svc_use_strongest_session_key);
+
/* We'll want to avoid keys with v4 salted keys in the pre-auth case... */
- ret = krb5_get_pw_salt(context, princ->entry.principal, &def_salt);
+ ret = krb5_get_pw_salt(context, request_princ, &def_salt);
if (ret)
return ret;
*ret_enctype = enctype;
if (ret_key != NULL)
*ret_key = key;
+ if (ret_default_salt != NULL)
+ *ret_default_salt = is_default_salt_p(&def_salt, key);
}
krb5_free_salt (context, def_salt);
krb5_error_code
_kdc_make_anonymous_principalname (PrincipalName *pn)
{
- pn->name_type = KRB5_NT_PRINCIPAL;
- pn->name_string.len = 1;
- pn->name_string.val = malloc(sizeof(*pn->name_string.val));
+ pn->name_type = KRB5_NT_WELLKNOWN;
+ pn->name_string.len = 2;
+ pn->name_string.val = calloc(2, sizeof(*pn->name_string.val));
if (pn->name_string.val == NULL)
- return ENOMEM;
- pn->name_string.val[0] = strdup("anonymous");
- if (pn->name_string.val[0] == NULL) {
- free(pn->name_string.val);
- pn->name_string.val = NULL;
- return ENOMEM;
- }
+ goto failed;
+
+ pn->name_string.val[0] = strdup(KRB5_WELLKNOWN_NAME);
+ if (pn->name_string.val[0] == NULL)
+ goto failed;
+
+ pn->name_string.val[1] = strdup(KRB5_ANON_NAME);
+ if (pn->name_string.val[1] == NULL)
+ goto failed;
+
return 0;
+
+failed:
+ free_PrincipalName(pn);
+
+ pn->name_type = KRB5_NT_UNKNOWN;
+ pn->name_string.len = 0;
+ pn->name_string.val = NULL;
+
+ return ENOMEM;
}
static void
-_kdc_r_log(kdc_request_t r, int level, const char *fmt, ...)
+_kdc_r_log(astgs_request_t r, int level, const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)))
{
va_list ap;
char *s;
va_end(ap);
}
-static void
-_kdc_set_e_text(kdc_request_t r, const char *e_text)
+void
+_kdc_set_e_text(astgs_request_t r, char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 2, 3)))
{
+ va_list ap;
+ char *e_text;
+
+ va_start(ap, fmt);
+ vasprintf(&e_text, fmt, ap);
+ va_end(ap);
+
+ if (!e_text)
+ /* not much else to do... */
+ return;
+
+ /* We should never see this */
+ if (r->e_text) {
+ kdc_log(r->context, r->config, 1, "trying to replace e-text: %s\n",
+ e_text);
+ free(e_text);
+ return;
+ }
+
r->e_text = e_text;
- kdc_log(r->context, r->config, 0, "%s", e_text);
+ r->e_text_buf = e_text;
+ kdc_log(r->context, r->config, 4, "%s", e_text);
}
void
-_kdc_log_timestamp(krb5_context context,
- krb5_kdc_configuration *config,
- const char *type,
+_kdc_log_timestamp(astgs_request_t r, const char *type,
KerberosTime authtime, KerberosTime *starttime,
KerberosTime endtime, KerberosTime *renew_till)
{
+ krb5_context context = r->context;
+ krb5_kdc_configuration *config = r->config;
char authtime_str[100], starttime_str[100],
endtime_str[100], renewtime_str[100];
+ if (authtime)
+ _kdc_audit_addkv((kdc_request_t)r, 0, "auth", "%ld", (long)authtime);
+ if (starttime && *starttime)
+ _kdc_audit_addkv((kdc_request_t)r, 0, "start", "%ld",
+ (long)*starttime);
+ if (endtime)
+ _kdc_audit_addkv((kdc_request_t)r, 0, "end", "%ld", (long)endtime);
+ if (renew_till && *renew_till)
+ _kdc_audit_addkv((kdc_request_t)r, 0, "renew", "%ld",
+ (long)*renew_till);
+
krb5_format_time(context, authtime,
authtime_str, sizeof(authtime_str), TRUE);
if (starttime)
else
strlcpy(renewtime_str, "unset", sizeof(renewtime_str));
- kdc_log(context, config, 5,
+ kdc_log(context, config, 4,
"%s authtime: %s starttime: %s endtime: %s renew till: %s",
type, authtime_str, starttime_str, endtime_str, renewtime_str);
}
#ifdef PKINIT
static krb5_error_code
-pa_pkinit_validate(kdc_request_t r, const PA_DATA *pa)
+pa_pkinit_validate(astgs_request_t r, const PA_DATA *pa)
{
pk_client_params *pkp = NULL;
char *client_cert = NULL;
krb5_error_code ret;
- ret = _kdc_pk_rd_padata(r->context, r->config, &r->req, pa, r->client, &pkp);
+ ret = _kdc_pk_rd_padata(r, pa, &pkp);
if (ret || pkp == NULL) {
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- _kdc_r_log(r, 5, "Failed to decode PKINIT PA-DATA -- %s",
- r->client_name);
+ _kdc_r_log(r, 4, "Failed to decode PKINIT PA-DATA -- %s",
+ r->cname);
goto out;
}
- ret = _kdc_pk_check_client(r->context,
- r->config,
- r->clientdb,
- r->client,
- pkp,
- &client_cert);
+ ret = _kdc_pk_check_client(r, pkp, &client_cert);
if (ret) {
_kdc_set_e_text(r, "PKINIT certificate not allowed to "
"impersonate principal");
goto out;
}
- _kdc_r_log(r, 0, "PKINIT pre-authentication succeeded -- %s using %s",
- r->client_name, client_cert);
+ _kdc_r_log(r, 4, "PKINIT pre-authentication succeeded -- %s using %s",
+ r->cname, client_cert);
free(client_cert);
- ret = _kdc_pk_mk_pa_reply(r->context, r->config, pkp, r->client,
- r->sessionetype, &r->req, &r->request,
- &r->reply_key, &r->session_key, &r->outpadata);
+ ret = _kdc_pk_mk_pa_reply(r, pkp);
if (ret) {
_kdc_set_e_text(r, "Failed to build PK-INIT reply");
goto out;
}
+ r->reply_kvno = 0;
#if 0
- ret = _kdc_add_inital_verified_cas(r->context, r->config,
- pkp, &r->et);
+ ret = _kdc_add_initial_verified_cas(r->context, r->config,
+ pkp, &r->et);
#endif
out:
if (pkp)
*/
static krb5_error_code
-make_pa_enc_challange(krb5_context context, METHOD_DATA *md,
- krb5_crypto crypto)
+make_pa_enc_challange(astgs_request_t r, krb5_crypto crypto)
{
+ krb5_context context = r->context;
+ METHOD_DATA *md = &r->outpadata;
PA_ENC_TS_ENC p;
unsigned char *buf;
size_t buf_size;
}
static krb5_error_code
-pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa)
+pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa)
{
krb5_data pepper1, pepper2, ts_data;
- KDC_REQ_BODY *b = &r->req.req_body;
int invalidPassword = 0;
EncryptedData enc_data;
krb5_enctype aenctype;
heim_assert(r->armor_crypto != NULL, "ENC-CHAL called for non FAST");
- if (_kdc_is_anon_request(b)) {
+ if (_kdc_is_anon_request(&r->req)) {
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- kdc_log(r->context, r->config, 0, "ENC-CHALL doesn't support anon");
+ kdc_log(r->context, r->config, 4, "ENC-CHALL doesn't support anon");
return ret;
}
+ if (r->client->entry.flags.locked_out) {
+ ret = KRB5KDC_ERR_CLIENT_REVOKED;
+ kdc_log(r->context, r->config, 0,
+ "Client (%s) is locked out", r->client_name);
+ return ret;
+ }
+
+
ret = decode_EncryptedData(pa->padata_value.data,
pa->padata_value.length,
&enc_data,
&size);
if (ret) {
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- _kdc_r_log(r, 5, "Failed to decode PA-DATA -- %s",
- r->client_name);
+ _kdc_r_log(r, 4, "Failed to decode PA-DATA -- %s",
+ r->cname);
return ret;
}
ret2 = krb5_enctype_to_string(r->context, k->key.keytype, &str);
if (ret2)
str = NULL;
- _kdc_r_log(r, 5, "Failed to decrypt ENC-CHAL -- %s "
+ _kdc_r_log(r, 4, "Failed to decrypt ENC-CHAL -- %s "
"(enctype %s) error %s",
- r->client_name, str ? str : "unknown enctype", msg);
+ r->cname, str ? str : "unknown enctype", msg);
krb5_free_error_message(r->context, msg);
free(str);
if(ret){
krb5_crypto_destroy(r->context, challangecrypto);
ret = KRB5KDC_ERR_PREAUTH_FAILED;
- _kdc_r_log(r, 5, "Failed to decode PA-ENC-TS_ENC -- %s",
- r->client_name);
+ _kdc_r_log(r, 4, "Failed to decode PA-ENC-TS_ENC -- %s",
+ r->cname);
continue;
}
client_time, sizeof(client_time), TRUE);
ret = KRB5KRB_AP_ERR_SKEW;
- _kdc_r_log(r, 0, "Too large time skew, "
+ _kdc_r_log(r, 4, "Too large time skew, "
"client time %s is out by %u > %u seconds -- %s",
client_time,
(unsigned)labs(kdc_time - p.patimestamp),
r->context->max_skew,
- r->client_name);
+ r->cname);
free_PA_ENC_TS_ENC(&p);
goto out;
free_PA_ENC_TS_ENC(&p);
- ret = make_pa_enc_challange(r->context, &r->outpadata,
- challangecrypto);
+ ret = make_pa_enc_challange(r, challangecrypto);
krb5_crypto_destroy(r->context, challangecrypto);
if (ret)
goto out;
if (ret)
goto out;
+ r->reply_kvno = 0;
+
/*
* Success
*/
}
static krb5_error_code
-pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa)
+pa_enc_ts_validate(astgs_request_t r, const PA_DATA *pa)
{
EncryptedData enc_data;
krb5_error_code ret;
size_t len;
Key *pa_key;
char *str;
-
- if (_kdc_is_anon_request(&r->req.req_body)) {
- ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- _kdc_set_e_text(r, "ENC-TS doesn't support anon");
- goto out;
+
+ if (r->client->entry.flags.locked_out) {
+ ret = KRB5KDC_ERR_CLIENT_REVOKED;
+ kdc_log(r->context, r->config, 0,
+ "Client (%s) is locked out", r->client_name);
+ return ret;
}
ret = decode_EncryptedData(pa->padata_value.data,
&len);
if (ret) {
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- _kdc_r_log(r, 5, "Failed to decode PA-DATA -- %s",
- r->client_name);
+ _kdc_r_log(r, 4, "Failed to decode PA-DATA -- %s",
+ r->cname);
goto out;
}
if(krb5_enctype_to_string(r->context, enc_data.etype, &estr))
estr = NULL;
if(estr == NULL)
- _kdc_r_log(r, 5,
+ _kdc_r_log(r, 4,
"No client key matching pa-data (%d) -- %s",
- enc_data.etype, r->client_name);
+ enc_data.etype, r->cname);
else
- _kdc_r_log(r, 5,
+ _kdc_r_log(r, 4,
"No client key matching pa-data (%s) -- %s",
- estr, r->client_name);
+ estr, r->cname);
free(estr);
free_EncryptedData(&enc_data);
goto out;
ret = krb5_crypto_init(r->context, &pa_key->key, 0, &crypto);
if (ret) {
const char *msg = krb5_get_error_message(r->context, ret);
- _kdc_r_log(r, 0, "krb5_crypto_init failed: %s", msg);
+ _kdc_r_log(r, 4, "krb5_crypto_init failed: %s", msg);
krb5_free_error_message(r->context, msg);
free_EncryptedData(&enc_data);
goto out;
pa_key->key.keytype, &str);
if (ret2)
str = NULL;
- _kdc_r_log(r, 5, "Failed to decrypt PA-DATA -- %s "
+ _kdc_r_log(r, 4, "Failed to decrypt PA-DATA -- %s "
"(enctype %s) error %s",
- r->client_name, str ? str : "unknown enctype", msg);
+ r->cname, str ? str : "unknown enctype", msg);
krb5_free_error_message(r->context, msg);
free(str);
krb5_data_free(&ts_data);
if(ret){
ret = KRB5KDC_ERR_PREAUTH_FAILED;
- _kdc_r_log(r, 5, "Failed to decode PA-ENC-TS_ENC -- %s",
- r->client_name);
+ _kdc_r_log(r, 4, "Failed to decode PA-ENC-TS_ENC -- %s",
+ r->cname);
goto out;
}
if (labs(kdc_time - p.patimestamp) > r->context->max_skew) {
client_time, sizeof(client_time), TRUE);
ret = KRB5KRB_AP_ERR_SKEW;
- _kdc_r_log(r, 0, "Too large time skew, "
+ _kdc_r_log(r, 4, "Too large time skew, "
"client time %s is out by %u > %u seconds -- %s",
client_time,
(unsigned)labs(kdc_time - p.patimestamp),
r->context->max_skew,
- r->client_name);
+ r->cname);
/*
* The following is needed to make windows clients to
if (ret)
return ret;
+ if (pa_key->mkvno != NULL) {
+ r->reply_kvno = *pa_key->mkvno;
+ } else {
+ r->reply_kvno = r->client->entry.kvno;
+ }
+
ret = krb5_enctype_to_string(r->context, pa_key->key.keytype, &str);
if (ret)
str = NULL;
- _kdc_r_log(r, 2, "ENC-TS Pre-authentication succeeded -- %s using %s",
- r->client_name, str ? str : "unknown enctype");
+ _kdc_r_log(r, 4, "ENC-TS Pre-authentication succeeded -- %s using %s",
+ r->cname, str ? str : "unknown enctype");
+ _kdc_audit_addkv((kdc_request_t)r, 0, "pa-etype", "%d",
+ (int)pa_key->key.keytype);
free(str);
ret = 0;
unsigned int flags;
#define PA_ANNOUNCE 1
#define PA_REQ_FAST 2 /* only use inside fast */
- krb5_error_code (*validate)(kdc_request_t, const PA_DATA *pa);
+ krb5_error_code (*validate)(astgs_request_t, const PA_DATA *pa);
};
static const struct kdc_patypes pat[] = {
};
static void
-log_patypes(krb5_context context,
- krb5_kdc_configuration *config,
- METHOD_DATA *padata)
+log_patypes(astgs_request_t r, METHOD_DATA *padata)
{
+ krb5_context context = r->context;
+ krb5_kdc_configuration *config = r->config;
struct rk_strpool *p = NULL;
char *str;
size_t n, m;
if (p && n + 1 < padata->len)
p = rk_strpoolprintf(p, ", ");
if (p == NULL) {
- kdc_log(context, config, 0, "out of memory");
+ kdc_log(context, config, 1, "out of memory");
return;
}
}
p = rk_strpoolprintf(p, "none");
str = rk_strpoolcollect(p);
- kdc_log(context, config, 0, "Client sent patypes: %s", str);
+ kdc_log(context, config, 4, "Client sent patypes: %s", str);
+ _kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE,
+ "client-pa", "%s", str);
free(str);
}
ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, et, &len, ret);
if(ret) {
const char *msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 0, "Failed to encode ticket: %s", msg);
+ kdc_log(context, config, 4, "Failed to encode ticket: %s", msg);
krb5_free_error_message(context, msg);
return ret;
}
ret = krb5_crypto_init(context, skey, etype, &crypto);
if (ret) {
const char *msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
+ kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
krb5_free_error_message(context, msg);
+ free(buf);
return ret;
}
krb5_crypto_destroy(context, crypto);
if(ret) {
const char *msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 0, "Failed to encrypt data: %s", msg);
+ kdc_log(context, config, 4, "Failed to encrypt data: %s", msg);
krb5_free_error_message(context, msg);
return ret;
}
krb5_keyblock *strengthen_key = NULL;
KrbFastFinished finished;
- kdc_log(context, config, 0, "FAST armor protection");
+ kdc_log(context, config, 4, "FAST armor protection");
memset(&finished, 0, sizeof(finished));
krb5_data_zero(&data);
ASN1_MALLOC_ENCODE(EncTGSRepPart, buf, buf_size, ek, &len, ret);
if(ret) {
const char *msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 0, "Failed to encode KDC-REP: %s", msg);
+ kdc_log(context, config, 4, "Failed to encode KDC-REP: %s", msg);
krb5_free_error_message(context, msg);
return ret;
}
if(buf_size != len) {
free(buf);
- kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
+ kdc_log(context, config, 4, "Internal error in ASN.1 encoder");
*e_text = "KDC internal error";
return KRB5KRB_ERR_GENERIC;
}
if (ret) {
const char *msg = krb5_get_error_message(context, ret);
free(buf);
- kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
+ kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
krb5_free_error_message(context, msg);
return ret;
}
krb5_crypto_destroy(context, crypto);
if(ret) {
const char *msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 0, "Failed to encode KDC-REP: %s", msg);
+ kdc_log(context, config, 4, "Failed to encode KDC-REP: %s", msg);
krb5_free_error_message(context, msg);
return ret;
}
if(buf_size != len) {
free(buf);
- kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
+ kdc_log(context, config, 4, "Internal error in ASN.1 encoder");
*e_text = "KDC internal error";
return KRB5KRB_ERR_GENERIC;
}
*/
static krb5_error_code
-make_etype_info_entry(krb5_context context, ETYPE_INFO_ENTRY *ent, Key *key)
+make_etype_info_entry(krb5_context context,
+ ETYPE_INFO_ENTRY *ent,
+ Key *key,
+ krb5_boolean include_salt)
{
ent->etype = key->key.keytype;
- if(key->salt){
+ if (key->salt && include_salt){
#if 0
ALLOC(ent->salttype);
else if(key->salt->type == hdb_afs3_salt)
*ent->salttype = 2;
else {
- kdc_log(context, config, 0, "unknown salt-type: %d",
+ kdc_log(context, config, 4, "unknown salt-type: %d",
key->salt->type);
return KRB5KRB_ERR_GENERIC;
}
static krb5_error_code
get_pa_etype_info(krb5_context context,
krb5_kdc_configuration *config,
- METHOD_DATA *md, Key *ckey)
+ METHOD_DATA *md, Key *ckey,
+ krb5_boolean include_salt)
{
krb5_error_code ret = 0;
ETYPE_INFO pa;
if(pa.val == NULL)
return ENOMEM;
- ret = make_etype_info_entry(context, &pa.val[0], ckey);
+ ret = make_etype_info_entry(context, &pa.val[0], ckey, include_salt);
if (ret) {
free_ETYPE_INFO(&pa);
return ret;
*
*/
-extern int _krb5_AES_string_to_default_iterator;
+extern int _krb5_AES_SHA1_string_to_default_iterator;
+extern int _krb5_AES_SHA2_string_to_default_iterator;
static krb5_error_code
-make_etype_info2_entry(ETYPE_INFO2_ENTRY *ent, Key *key)
+make_s2kparams(int value, size_t len, krb5_data **ps2kparams)
{
+ krb5_data *s2kparams;
+ krb5_error_code ret;
+
+ ALLOC(s2kparams);
+ if (s2kparams == NULL)
+ return ENOMEM;
+ ret = krb5_data_alloc(s2kparams, len);
+ if (ret) {
+ free(s2kparams);
+ return ret;
+ }
+ _krb5_put_int(s2kparams->data, value, len);
+ *ps2kparams = s2kparams;
+ return 0;
+}
+
+static krb5_error_code
+make_etype_info2_entry(ETYPE_INFO2_ENTRY *ent,
+ Key *key,
+ krb5_boolean include_salt)
+{
+ krb5_error_code ret;
+
ent->etype = key->key.keytype;
- if(key->salt) {
+ if (key->salt && include_salt) {
ALLOC(ent->salt);
if (ent->salt == NULL)
return ENOMEM;
switch (key->key.keytype) {
case ETYPE_AES128_CTS_HMAC_SHA1_96:
case ETYPE_AES256_CTS_HMAC_SHA1_96:
- ALLOC(ent->s2kparams);
- if (ent->s2kparams == NULL)
- return ENOMEM;
- ent->s2kparams->length = 4;
- ent->s2kparams->data = malloc(ent->s2kparams->length);
- if (ent->s2kparams->data == NULL) {
- free(ent->s2kparams);
- ent->s2kparams = NULL;
- return ENOMEM;
- }
- _krb5_put_int(ent->s2kparams->data,
- _krb5_AES_string_to_default_iterator,
- ent->s2kparams->length);
+ ret = make_s2kparams(_krb5_AES_SHA1_string_to_default_iterator,
+ 4, &ent->s2kparams);
+ break;
+ case KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128:
+ case KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192:
+ ret = make_s2kparams(_krb5_AES_SHA2_string_to_default_iterator,
+ 4, &ent->s2kparams);
break;
case ETYPE_DES_CBC_CRC:
case ETYPE_DES_CBC_MD4:
case ETYPE_DES_CBC_MD5:
/* Check if this was a AFS3 salted key */
- if(key->salt && key->salt->type == hdb_afs3_salt){
- ALLOC(ent->s2kparams);
- if (ent->s2kparams == NULL)
- return ENOMEM;
- ent->s2kparams->length = 1;
- ent->s2kparams->data = malloc(ent->s2kparams->length);
- if (ent->s2kparams->data == NULL) {
- free(ent->s2kparams);
- ent->s2kparams = NULL;
- return ENOMEM;
- }
- _krb5_put_int(ent->s2kparams->data,
- 1,
- ent->s2kparams->length);
- }
+ if(key->salt && key->salt->type == hdb_afs3_salt)
+ ret = make_s2kparams(1, 1, &ent->s2kparams);
+ else
+ ret = 0;
break;
default:
+ ret = 0;
break;
}
- return 0;
+ return ret;
}
/*
static krb5_error_code
get_pa_etype_info2(krb5_context context,
krb5_kdc_configuration *config,
- METHOD_DATA *md, Key *ckey)
+ METHOD_DATA *md, Key *ckey,
+ krb5_boolean include_salt)
{
krb5_error_code ret = 0;
ETYPE_INFO2 pa;
if(pa.val == NULL)
return ENOMEM;
- ret = make_etype_info2_entry(&pa.val[0], ckey);
+ ret = make_etype_info2_entry(&pa.val[0], ckey, include_salt);
if (ret) {
free_ETYPE_INFO2(&pa);
return ret;
return 0;
}
+static int
+newer_enctype_present(struct KDC_REQ_BODY_etype *etype_list)
+{
+ size_t i;
+
+ for (i = 0; i < etype_list->len; i++) {
+ if (!older_enctype(etype_list->val[i]))
+ return 1;
+ }
+ return 0;
+}
+
+static krb5_error_code
+get_pa_etype_info_both(krb5_context context,
+ krb5_kdc_configuration *config,
+ struct KDC_REQ_BODY_etype *etype_list,
+ METHOD_DATA *md, Key *ckey,
+ krb5_boolean include_salt)
+{
+ krb5_error_code ret;
+
+ /*
+ * RFC4120 requires:
+ * When the AS server is to include pre-authentication data in a
+ * KRB-ERROR or in an AS-REP, it MUST use PA-ETYPE-INFO2, not
+ * PA-ETYPE-INFO, if the etype field of the client's AS-REQ lists
+ * at least one "newer" encryption type. Otherwise (when the etype
+ * field of the client's AS-REQ does not list any "newer" encryption
+ * types), it MUST send both PA-ETYPE-INFO2 and PA-ETYPE-INFO (both
+ * with an entry for each enctype). A "newer" enctype is any enctype
+ * first officially specified concurrently with or subsequent to the
+ * issue of this RFC. The enctypes DES, 3DES, or RC4 and any defined
+ * in [RFC1510] are not "newer" enctypes.
+ *
+ * It goes on to state:
+ * The preferred ordering of the "hint" pre-authentication data that
+ * affect client key selection is: ETYPE-INFO2, followed by ETYPE-INFO,
+ * followed by PW-SALT. As noted in Section 3.1.3, a KDC MUST NOT send
+ * ETYPE-INFO or PW-SALT when the client's AS-REQ includes at least one
+ * "newer" etype.
+ */
+
+ ret = get_pa_etype_info2(context, config, md, ckey, include_salt);
+ if (ret)
+ return ret;
+
+ if (!newer_enctype_present(etype_list))
+ ret = get_pa_etype_info(context, config, md, ckey, include_salt);
+
+ return ret;
+}
+
/*
*
*/
-static void
-log_as_req(krb5_context context,
- krb5_kdc_configuration *config,
- krb5_enctype cetype,
- krb5_enctype setype,
- const KDC_REQ_BODY *b)
+void
+_log_astgs_req(astgs_request_t r, krb5_enctype setype)
{
+ krb5_context context = r->context;
+ const KDC_REQ_BODY *b = &r->req.req_body;
+ krb5_enctype cetype = r->reply_key.keytype;
krb5_error_code ret;
struct rk_strpool *p;
+ struct rk_strpool *s = NULL;
char *str;
+ char *cet;
+ char *set;
size_t i;
+ /*
+ * we are collecting ``p'' and ``s''. The former is a textual
+ * representation of the enctypes as strings which will be used
+ * for debugging. The latter is a terse comma separated list of
+ * the %d's of the enctypes to emit into our audit trail to
+ * conserve space in the logs.
+ */
+
p = rk_strpoolprintf(NULL, "%s", "Client supported enctypes: ");
for (i = 0; i < b->etype.len; i++) {
free(str);
} else
p = rk_strpoolprintf(p, "%d", b->etype.val[i]);
- if (p && i + 1 < b->etype.len)
- p = rk_strpoolprintf(p, ", ");
if (p == NULL) {
- kdc_log(context, config, 0, "out of memory");
+ rk_strpoolfree(s);
+ _kdc_r_log(r, 4, "out of memory");
return;
}
+ s = rk_strpoolprintf(s, "%d", b->etype.val[i]);
+ if (i + 1 < b->etype.len) {
+ p = rk_strpoolprintf(p, ", ");
+ s = rk_strpoolprintf(s, ",");
+ }
}
if (p == NULL)
p = rk_strpoolprintf(p, "no encryption types");
- {
- char *cet;
- char *set;
-
- ret = krb5_enctype_to_string(context, cetype, &cet);
- if(ret == 0) {
- ret = krb5_enctype_to_string(context, setype, &set);
- if (ret == 0) {
- p = rk_strpoolprintf(p, ", using %s/%s", cet, set);
- free(set);
- }
- free(cet);
+ str = rk_strpoolcollect(s);
+ if (str)
+ _kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, "etypes", "%s",
+ str);
+ free(str);
+
+ ret = krb5_enctype_to_string(context, cetype, &cet);
+ if(ret == 0) {
+ ret = krb5_enctype_to_string(context, setype, &set);
+ if (ret == 0) {
+ p = rk_strpoolprintf(p, ", using %s/%s", cet, set);
+ free(set);
}
- if (ret != 0)
- p = rk_strpoolprintf(p, ", using enctypes %d/%d",
- cetype, setype);
+ free(cet);
}
+ if (ret != 0)
+ p = rk_strpoolprintf(p, ", using enctypes %d/%d",
+ cetype, setype);
str = rk_strpoolcollect(p);
- kdc_log(context, config, 0, "%s", str);
+ if (str)
+ _kdc_r_log(r, 4, "%s", str);
free(str);
+ _kdc_audit_addkv((kdc_request_t)r, 0, "etype", "%d/%d", cetype, setype);
+
{
char fixedstr[128];
+
unparse_flags(KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(),
fixedstr, sizeof(fixedstr));
- if(*fixedstr)
- kdc_log(context, config, 0, "Requested flags: %s", fixedstr);
+ if (*fixedstr) {
+ _kdc_r_log(r, 4, "Requested flags: %s", fixedstr);
+ _kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE,
+ "flags", "%s", fixedstr);
+ }
}
}
*/
krb5_error_code
-kdc_check_flags(krb5_context context,
- krb5_kdc_configuration *config,
- hdb_entry_ex *client_ex, const char *client_name,
- hdb_entry_ex *server_ex, const char *server_name,
- krb5_boolean is_as_req)
+kdc_check_flags(astgs_request_t r, krb5_boolean is_as_req)
{
+ krb5_context context = r->context;
+ hdb_entry_ex *client_ex = r->client;
+ hdb_entry_ex *server_ex = r->server;
+
if(client_ex != NULL) {
hdb_entry *client = &client_ex->entry;
/* check client */
if (client->flags.locked_out) {
- kdc_log(context, config, 0,
- "Client (%s) is locked out", client_name);
- return KRB5KDC_ERR_POLICY;
+ _kdc_audit_addreason((kdc_request_t)r, "Client is locked out");
+ return KRB5KDC_ERR_CLIENT_REVOKED;
}
if (client->flags.invalid) {
- kdc_log(context, config, 0,
- "Client (%s) has invalid bit set", client_name);
+ _kdc_audit_addreason((kdc_request_t)r,
+ "Client has invalid bit set");
return KRB5KDC_ERR_POLICY;
}
- if(!client->flags.client){
- kdc_log(context, config, 0,
- "Principal may not act as client -- %s", client_name);
+ if (!client->flags.client) {
+ _kdc_audit_addreason((kdc_request_t)r,
+ "Principal may not act as client");
return KRB5KDC_ERR_POLICY;
}
char starttime_str[100];
krb5_format_time(context, *client->valid_start,
starttime_str, sizeof(starttime_str), TRUE);
- kdc_log(context, config, 0,
- "Client not yet valid until %s -- %s",
- starttime_str, client_name);
+ _kdc_audit_addreason((kdc_request_t)r, "Client not yet valid "
+ "until %s", starttime_str);
return KRB5KDC_ERR_CLIENT_NOTYET;
}
char endtime_str[100];
krb5_format_time(context, *client->valid_end,
endtime_str, sizeof(endtime_str), TRUE);
- kdc_log(context, config, 0,
- "Client expired at %s -- %s",
- endtime_str, client_name);
- return KRB5KDC_ERR_NAME_EXP;
+ _kdc_audit_addreason((kdc_request_t)r, "Client expired at %s",
+ endtime_str);
+ return KRB5KDC_ERR_NAME_EXP;
}
if (client->flags.require_pwchange &&
- (server_ex == NULL || !server_ex->entry.flags.change_pw)) {
- kdc_log(context, config, 0,
- "Client's key must be changed -- %s", client_name);
+ (server_ex == NULL || !server_ex->entry.flags.change_pw))
return KRB5KDC_ERR_KEY_EXPIRED;
- }
if (client->pw_end && *client->pw_end < kdc_time
&& (server_ex == NULL || !server_ex->entry.flags.change_pw)) {
char pwend_str[100];
krb5_format_time(context, *client->pw_end,
pwend_str, sizeof(pwend_str), TRUE);
- kdc_log(context, config, 0,
- "Client's key has expired at %s -- %s",
- pwend_str, client_name);
+ _kdc_audit_addreason((kdc_request_t)r, "Client's key has expired "
+ "at %s", pwend_str);
return KRB5KDC_ERR_KEY_EXPIRED;
}
}
hdb_entry *server = &server_ex->entry;
if (server->flags.locked_out) {
- kdc_log(context, config, 0,
- "Client server locked out -- %s", server_name);
+ _kdc_audit_addreason((kdc_request_t)r, "Server locked out");
return KRB5KDC_ERR_POLICY;
}
if (server->flags.invalid) {
- kdc_log(context, config, 0,
- "Server has invalid flag set -- %s", server_name);
+ _kdc_audit_addreason((kdc_request_t)r,
+ "Server has invalid flag set");
return KRB5KDC_ERR_POLICY;
}
-
- if(!server->flags.server){
- kdc_log(context, config, 0,
- "Principal may not act as server -- %s", server_name);
+ if (!server->flags.server) {
+ _kdc_audit_addreason((kdc_request_t)r,
+ "Principal may not act as server");
return KRB5KDC_ERR_POLICY;
}
- if(!is_as_req && server->flags.initial) {
- kdc_log(context, config, 0,
- "AS-REQ is required for server -- %s", server_name);
+ if (!is_as_req && server->flags.initial) {
+ _kdc_audit_addreason((kdc_request_t)r,
+ "AS-REQ is required for server");
return KRB5KDC_ERR_POLICY;
}
char starttime_str[100];
krb5_format_time(context, *server->valid_start,
starttime_str, sizeof(starttime_str), TRUE);
- kdc_log(context, config, 0,
- "Server not yet valid until %s -- %s",
- starttime_str, server_name);
+ _kdc_audit_addreason((kdc_request_t)r, "Server not yet valid "
+ "until %s", starttime_str);
return KRB5KDC_ERR_SERVICE_NOTYET;
}
char endtime_str[100];
krb5_format_time(context, *server->valid_end,
endtime_str, sizeof(endtime_str), TRUE);
- kdc_log(context, config, 0,
- "Server expired at %s -- %s",
- endtime_str, server_name);
+ _kdc_audit_addreason((kdc_request_t)r, "Server expired at %s",
+ endtime_str);
return KRB5KDC_ERR_SERVICE_EXP;
}
char pwend_str[100];
krb5_format_time(context, *server->pw_end,
pwend_str, sizeof(pwend_str), TRUE);
- kdc_log(context, config, 0,
- "Server's key has expired at -- %s",
- pwend_str, server_name);
+ _kdc_audit_addreason((kdc_request_t)r, "Server's key has expired "
+ "at %s", pwend_str);
return KRB5KDC_ERR_KEY_EXPIRED;
}
}
*/
krb5_boolean
-_kdc_check_addresses(krb5_context context,
- krb5_kdc_configuration *config,
- HostAddresses *addresses, const struct sockaddr *from)
+_kdc_check_addresses(astgs_request_t r, HostAddresses *addresses,
+ const struct sockaddr *from)
{
+ krb5_context context = r->context;
+ krb5_kdc_configuration *config = r->config;
krb5_error_code ret;
krb5_address addr;
krb5_boolean result;
return result;
}
+/*
+ *
+ */
+krb5_error_code
+_kdc_check_anon_policy(astgs_request_t r)
+{
+ if (!r->config->allow_anonymous) {
+ _kdc_audit_addreason((kdc_request_t)r,
+ "Anonymous tickets denied by local policy");
+ return KRB5KDC_ERR_POLICY;
+ }
+
+ return 0;
+}
+
/*
*
*/
*/
static krb5_error_code
-generate_pac(kdc_request_t r, Key *skey)
+generate_pac(astgs_request_t r, Key *skey)
{
krb5_error_code ret;
+ const krb5_keyblock *pk_reply_key = NULL;
krb5_pac p = NULL;
krb5_data data;
- ret = _kdc_pac_generate(r->context, r->client, &p);
+ switch (r->validated_pa_type) {
+ case KRB5_PADATA_PK_AS_REQ:
+ case KRB5_PADATA_PK_AS_REQ_WIN:
+ pk_reply_key = &r->reply_key;
+ break;
+ }
+
+ ret = _kdc_pac_generate(r->context, r->client,
+ pk_reply_key, &p);
if (ret) {
- _kdc_r_log(r, 0, "PAC generation failed for -- %s",
- r->client_name);
+ _kdc_r_log(r, 4, "PAC generation failed for -- %s",
+ r->cname);
return ret;
}
if (p == NULL)
&data);
krb5_pac_free(r->context, p);
if (ret) {
- _kdc_r_log(r, 0, "PAC signing failed for -- %s",
- r->client_name);
+ _kdc_r_log(r, 4, "PAC signing failed for -- %s",
+ r->cname);
return ret;
}
*/
krb5_boolean
-_kdc_is_anonymous(krb5_context context, krb5_principal principal)
+_kdc_is_anonymous(krb5_context context, krb5_const_principal principal)
{
- if (principal->name.name_type != KRB5_NT_WELLKNOWN ||
- principal->name.name_string.len != 2 ||
- strcmp(principal->name.name_string.val[0], KRB5_WELLKNOWN_NAME) != 0 ||
- strcmp(principal->name.name_string.val[1], KRB5_ANON_NAME) != 0)
- return 0;
- return 1;
+ return krb5_principal_is_anonymous(context, principal, KRB5_ANON_MATCH_ANY);
}
static int
-require_preauth_p(kdc_request_t r)
+require_preauth_p(astgs_request_t r)
{
return r->config->require_preauth
|| r->client->entry.flags.require_preauth
*/
static krb5_error_code
-add_enc_pa_rep(kdc_request_t r)
+add_enc_pa_rep(astgs_request_t r)
{
krb5_error_code ret;
krb5_crypto crypto;
*/
krb5_error_code
-_kdc_as_rep(kdc_request_t r,
- krb5_data *reply,
- const char *from,
- struct sockaddr *from_addr,
- int datagram_reply)
+_kdc_as_rep(astgs_request_t r)
{
krb5_context context = r->context;
krb5_kdc_configuration *config = r->config;
KDC_REQ *req = &r->req;
+ const char *from = r->from;
KDC_REQ_BODY *b = NULL;
AS_REP rep;
KDCOptions f;
int i, flags = HDB_F_FOR_AS_REQ;
METHOD_DATA error_method;
const PA_DATA *pa;
+ krb5_boolean is_tgs;
+ const char *msg;
memset(&rep, 0, sizeof(rep));
error_method.len = 0;
*/
ret = _kdc_fast_unwrap_request(r);
if (ret) {
- _kdc_r_log(r, 0, "FAST unwrap request from %s failed: %d", from, ret);
+ _kdc_r_log(r, 1, "FAST unwrap request from %s failed: %d", from, ret);
goto out;
}
if (f.canonicalize)
flags |= HDB_F_CANON;
- if(b->sname == NULL){
+ if (b->sname == NULL) {
ret = KRB5KRB_ERR_GENERIC;
_kdc_set_e_text(r, "No server in request");
- } else{
- ret = _krb5_principalname2krb5_principal (context,
- &r->server_princ,
- *(b->sname),
- b->realm);
- if (ret == 0)
- ret = krb5_unparse_name(context, r->server_princ, &r->server_name);
+ goto out;
}
+
+ ret = _krb5_principalname2krb5_principal(context, &r->server_princ,
+ *(b->sname), b->realm);
+ if (!ret)
+ ret = krb5_unparse_name(context, r->server_princ, &r->sname);
if (ret) {
- kdc_log(context, config, 0,
- "AS-REQ malformed server name from %s", from);
+ kdc_log(context, config, 2,
+ "AS_REQ malformed server name from %s", from);
goto out;
}
- if(b->cname == NULL){
+
+ if (b->cname == NULL) {
ret = KRB5KRB_ERR_GENERIC;
_kdc_set_e_text(r, "No client in request");
- } else {
- ret = _krb5_principalname2krb5_principal (context,
- &r->client_princ,
- *(b->cname),
- b->realm);
- if (ret)
- goto out;
-
- ret = krb5_unparse_name(context, r->client_princ, &r->client_name);
+ goto out;
}
+
+ ret = _krb5_principalname2krb5_principal(context, &r->client_princ,
+ *(b->cname), b->realm);
+ if (!ret)
+ ret = krb5_unparse_name(context, r->client_princ, &r->cname);
if (ret) {
- kdc_log(context, config, 0,
+ kdc_log(context, config, 2,
"AS-REQ malformed client name from %s", from);
goto out;
}
- kdc_log(context, config, 0, "AS-REQ %s from %s for %s",
- r->client_name, from, r->server_name);
+ kdc_log(context, config, 4, "AS-REQ %s from %s for %s",
+ r->cname, r->from, r->sname);
- /*
- *
- */
+ is_tgs = krb5_principal_is_krbtgt(context, r->server_princ);
- if (_kdc_is_anonymous(context, r->client_princ)) {
- if (!_kdc_is_anon_request(b)) {
- kdc_log(context, config, 0, "Anonymous ticket w/o anonymous flag");
- ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
- goto out;
- }
- } else if (_kdc_is_anon_request(b)) {
- kdc_log(context, config, 0,
- "Request for a anonymous ticket with non "
- "anonymous client name: %s", r->client_name);
- ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ if (_kdc_is_anonymous(context, r->client_princ) &&
+ !_kdc_is_anon_request(req)) {
+ kdc_log(context, config, 2, "Anonymous client w/o anonymous flag");
+ ret = KRB5KDC_ERR_BADOPTION;
goto out;
}
- /*
- *
- */
-
ret = _kdc_db_fetch(context, config, r->client_princ,
HDB_F_GET_CLIENT | flags, NULL,
&r->clientdb, &r->client);
- if(ret == HDB_ERR_NOT_FOUND_HERE) {
+ switch (ret) {
+ case 0: /* Success */
+ break;
+ case HDB_ERR_NOT_FOUND_HERE:
kdc_log(context, config, 5, "client %s does not have secrets at this KDC, need to proxy",
- r->client_name);
+ r->cname);
goto out;
- } else if (ret == HDB_ERR_WRONG_REALM) {
+ case HDB_ERR_WRONG_REALM: {
char *fixed_client_name = NULL;
ret = krb5_unparse_name(context, r->client->entry.principal,
goto out;
}
- kdc_log(context, config, 0, "WRONG_REALM - %s -> %s",
- r->client_name, fixed_client_name);
+ kdc_log(context, config, 4, "WRONG_REALM - %s -> %s",
+ r->cname, fixed_client_name);
free(fixed_client_name);
- ret = _kdc_fast_mk_error(context, r,
- &error_method,
- r->armor_crypto,
- &req->req_body,
- KRB5_KDC_ERR_WRONG_REALM,
- NULL,
- r->server_princ,
- NULL,
+ ret = _kdc_fast_mk_error(r, &error_method, r->armor_crypto,
+ &req->req_body, KRB5_KDC_ERR_WRONG_REALM,
+ NULL, r->server_princ, NULL,
&r->client->entry.principal->realm,
- NULL, NULL,
- reply);
+ NULL, NULL, r->reply);
goto out;
- } else if(ret){
- const char *msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 0, "UNKNOWN -- %s: %s", r->client_name, msg);
+ }
+ default:
+ msg = krb5_get_error_message(context, ret);
+ kdc_log(context, config, 4, "UNKNOWN -- %s: %s", r->cname, msg);
krb5_free_error_message(context, msg);
ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
goto out;
}
ret = _kdc_db_fetch(context, config, r->server_princ,
- HDB_F_GET_SERVER|HDB_F_GET_KRBTGT | flags,
+ HDB_F_GET_SERVER | flags | (is_tgs ? HDB_F_GET_KRBTGT : 0),
NULL, NULL, &r->server);
- if(ret == HDB_ERR_NOT_FOUND_HERE) {
+ switch (ret) {
+ case 0: /* Success */
+ break;
+ case HDB_ERR_NOT_FOUND_HERE:
kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy",
- r->server_name);
+ r->sname);
goto out;
- } else if(ret){
- const char *msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 0, "UNKNOWN -- %s: %s", r->server_name, msg);
+ default:
+ msg = krb5_get_error_message(context, ret);
+ kdc_log(context, config, 4, "UNKNOWN -- %s: %s", r->sname, msg);
krb5_free_error_message(context, msg);
ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
goto out;
* decrypt.
*/
- ret = _kdc_find_etype(context,
- krb5_principal_is_krbtgt(context, r->server_princ) ?
- config->tgt_use_strongest_session_key :
- config->svc_use_strongest_session_key, FALSE,
- r->client, b->etype.val, b->etype.len, &r->sessionetype,
- NULL);
+ ret = _kdc_find_etype(r, (is_tgs ? KFE_IS_TGS:0) | KFE_USE_CLIENT,
+ b->etype.val, b->etype.len,
+ &r->sessionetype, NULL, NULL);
if (ret) {
- kdc_log(context, config, 0,
+ kdc_log(context, config, 4,
"Client (%s) from %s has no common enctypes with KDC "
"to use for the session key",
- r->client_name, from);
+ r->cname, from);
goto out;
}
if(req->padata){
unsigned int n;
- log_patypes(context, config, req->padata);
+ log_patypes(r, req->padata);
/* Check if preauth matching */
continue;
kdc_log(context, config, 5,
- "Looking for %s pa-data -- %s", pat[n].name, r->client_name);
+ "Looking for %s pa-data -- %s", pat[n].name, r->cname);
i = 0;
pa = _kdc_find_padata(req, &i, pat[n].type);
if (pa) {
+ _kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_VIS, "pa", "%s",
+ pat[n].name);
ret = pat[n].validate(r, pa);
if (ret != 0) {
+ krb5_error_code ret2;
+ Key *ckey = NULL;
+ krb5_boolean default_salt;
+
+ /*
+ * If there is a client key, send ETYPE_INFO{,2}
+ */
+ ret2 = _kdc_find_etype(r, KFE_IS_PREAUTH|KFE_USE_CLIENT,
+ b->etype.val, b->etype.len,
+ NULL, &ckey, &default_salt);
+ if (ret2 == 0) {
+ ret2 = get_pa_etype_info_both(context, config, &b->etype,
+ &error_method, ckey, !default_salt);
+ if (ret2 != 0)
+ ret = ret2;
+ }
goto out;
}
- kdc_log(context, config, 0,
+ kdc_log(context, config, 4,
"%s pre-authentication succeeded -- %s",
- pat[n].name, r->client_name);
+ pat[n].name, r->cname);
found_pa = 1;
r->et.flags.pre_authent = 1;
+ r->validated_pa_type = pat[n].type;
}
}
}
if (found_pa == 0) {
Key *ckey = NULL;
size_t n;
+ krb5_boolean default_salt;
for (n = 0; n < sizeof(pat) / sizeof(pat[0]); n++) {
if ((pat[n].flags & PA_ANNOUNCE) == 0)
/*
* If there is a client key, send ETYPE_INFO{,2}
*/
- ret = _kdc_find_etype(context,
- config->preauth_use_strongest_session_key, TRUE,
- r->client, b->etype.val, b->etype.len, NULL, &ckey);
+ ret = _kdc_find_etype(r, KFE_IS_PREAUTH|KFE_USE_CLIENT,
+ b->etype.val, b->etype.len,
+ NULL, &ckey, &default_salt);
if (ret == 0) {
-
- /*
- * RFC4120 requires:
- * - If the client only knows about old enctypes, then send
- * both info replies (we send 'info' first in the list).
- * - If the client is 'modern', because it knows about 'new'
- * enctype types, then only send the 'info2' reply.
- *
- * Before we send the full list of etype-info data, we pick
- * the client key we would have used anyway below, just pick
- * that instead.
- */
-
- if (older_enctype(ckey->key.keytype)) {
- ret = get_pa_etype_info(context, config,
- &error_method, ckey);
- if (ret)
- goto out;
- }
- ret = get_pa_etype_info2(context, config,
- &error_method, ckey);
+ ret = get_pa_etype_info_both(context, config, &b->etype,
+ &error_method, ckey, !default_salt);
if (ret)
goto out;
}
* send requre preauth is its required or anon is requested,
* anon is today only allowed via preauth mechanisms.
*/
- if (require_preauth_p(r) || _kdc_is_anon_request(b)) {
+ if (require_preauth_p(r) || _kdc_is_anon_request(&r->req)) {
ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
_kdc_set_e_text(r, "Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ");
goto out;
ret = krb5_copy_keyblock_contents(r->context, &ckey->key, &r->reply_key);
if (ret)
goto out;
+
+ r->reply_kvno = 0;
}
if (r->clientdb->hdb_auth_status) {
- r->clientdb->hdb_auth_status(context, r->clientdb, r->client,
+ r->clientdb->hdb_auth_status(context, r->clientdb, r->client,
HDB_AUTH_SUCCESS);
}
* with in a preauth mech.
*/
- ret = _kdc_check_access(context, config, r->client, r->client_name,
- r->server, r->server_name,
- req, &error_method);
+ ret = _kdc_check_access(r, req, &error_method);
if(ret)
goto out;
+ if (_kdc_is_anon_request(&r->req)) {
+ ret = _kdc_check_anon_policy(r);
+ if (ret) {
+ _kdc_set_e_text(r, "Anonymous ticket requests are disabled");
+ goto out;
+ }
+
+ r->et.flags.anonymous = 1;
+ }
+
/*
* Select the best encryption type for the KDC with out regard to
* the client since the client never needs to read that data.
*/
ret = _kdc_get_preferred_key(context, config,
- r->server, r->server_name,
+ r->server, r->sname,
&setype, &skey);
if(ret)
goto out;
- if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
- || (_kdc_is_anon_request(b) && !config->allow_anonymous)) {
+ if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey) {
ret = KRB5KDC_ERR_BADOPTION;
_kdc_set_e_text(r, "Bad KDC options");
goto out;
rep.pvno = 5;
rep.msg_type = krb_as_rep;
- if (_kdc_is_anonymous(context, r->client_princ)) {
- Realm anon_realm=KRB5_ANON_REALM;
+ if (!config->historical_anon_realm &&
+ _kdc_is_anonymous(context, r->client_princ)) {
+ Realm anon_realm = KRB5_ANON_REALM;
ret = copy_Realm(&anon_realm, &rep.crealm);
- } else
+ } else if (f.canonicalize || r->client->entry.flags.force_canonicalize)
ret = copy_Realm(&r->client->entry.principal->realm, &rep.crealm);
+ else
+ ret = copy_Realm(&r->client_princ->realm, &rep.crealm);
if (ret)
goto out;
- ret = _krb5_principal2principalname(&rep.cname, r->client->entry.principal);
+ if (r->et.flags.anonymous)
+ ret = _kdc_make_anonymous_principalname(&rep.cname);
+ else if (f.canonicalize || r->client->entry.flags.force_canonicalize)
+ ret = _krb5_principal2principalname(&rep.cname, r->client->entry.principal);
+ else
+ ret = _krb5_principal2principalname(&rep.cname, r->client_princ);
if (ret)
goto out;
rep.ticket.tkt_vno = 5;
- copy_Realm(&r->server->entry.principal->realm, &rep.ticket.realm);
- _krb5_principal2principalname(&rep.ticket.sname,
- r->server->entry.principal);
+ if (f.canonicalize || r->server->entry.flags.force_canonicalize)
+ ret = copy_Realm(&r->server->entry.principal->realm, &rep.ticket.realm);
+ else
+ ret = copy_Realm(&r->server_princ->realm, &rep.ticket.realm);
+ if (ret)
+ goto out;
+ if (f.canonicalize || r->server->entry.flags.force_canonicalize)
+ _krb5_principal2principalname(&rep.ticket.sname,
+ r->server->entry.principal);
+ else
+ _krb5_principal2principalname(&rep.ticket.sname,
+ r->server_princ);
/* java 1.6 expects the name to be the same type, lets allow that
* uncomplicated name-types. */
#define CNT(sp,t) (((sp)->sname->name_type) == KRB5_NT_##t)
r->et.flags.initial = 1;
if(r->client->entry.flags.forwardable && r->server->entry.flags.forwardable)
r->et.flags.forwardable = f.forwardable;
- else if (f.forwardable) {
- _kdc_set_e_text(r, "Ticket may not be forwardable");
- ret = KRB5KDC_ERR_POLICY;
- goto out;
- }
if(r->client->entry.flags.proxiable && r->server->entry.flags.proxiable)
r->et.flags.proxiable = f.proxiable;
else if (f.proxiable) {
}
/* check for valid set of addresses */
- if(!_kdc_check_addresses(context, config, b->addresses, from_addr)) {
+ if (!_kdc_check_addresses(r, b->addresses, r->addr)) {
_kdc_set_e_text(r, "Bad address list in requested");
ret = KRB5KRB_AP_ERR_BADADDR;
goto out;
}
}
- if (_kdc_is_anon_request(b))
- r->et.flags.anonymous = 1;
-
if(b->addresses){
ALLOC(r->et.caddr);
copy_HostAddresses(b->addresses, r->et.caddr);
ALLOC(r->ek.renew_till);
*r->ek.renew_till = *r->et.renew_till;
}
- copy_Realm(&rep.ticket.realm, &r->ek.srealm);
- copy_PrincipalName(&rep.ticket.sname, &r->ek.sname);
+ ret = copy_Realm(&rep.ticket.realm, &r->ek.srealm);
+ if (ret)
+ goto out;
+ ret = copy_PrincipalName(&rep.ticket.sname, &r->ek.sname);
+ if (ret)
+ goto out;
if(r->et.caddr){
ALLOC(r->ek.caddr);
copy_HostAddresses(r->et.caddr, r->ek.caddr);
}
/* Add the PAC */
- if (send_pac_p(context, req)) {
+ if (send_pac_p(context, req) && !r->et.flags.anonymous) {
generate_pac(r, skey);
}
- _kdc_log_timestamp(context, config, "AS-REQ", r->et.authtime, r->et.starttime,
- r->et.endtime, r->et.renew_till);
+ _kdc_log_timestamp(r, "AS-REQ", r->et.authtime,
+ r->et.starttime, r->et.endtime,
+ r->et.renew_till);
- /* do this as the last thing since this signs the EncTicketPart */
- ret = _kdc_add_KRB5SignedPath(context,
- config,
- r->server,
- setype,
- r->client->entry.principal,
- NULL,
- NULL,
- &r->et);
- if (ret)
- goto out;
+ {
+ krb5_principal client_principal;
+
+ ret = _krb5_principalname2krb5_principal(context, &client_principal,
+ rep.cname, rep.crealm);
+ if (ret)
+ goto out;
+
+ /* do this as the last thing since this signs the EncTicketPart */
+ ret = _kdc_add_KRB5SignedPath(context,
+ config,
+ r->server,
+ setype,
+ client_principal,
+ NULL,
+ NULL,
+ &r->et);
+ krb5_free_principal(context, client_principal);
+ if (ret)
+ goto out;
+ }
- log_as_req(context, config, r->reply_key.keytype, setype, b);
+ _log_astgs_req(r, setype);
/*
* We always say we support FAST/enc-pa-rep
ret = add_enc_pa_rep(r);
if (ret) {
- const char *msg = krb5_get_error_message(r->context, ret);
- _kdc_r_log(r, 0, "add_enc_pa_rep failed: %s: %d", msg, ret);
+ msg = krb5_get_error_message(r->context, ret);
+ _kdc_r_log(r, 4, "add_enc_pa_rep failed: %s: %d", msg, ret);
krb5_free_error_message(r->context, msg);
goto out;
}
ret = _kdc_encode_reply(context, config,
r->armor_crypto, req->req_body.nonce,
- &rep, &r->et, &r->ek, setype, r->server->entry.kvno,
- &skey->key, r->client->entry.kvno,
- &r->reply_key, 0, &r->e_text, reply);
+ &rep, &r->et, &r->ek, setype,
+ r->server->entry.kvno, &skey->key,
+ r->reply_kvno,
+ &r->reply_key, 0, &r->e_text, r->reply);
if (ret)
goto out;
/*
* Check if message too large
*/
- if (datagram_reply && reply->length > config->max_datagram_reply_length) {
- krb5_data_free(reply);
+ if (r->datagram_reply && r->reply->length > config->max_datagram_reply_length) {
+ krb5_data_free(r->reply);
ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
_kdc_set_e_text(r, "Reply packet too large");
}
/*
* In case of a non proxy error, build an error message.
*/
- if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE && reply->length == 0) {
- ret = _kdc_fast_mk_error(context, r,
- &error_method,
- r->armor_crypto,
- &req->req_body,
- ret, r->e_text,
- r->server_princ,
- &r->client_princ->name,
- &r->client_princ->realm,
- NULL, NULL,
- reply);
- if (ret)
- goto out2;
- }
-out2:
+ if (ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE && r->reply->length == 0)
+ ret = _kdc_fast_mk_error(r, &error_method,
+ r->armor_crypto,
+ &req->req_body,
+ ret, r->e_text,
+ r->server_princ,
+ r->client_princ ?
+ &r->client_princ->name : NULL,
+ r->client_princ ?
+ &r->client_princ->realm : NULL,
+ NULL, NULL,
+ r->reply);
+
free_EncTicketPart(&r->et);
free_EncKDCRepPart(&r->ek);
free_KDCFastState(&r->fast);
krb5_free_principal(context, r->client_princ);
r->client_princ = NULL;
}
- if (r->client_name) {
- free(r->client_name);
- r->client_name = NULL;
- }
if (r->server_princ){
krb5_free_principal(context, r->server_princ);
r->server_princ = NULL;
}
- if (r->server_name) {
- free(r->server_name);
- r->server_name = NULL;
- }
if (r->client)
_kdc_free_ent(context, r->client);
if (r->server)
return 0;
}
-
-krb5_boolean
-_kdc_is_anon_request(const KDC_REQ_BODY *b)
-{
- /* some versions of heimdal use bit 14 instead of 16 for
- request_anonymous, as indicated in the anonymous draft prior to
- version 11. Bit 14 is assigned to S4U2Proxy, but all S4U2Proxy
- requests will have a second ticket; don't consider those anonymous */
- return (b->kdc_options.request_anonymous ||
- (b->kdc_options.constrained_delegation && !b->additional_tickets));
-}