kdc: add support for HDB_ERR_WRONG_REALM
A backend can return this if asked with HDB_F_GET_CLIENT|HDB_F_FOR_AS_REQ for a KRB5_NT_ENTERPRISE_PRINCIPAL record or for HDB_F_GET_SERVER | HDB_F_FOR_TGS_REQ. entry_ex->entry.principal->realm needs to return the real realm of the principal (or at least a the realm of the next cross-realm trust hop). This is needed to route enterprise principals between AD domain trusts. Signed-off-by: Stefan Metzmacher <metze@samba.org>
This commit is contained in:

committed by
Andrew Bartlett

parent
81f9ed4a6c
commit
078e6f5dd2
@@ -1712,6 +1712,31 @@ _kdc_as_rep(kdc_request_t r,
|
|||||||
kdc_log(context, config, 5, "client %s does not have secrets at this KDC, need to proxy",
|
kdc_log(context, config, 5, "client %s does not have secrets at this KDC, need to proxy",
|
||||||
r->client_name);
|
r->client_name);
|
||||||
goto out;
|
goto out;
|
||||||
|
} else if (ret == HDB_ERR_WRONG_REALM) {
|
||||||
|
char *fixed_client_name = NULL;
|
||||||
|
|
||||||
|
ret = krb5_unparse_name(context, r->client->entry.principal,
|
||||||
|
&fixed_client_name);
|
||||||
|
if (ret) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
kdc_log(context, config, 0, "WRONG_REALM - %s -> %s",
|
||||||
|
r->client_name, 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,
|
||||||
|
&r->client->entry.principal->realm,
|
||||||
|
NULL, NULL,
|
||||||
|
reply);
|
||||||
|
goto out;
|
||||||
} else if(ret){
|
} else if(ret){
|
||||||
const char *msg = krb5_get_error_message(context, ret);
|
const char *msg = krb5_get_error_message(context, ret);
|
||||||
kdc_log(context, config, 0, "UNKNOWN -- %s: %s", r->client_name, msg);
|
kdc_log(context, config, 0, "UNKNOWN -- %s: %s", r->client_name, msg);
|
||||||
@@ -2193,7 +2218,7 @@ out:
|
|||||||
/*
|
/*
|
||||||
* In case of a non proxy error, build an error message.
|
* In case of a non proxy error, build an error message.
|
||||||
*/
|
*/
|
||||||
if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE) {
|
if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE && reply->length == 0) {
|
||||||
ret = _kdc_fast_mk_error(context, r,
|
ret = _kdc_fast_mk_error(context, r,
|
||||||
&error_method,
|
&error_method,
|
||||||
r->armor_crypto,
|
r->armor_crypto,
|
||||||
|
@@ -1647,6 +1647,32 @@ server_lookup:
|
|||||||
if(ret == HDB_ERR_NOT_FOUND_HERE) {
|
if(ret == HDB_ERR_NOT_FOUND_HERE) {
|
||||||
kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
|
kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
|
||||||
goto out;
|
goto out;
|
||||||
|
} else if (ret == HDB_ERR_WRONG_REALM) {
|
||||||
|
if (ref_realm)
|
||||||
|
free(ref_realm);
|
||||||
|
ref_realm = strdup(server->entry.principal->realm);
|
||||||
|
if (ref_realm == NULL) {
|
||||||
|
ret = ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
kdc_log(context, config, 5,
|
||||||
|
"Returning a referral to realm %s for "
|
||||||
|
"server %s.",
|
||||||
|
ref_realm, spn);
|
||||||
|
krb5_free_principal(context, sp);
|
||||||
|
sp = NULL;
|
||||||
|
free(spn);
|
||||||
|
spn = NULL;
|
||||||
|
ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
|
||||||
|
ref_realm, NULL);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
ret = krb5_unparse_name(context, sp, &spn);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
goto server_lookup;
|
||||||
} else if(ret){
|
} else if(ret){
|
||||||
const char *new_rlm, *msg;
|
const char *new_rlm, *msg;
|
||||||
Realm req_rlm;
|
Realm req_rlm;
|
||||||
|
@@ -101,6 +101,13 @@ _kdc_db_fetch(krb5_context context,
|
|||||||
config->db[i]->hdb_close(context, config->db[i]);
|
config->db[i]->hdb_close(context, config->db[i]);
|
||||||
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
|
case HDB_ERR_WRONG_REALM:
|
||||||
|
/*
|
||||||
|
* the ent->entry.principal just contains hints for the client
|
||||||
|
* to retry. This is important for enterprise principal routing
|
||||||
|
* between trusts.
|
||||||
|
*/
|
||||||
|
/* fall through */
|
||||||
case 0:
|
case 0:
|
||||||
if (db)
|
if (db)
|
||||||
*db = config->db[i];
|
*db = config->db[i];
|
||||||
|
@@ -28,5 +28,6 @@ error_code NO_WRITE_SUPPORT, "HDB backend doesn't contain write support"
|
|||||||
error_code NOT_FOUND_HERE, "The secret for this entry is not replicated to this database"
|
error_code NOT_FOUND_HERE, "The secret for this entry is not replicated to this database"
|
||||||
error_code MISUSE, "Incorrect use of the API"
|
error_code MISUSE, "Incorrect use of the API"
|
||||||
error_code KVNO_NOT_FOUND, "Entry key version number not found"
|
error_code KVNO_NOT_FOUND, "Entry key version number not found"
|
||||||
|
error_code WRONG_REALM, "The principal exists in another realm."
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user