#include "includes.h"
#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
#include "auth/auth.h"
#include "auth/auth_sam.h"
#include "dsdb/samdb/samdb.h"
#include "dsdb/common/util.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
#include "param/param.h"
+#include "param/secrets.h"
#include "../lib/crypto/md4.h"
#include "system/kerberos.h"
#include "auth/kerberos/kerberos.h"
#include "kdc/sdb.h"
#include "kdc/samba_kdc.h"
#include "kdc/db-glue.h"
+#include "kdc/pac-glue.h"
#include "librpc/gen_ndr/ndr_irpc_c.h"
#include "lib/messaging/irpc.h"
+#undef strcasecmp
+#undef strncasecmp
#define SAMBA_KVNO_GET_KRBTGT(kvno) \
((uint16_t)(((uint32_t)kvno) >> 16))
flags.require_preauth = 0;
} else {
flags.require_preauth = 1;
+ }
+ if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
+ flags.no_auth_data_reqd = 1;
}
+
return flags;
}
return 0;
}
+int samba_kdc_set_fixed_keys(krb5_context context,
+ struct samba_kdc_db_context *kdc_db_ctx,
+ const struct ldb_val *secretbuffer,
+ bool is_protected,
+ struct sdb_entry_ex *entry_ex)
+{
+ uint32_t supported_enctypes = ENC_ALL_TYPES;
+ uint16_t allocated_keys = 0;
+ int ret;
+
+ allocated_keys = 3;
+ entry_ex->entry.keys.len = 0;
+ entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(struct sdb_key));
+ if (entry_ex->entry.keys.val == NULL) {
+ memset(secretbuffer->data, 0, secretbuffer->length);
+ ret = ENOMEM;
+ goto out;
+ }
+
+ if (is_protected) {
+ supported_enctypes &= ~ENC_RC4_HMAC_MD5;
+ }
+
+ if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
+ struct sdb_key key = {};
+
+ ret = smb_krb5_keyblock_init_contents(context,
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ secretbuffer->data,
+ MIN(secretbuffer->length, 32),
+ &key.key);
+ if (ret) {
+ memset(secretbuffer->data, 0, secretbuffer->length);
+ goto out;
+ }
+
+ entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
+ entry_ex->entry.keys.len++;
+ }
+
+ if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
+ struct sdb_key key = {};
+
+ ret = smb_krb5_keyblock_init_contents(context,
+ ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+ secretbuffer->data,
+ MIN(secretbuffer->length, 16),
+ &key.key);
+ if (ret) {
+ memset(secretbuffer->data, 0, secretbuffer->length);
+ goto out;
+ }
+
+ entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
+ entry_ex->entry.keys.len++;
+ }
+
+ if (supported_enctypes & ENC_RC4_HMAC_MD5) {
+ struct sdb_key key = {};
+
+ ret = smb_krb5_keyblock_init_contents(context,
+ ENCTYPE_ARCFOUR_HMAC,
+ secretbuffer->data,
+ MIN(secretbuffer->length, 16),
+ &key.key);
+ if (ret) {
+ memset(secretbuffer->data, 0, secretbuffer->length);
+ goto out;
+ }
+
+ entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
+ entry_ex->entry.keys.len++;
+ }
+ ret = 0;
+out:
+ return ret;
+}
+
+
+static int samba_kdc_set_random_keys(krb5_context context,
+ struct samba_kdc_db_context *kdc_db_ctx,
+ struct sdb_entry_ex *entry_ex,
+ bool is_protected)
+{
+ struct ldb_val secret_val;
+ uint8_t secretbuffer[32];
+
+ /*
+ * Fake keys until we have a better way to reject
+ * non-pkinit requests.
+ *
+ * We just need to indicate which encryption types are
+ * supported.
+ */
+ generate_secret_buffer(secretbuffer, sizeof(secretbuffer));
+
+ secret_val = data_blob_const(secretbuffer,
+ sizeof(secretbuffer));
+ return samba_kdc_set_fixed_keys(context, kdc_db_ctx,
+ &secret_val,
+ is_protected,
+ entry_ex);
+}
+
+
static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
struct samba_kdc_db_context *kdc_db_ctx,
TALLOC_CTX *mem_ctx,
bool is_rodc,
uint32_t userAccountControl,
enum samba_kdc_ent_type ent_type,
- struct sdb_entry_ex *entry_ex)
+ struct sdb_entry_ex *entry_ex,
+ bool is_protected,
+ uint32_t *supported_enctypes_out)
{
krb5_error_code ret = 0;
enum ndr_err_code ndr_err;
= ldb_msg_find_attr_as_uint(msg,
"msDS-SupportedEncryptionTypes",
0);
+ *supported_enctypes_out = 0;
if (rid == DOMAIN_RID_KRBTGT || is_rodc) {
+ bool enable_fast;
+
/* KDCs (and KDCs on RODCs) use AES */
supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
+
+ enable_fast = lpcfg_kdc_enable_fast(kdc_db_ctx->lp_ctx);
+ if (enable_fast) {
+ supported_enctypes |= ENC_FAST_SUPPORTED;
+ }
} else if (userAccountControl & (UF_PARTIAL_SECRETS_ACCOUNT|UF_SERVER_TRUST_ACCOUNT)) {
/* DCs and RODCs comptuer accounts use AES */
supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
supported_enctypes |= ENC_RC4_HMAC_MD5;
}
+ if (is_protected) {
+ supported_enctypes &= ~ENC_RC4_HMAC_MD5;
+ }
+
/* Is this the krbtgt or a RODC krbtgt */
if (is_rodc) {
rodc_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
if ((ent_type == SAMBA_KDC_ENT_TYPE_CLIENT)
&& (userAccountControl & UF_SMARTCARD_REQUIRED)) {
- uint8_t secretbuffer[32];
-
- /*
- * Fake keys until we have a better way to reject
- * non-pkinit requests.
- *
- * We just need to indicate which encryption types are
- * supported.
- */
- generate_secret_buffer(secretbuffer, sizeof(secretbuffer));
-
- allocated_keys = 3;
- entry_ex->entry.keys.len = 0;
- entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(struct sdb_key));
- if (entry_ex->entry.keys.val == NULL) {
- ZERO_STRUCT(secretbuffer);
- ret = ENOMEM;
- goto out;
- }
+ ret = samba_kdc_set_random_keys(context,
+ kdc_db_ctx,
+ entry_ex,
+ is_protected);
- if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
- struct sdb_key key = {};
+ *supported_enctypes_out = supported_enctypes;
- ret = smb_krb5_keyblock_init_contents(context,
- ENCTYPE_AES256_CTS_HMAC_SHA1_96,
- secretbuffer, 32,
- &key.key);
- if (ret) {
- ZERO_STRUCT(secretbuffer);
- goto out;
- }
-
- entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
- entry_ex->entry.keys.len++;
- }
-
- if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
- struct sdb_key key = {};
-
- ret = smb_krb5_keyblock_init_contents(context,
- ENCTYPE_AES128_CTS_HMAC_SHA1_96,
- secretbuffer, 16,
- &key.key);
- if (ret) {
- ZERO_STRUCT(secretbuffer);
- goto out;
- }
-
- entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
- entry_ex->entry.keys.len++;
- }
-
- if (supported_enctypes & ENC_RC4_HMAC_MD5) {
- struct sdb_key key = {};
-
- ret = smb_krb5_keyblock_init_contents(context,
- ENCTYPE_ARCFOUR_HMAC,
- secretbuffer, 16,
- &key.key);
- if (ret) {
- ZERO_STRUCT(secretbuffer);
- goto out;
- }
-
- entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
- entry_ex->entry.keys.len++;
- }
-
- ret = 0;
goto out;
}
entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
entry_ex->entry.keys.len++;
+
+ *supported_enctypes_out |= ENC_RC4_HMAC_MD5;
}
if (pkb4) {
for (i=0; i < pkb4->num_keys; i++) {
struct sdb_key key = {};
+ uint32_t enctype_bit;
if (!pkb4->keys[i].value) continue;
- if (!(kerberos_enctype_to_bitmap(pkb4->keys[i].keytype) & supported_enctypes)) {
+ enctype_bit = kerberos_enctype_to_bitmap(pkb4->keys[i].keytype);
+ if (!(enctype_bit & supported_enctypes)) {
continue;
}
pkb4->keys[i].value->data,
pkb4->keys[i].value->length,
&key.key);
- if (ret == KRB5_PROG_ETYPE_NOSUPP) {
- DEBUG(2,("Unsupported keytype ignored - type %u\n",
- pkb4->keys[i].keytype));
- ret = 0;
- continue;
- }
if (ret) {
if (key.salt) {
smb_krb5_free_data_contents(context, &key.salt->salt);
free(key.salt);
key.salt = NULL;
}
+ if (ret == KRB5_PROG_ETYPE_NOSUPP) {
+ DEBUG(2,("Unsupported keytype ignored - type %u\n",
+ pkb4->keys[i].keytype));
+ ret = 0;
+ continue;
+ }
goto out;
}
entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
entry_ex->entry.keys.len++;
+
+ *supported_enctypes_out |= enctype_bit;
}
} else if (pkb3) {
for (i=0; i < pkb3->num_keys; i++) {
struct sdb_key key = {};
+ uint32_t enctype_bit;
if (!pkb3->keys[i].value) continue;
- if (!(kerberos_enctype_to_bitmap(pkb3->keys[i].keytype) & supported_enctypes)) {
+ enctype_bit = kerberos_enctype_to_bitmap(pkb3->keys[i].keytype);
+ if (!(enctype_bit & supported_enctypes)) {
continue;
}
free(key.salt);
key.salt = NULL;
}
+ if (ret == KRB5_PROG_ETYPE_NOSUPP) {
+ DEBUG(2,("Unsupported keytype ignored - type %u\n",
+ pkb3->keys[i].keytype));
+ ret = 0;
+ continue;
+ }
goto out;
}
entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
entry_ex->entry.keys.len++;
+
+ *supported_enctypes_out |= enctype_bit;
}
}
+ /* Set FAST support bits */
+ *supported_enctypes_out |= supported_enctypes & (ENC_FAST_SUPPORTED |
+ ENC_COMPOUND_IDENTITY_SUPPORTED |
+ ENC_CLAIMS_SUPPORTED);
+
out:
if (ret != 0) {
entry_ex->entry.keys.len = 0;
uint32_t msDS_User_Account_Control_Computed;
krb5_error_code ret = 0;
krb5_boolean is_computer = FALSE;
-
struct samba_kdc_entry *p;
+ uint32_t supported_enctypes = 0;
NTTIME acct_expiry;
NTSTATUS status;
-
+ bool protected_user = false;
uint32_t rid;
bool is_rodc = false;
struct ldb_message_element *objectclasses;
- struct ldb_val computer_val;
+ struct ldb_val computer_val = data_blob_string_const("computer");
const char *samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
- computer_val.data = discard_const_p(uint8_t,"computer");
- computer_val.length = strlen((const char *)computer_val.data);
if (ldb_msg_find_element(msg, "msDS-SecondaryKrbTgtNumber")) {
is_rodc = true;
userAccountControl |= msDS_User_Account_Control_Computed;
}
- /*
+ /*
* If we are set to canonicalize, we get back the fixed UPPER
* case realm, and the real username (ie matching LDAP
- * samAccountName)
+ * samAccountName)
*
* Otherwise, if we are set to enterprise, we
- * get back the whole principal as-sent
+ * get back the whole principal as-sent
*
* Finally, if we are not set to canonicalize, we get back the
* fixed UPPER case realm, but the as-sent username
if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT) {
p->is_krbtgt = true;
- if (flags & (SDB_F_CANON)) {
+ if (flags & (SDB_F_CANON|SDB_F_FORCE_CANON)) {
/*
* When requested to do so, ensure that the
* both realm values in the principal are set
krb5_clear_error_message(context);
goto out;
}
- } else if ((flags & SDB_F_CANON) && (flags & SDB_F_FOR_AS_REQ)) {
+ } else if ((flags & SDB_F_FORCE_CANON) ||
+ ((flags & SDB_F_CANON) && (flags & SDB_F_FOR_AS_REQ))) {
/*
* SDB_F_CANON maps from the canonicalize flag in the
* packet, and has a different meaning between AS-REQ
* and TGS-REQ. We only change the principal in the AS-REQ case
+ *
+ * The SDB_F_FORCE_CANON if for new MIT KDC code that wants
+ * the canonical name in all lookups, and takes care to
+ * canonicalize only when appropriate.
*/
ret = smb_krb5_make_principal(context, &entry_ex->entry.principal, lpcfg_realm(lp_ctx), samAccountName, NULL);
if (ret) {
goto out;
}
- if (smb_krb5_principal_get_type(context, principal) != KRB5_NT_ENTERPRISE_PRINCIPAL) {
- /* While we have copied the client principal, tests
- * show that Win2k3 returns the 'corrected' realm, not
- * the client-specified realm. This code attempts to
- * replace the client principal's realm with the one
- * we determine from our records */
-
- /* this has to be with malloc() */
- ret = smb_krb5_principal_set_realm(context, entry_ex->entry.principal, lpcfg_realm(lp_ctx));
- if (ret) {
- krb5_clear_error_message(context);
- goto out;
- }
+ /* While we have copied the client principal, tests
+ * show that Win2k3 returns the 'corrected' realm, not
+ * the client-specified realm. This code attempts to
+ * replace the client principal's realm with the one
+ * we determine from our records */
+
+ /* this has to be with malloc() */
+ ret = smb_krb5_principal_set_realm(context, entry_ex->entry.principal, lpcfg_realm(lp_ctx));
+ if (ret) {
+ krb5_clear_error_message(context);
+ goto out;
}
}
/* First try and figure out the flags based on the userAccountControl */
entry_ex->entry.flags = uf2SDBFlags(context, userAccountControl, ent_type);
+ /*
+ * Take control of the returned principal here, rather than
+ * allowing the Heimdal code to do it as we have specific
+ * behaviour around the forced realm to honour
+ */
+ entry_ex->entry.flags.force_canonicalize = true;
+
/* Windows 2008 seems to enforce this (very sensible) rule by
* default - don't allow offline attacks on a user's password
* by asking for a ticket to them as a service (encrypted with
entry_ex->entry.flags.server = 0;
}
}
+
+ /*
+ * We restrict a 3-part SPN ending in my domain/realm to full
+ * domain controllers.
+ *
+ * This avoids any cases where (eg) a demoted DC still has
+ * these more restricted SPNs.
+ */
+ if (krb5_princ_size(context, principal) > 2) {
+ char *third_part
+ = smb_krb5_principal_get_comp_string(mem_ctx,
+ context,
+ principal,
+ 2);
+ bool is_our_realm =
+ lpcfg_is_my_domain_or_realm(lp_ctx,
+ third_part);
+ bool is_dc = userAccountControl &
+ (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT);
+ if (is_our_realm && !is_dc) {
+ entry_ex->entry.flags.server = 0;
+ }
+ }
/*
* To give the correct type of error to the client, we must
* not just return the entry without .server set, we must
kdc_db_ctx->policy.usr_tkt_lifetime);
}
- entry_ex->entry.max_renew = malloc(sizeof(*entry_ex->entry.max_life));
+ entry_ex->entry.max_renew = malloc(sizeof(*entry_ex->entry.max_renew));
if (entry_ex->entry.max_renew == NULL) {
ret = ENOMEM;
goto out;
*entry_ex->entry.max_renew = kdc_db_ctx->policy.renewal_lifetime;
+ if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT && (flags & SDB_F_FOR_AS_REQ)) {
+ int result;
+ struct auth_user_info_dc *user_info_dc = NULL;
+ /*
+ * These protections only apply to clients, so servers in the
+ * Protected Users group may still have service tickets to them
+ * encrypted with RC4. For accounts looked up as servers, note
+ * that 'msg' does not contain the 'memberOf' attribute for
+ * determining whether the account is a member of Protected
+ * Users.
+ *
+ * Additionally, Microsoft advises that accounts for services
+ * and computers should never be members of Protected Users, or
+ * they may fail to authenticate.
+ */
+ status = samba_kdc_get_user_info_from_db(p, msg, &user_info_dc);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = EINVAL;
+ goto out;
+ }
+
+ result = dsdb_is_protected_user(kdc_db_ctx->samdb,
+ user_info_dc->sids,
+ user_info_dc->num_sids);
+ if (result == -1) {
+ ret = EINVAL;
+ goto out;
+ }
+
+ protected_user = result;
+
+ if (protected_user) {
+ *entry_ex->entry.max_life = MIN(*entry_ex->entry.max_life, 4 * 60 * 60);
+ *entry_ex->entry.max_renew = MIN(*entry_ex->entry.max_renew, 4 * 60 * 60);
+
+ entry_ex->entry.flags.forwardable = 0;
+ entry_ex->entry.flags.proxiable = 0;
+ }
+ }
+
/* Get keys from the db */
ret = samba_kdc_message2entry_keys(context, kdc_db_ctx, p, msg,
rid, is_rodc, userAccountControl,
- ent_type, entry_ex);
+ ent_type, entry_ex, protected_user, &supported_enctypes);
if (ret) {
/* Could be bogus data in the entry, or out of memory */
goto out;
}
p->msg = talloc_steal(p, msg);
+ p->supported_enctypes = supported_enctypes;
out:
if (ret != 0) {
p->is_trust = true;
p->kdc_db_ctx = kdc_db_ctx;
p->realm_dn = realm_dn;
+ p->supported_enctypes = supported_enctypes;
talloc_set_destructor(p, samba_kdc_entry_destructor);
entry_ex->entry.max_renew = NULL;
+ /* Match Windows behavior and allow forwardable flag in cross-realm. */
+ entry_ex->entry.flags.forwardable = 1;
+
ret = samba_kdc_sort_encryption_keys(entry_ex);
if (ret != 0) {
krb5_clear_error_message(context);
/* Check if a given entry may delegate or do s4u2self to this target principal
*
- * This is currently a very nasty hack - allowing only delegation to itself.
+ * The safest way to determine 'self' is to check the DB record made at
+ * the time the principal was presented to the KDC.
*/
krb5_error_code
-samba_kdc_check_s4u2self(krb5_context context,
- struct samba_kdc_db_context *kdc_db_ctx,
- struct samba_kdc_entry *skdc_entry,
- krb5_const_principal target_principal)
+samba_kdc_check_client_matches_target_service(krb5_context context,
+ struct samba_kdc_entry *skdc_entry_client,
+ struct samba_kdc_entry *skdc_entry_server_target)
{
- krb5_error_code ret;
- struct ldb_dn *realm_dn;
- struct ldb_message *msg;
struct dom_sid *orig_sid;
struct dom_sid *target_sid;
- const char *delegation_check_attrs[] = {
- "objectSid", NULL
- };
-
- TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2self");
-
- if (!mem_ctx) {
- ret = ENOMEM;
- krb5_set_error_message(context, ret, "samba_kdc_check_s4u2self: talloc_named() failed!");
- return ret;
- }
-
- ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, target_principal,
- SDB_F_GET_CLIENT|SDB_F_GET_SERVER,
- delegation_check_attrs, &realm_dn, &msg);
-
- if (ret != 0) {
- talloc_free(mem_ctx);
- return ret;
- }
+ TALLOC_CTX *frame = talloc_stackframe();
- orig_sid = samdb_result_dom_sid(mem_ctx, skdc_entry->msg, "objectSid");
- target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
+ orig_sid = samdb_result_dom_sid(frame,
+ skdc_entry_client->msg,
+ "objectSid");
+ target_sid = samdb_result_dom_sid(frame,
+ skdc_entry_server_target->msg,
+ "objectSid");
- /* Allow delegation to the same principal, even if by a different
- * name. The easy and safe way to prove this is by SID
- * comparison */
+ /*
+ * Allow delegation to the same record (representing a
+ * principal), even if by a different name. The easy and safe
+ * way to prove this is by SID comparison
+ */
if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
- talloc_free(mem_ctx);
- return KRB5KDC_ERR_BADOPTION;
+ talloc_free(frame);
+ return KRB5KRB_AP_ERR_BADMATCH;
}
- talloc_free(mem_ctx);
- return ret;
+ talloc_free(frame);
+ return 0;
}
/* Certificates printed by a the Certificate Authority might have a
return ret;
}
+ el = ldb_msg_find_element(skdc_entry->msg, "msDS-AllowedToDelegateTo");
+ if (el == NULL) {
+ ret = ENOENT;
+ goto bad_option;
+ }
+ SMB_ASSERT(el->num_values != 0);
+
+ /*
+ * This is the Microsoft forwardable flag behavior.
+ *
+ * If the proxy (target) principal is NULL, and we have any authorized
+ * delegation target, allow to forward.
+ */
+ if (target_principal == NULL) {
+ return 0;
+ }
+
+
/*
* The main heimdal code already checked that the target_principal
* belongs to the same realm as the client.
return ret;
}
- el = ldb_msg_find_element(skdc_entry->msg, "msDS-AllowedToDelegateTo");
- if (el == NULL) {
- goto bad_option;
- }
-
val = data_blob_string_const(target_principal_name);
for (i=0; i<el->num_values; i++) {
}
if (!found) {
+ ret = ENOENT;
goto bad_option;
}
return KRB5KDC_ERR_BADOPTION;
}
+/*
+ * This method is called for S4U2Proxy requests and implements the
+ * resource-based constrained delegation variant, which can support
+ * cross-realm delegation.
+ */
+krb5_error_code samba_kdc_check_s4u2proxy_rbcd(
+ krb5_context context,
+ struct samba_kdc_db_context *kdc_db_ctx,
+ krb5_const_principal client_principal,
+ krb5_const_principal server_principal,
+ krb5_pac header_pac,
+ struct samba_kdc_entry *proxy_skdc_entry)
+{
+ krb5_error_code code;
+ enum ndr_err_code ndr_err;
+ char *client_name = NULL;
+ char *server_name = NULL;
+ const char *proxy_dn = NULL;
+ const DATA_BLOB *data = NULL;
+ struct security_descriptor *rbcd_security_descriptor = NULL;
+ struct auth_user_info_dc *user_info_dc = NULL;
+ struct auth_session_info *session_info = NULL;
+ uint32_t session_info_flags = AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
+ uint32_t access_desired = SEC_ADS_GENERIC_ALL; /* => 0x000f01ff */
+ uint32_t access_granted = 0;
+ NTSTATUS nt_status;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ mem_ctx = talloc_named(kdc_db_ctx,
+ 0,
+ "samba_kdc_check_s4u2proxy_rbcd");
+ if (mem_ctx == NULL) {
+ errno = ENOMEM;
+ code = errno;
+
+ return code;
+ }
+
+ proxy_dn = ldb_dn_get_linearized(proxy_skdc_entry->msg->dn);
+ if (proxy_dn == NULL) {
+ DBG_ERR("ldb_dn_get_linearized failed for proxy_dn!\n");
+ TALLOC_FREE(mem_ctx);
+ if (errno == 0) {
+ errno = ENOMEM;
+ }
+ code = errno;
+
+ goto out;
+ }
+
+ rbcd_security_descriptor = talloc_zero(mem_ctx,
+ struct security_descriptor);
+ if (rbcd_security_descriptor == NULL) {
+ errno = ENOMEM;
+ code = errno;
+
+ goto out;
+ }
+
+ code = krb5_unparse_name_flags(context,
+ client_principal,
+ KRB5_PRINCIPAL_UNPARSE_DISPLAY,
+ &client_name);
+ if (code != 0) {
+ DBG_ERR("Unable to parse client_principal!\n");
+ goto out;
+ }
+
+ code = krb5_unparse_name_flags(context,
+ server_principal,
+ KRB5_PRINCIPAL_UNPARSE_DISPLAY,
+ &server_name);
+ if (code != 0) {
+ DBG_ERR("Unable to parse server_principal!\n");
+ SAFE_FREE(client_name);
+ goto out;
+ }
+
+ DBG_INFO("Check delegation from client[%s] to server[%s] via "
+ "proxy[%s]\n",
+ client_name,
+ server_name,
+ proxy_dn);
+
+ code = kerberos_pac_to_user_info_dc(mem_ctx,
+ header_pac,
+ context,
+ &user_info_dc,
+ NULL,
+ NULL);
+ if (code != 0) {
+ goto out;
+ }
+
+ if (user_info_dc->info->authenticated) {
+ session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
+ }
+
+ nt_status = auth_generate_session_info(mem_ctx,
+ kdc_db_ctx->lp_ctx,
+ kdc_db_ctx->samdb,
+ user_info_dc,
+ session_info_flags,
+ &session_info);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ code = map_errno_from_nt_status(nt_status);
+ goto out;
+ }
+
+ data = ldb_msg_find_ldb_val(proxy_skdc_entry->msg,
+ "msDS-AllowedToActOnBehalfOfOtherIdentity");
+ if (data == NULL) {
+ DBG_ERR("Could not find security descriptor"
+ "msDS-AllowedToActOnBehalfOfOtherIdentity in "
+ "proxy[%s]\n",
+ proxy_dn);
+ code = KRB5KDC_ERR_BADOPTION;
+ goto out;
+ }
+
+ ndr_err = ndr_pull_struct_blob(
+ data,
+ mem_ctx,
+ rbcd_security_descriptor,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ errno = ndr_map_error2errno(ndr_err);
+ DBG_ERR("Failed to unmarshall "
+ "msDS-AllowedToActOnBehalfOfOtherIdentity "
+ "security descriptor of proxy[%s]\n",
+ proxy_dn);
+ code = KRB5KDC_ERR_BADOPTION;
+ goto out;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(security_token, session_info->security_token);
+ NDR_PRINT_DEBUG(security_descriptor, rbcd_security_descriptor);
+ }
+
+ nt_status = sec_access_check_ds(rbcd_security_descriptor,
+ session_info->security_token,
+ access_desired,
+ &access_granted,
+ NULL,
+ NULL);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DBG_WARNING("RBCD: sec_access_check_ds(access_desired=%#08x, "
+ "access_granted:%#08x) failed with: %s\n",
+ access_desired,
+ access_granted,
+ nt_errstr(nt_status));
+
+ code = KRB5KDC_ERR_BADOPTION;
+ goto out;
+ }
+
+ DBG_NOTICE("RBCD: Access granted for client[%s]\n", client_name);
+
+ code = 0;
+out:
+ SAFE_FREE(client_name);
+ SAFE_FREE(server_name);
+
+ TALLOC_FREE(mem_ctx);
+ return code;
+}
+
NTSTATUS samba_kdc_setup_db_ctx(TALLOC_CTX *mem_ctx, struct samba_kdc_base_context *base_ctx,
struct samba_kdc_db_context **kdc_db_ctx_out)
{
return NT_STATUS_INTERNAL_ERROR;
}
+ /* Setup the link to secrets.ldb */
+
+ kdc_db_ctx->secrets_db = secrets_db_connect(kdc_db_ctx,
+ base_ctx->lp_ctx);
+ if (kdc_db_ctx->secrets_db == NULL) {
+ DEBUG(1, ("samba_kdc_setup_db_ctx: "
+ "Cannot open secrets.ldb for KDC backend!"));
+ talloc_free(kdc_db_ctx);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ kdc_db_ctx->fx_cookie_dn = ldb_dn_new(kdc_db_ctx,
+ kdc_db_ctx->secrets_db,
+ "CN=FX Cookie");
+
/* Setup the link to LDB */
kdc_db_ctx->samdb = samdb_connect(kdc_db_ctx,
base_ctx->ev_ctx,
}
*kdc_db_ctx_out = kdc_db_ctx;
return NT_STATUS_OK;
-}
+}
\ No newline at end of file