flags.client = 0;
}
if (userAccountControl & UF_LOCKOUT) {
- flags.invalid = 1;
+ flags.locked_out = 1;
}
/*
if (userAccountControl & UF_PASSWORD_NOTREQD) {
{
struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
uint32_t userAccountControl;
+ uint32_t msDS_User_Account_Control_Computed;
unsigned int i;
krb5_error_code ret = 0;
krb5_boolean is_computer = FALSE;
userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
+ msDS_User_Account_Control_Computed
+ = ldb_msg_find_attr_as_uint(msg,
+ "msDS-User-Account-Control-Computed",
+ UF_ACCOUNTDISABLE);
+
+ /*
+ * This brings in the lockout flag, block the account if not
+ * found. We need the weird UF_ACCOUNTDISABLE check because
+ * we do not want to fail open if the value is not returned,
+ * but 0 is a valid value (all OK)
+ */
+ if (msDS_User_Account_Control_Computed == UF_ACCOUNTDISABLE) {
+ ret = EINVAL;
+ krb5_set_error_message(context, ret, "samba_kdc_message2entry: "
+ "no msDS-User-Account-Control-Computed present");
+ goto out;
+ } else {
+ userAccountControl |= msDS_User_Account_Control_Computed;
+ }
entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal)));
if (ent_type == SAMBA_KDC_ENT_TYPE_ANY && principal == NULL) {
struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
const char *dnsdomain;
const char *realm = lpcfg_realm(lp_ctx);
- DATA_BLOB password_utf16;
- struct samr_Password password_hash;
+ DATA_BLOB password_utf16 = data_blob_null;
+ DATA_BLOB password_utf8 = data_blob_null;
+ struct samr_Password _password_hash;
+ const struct samr_Password *password_hash = NULL;
const struct ldb_val *password_val;
struct trustAuthInOutBlob password_blob;
struct samba_kdc_entry *p;
bool use_previous;
uint32_t current_kvno;
+ uint32_t num_keys = 0;
enum ndr_err_code ndr_err;
int ret, trust_direction_flags;
unsigned int i;
struct AuthenticationInformationArray *auth_array;
+ uint32_t supported_enctypes = ENCTYPE_ARCFOUR_HMAC;
+
+ if (dsdb_functional_level(kdc_db_ctx->samdb) >= DS_DOMAIN_FUNCTION_2008) {
+ supported_enctypes = ldb_msg_find_attr_as_uint(msg,
+ "msDS-SupportedEncryptionTypes",
+ supported_enctypes);
+ }
p = talloc(mem_ctx, struct samba_kdc_entry);
if (!p) {
&entry_ex->entry.created_by.principal,
realm, "kadmin", NULL);
+ entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal)));
+ if (entry_ex->entry.principal == NULL) {
+ krb5_clear_error_message(context);
+ ret = ENOMEM;
+ goto out;
+ }
+
+ ret = copy_Principal(principal, entry_ex->entry.principal);
+ 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
+ */
+
+ krb5_principal_set_realm(context, entry_ex->entry.principal, realm);
+
entry_ex->entry.valid_start = NULL;
trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
}
if (!password_val || !(trust_direction_flags & direction)) {
- ret = ENOENT;
+ krb5_clear_error_message(context);
+ ret = HDB_ERR_NOENTRY;
goto out;
}
ndr_err = ndr_pull_struct_blob(password_val, mem_ctx, &password_blob,
(ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ krb5_clear_error_message(context);
ret = EINVAL;
goto out;
}
} else {
DEBUG(1,(__location__ ": Request for unknown kvno %u - current kvno is %u\n",
kvno, current_kvno));
- ret = ENOENT;
+ krb5_clear_error_message(context);
+ ret = HDB_ERR_NOENTRY;
goto out;
}
for (i=0; i < auth_array->count; i++) {
if (auth_array->array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
+ bool ok;
+
password_utf16 = data_blob_const(auth_array->array[i].AuthInfo.clear.password,
auth_array->array[i].AuthInfo.clear.size);
- /* In the future, generate all sorts of
- * hashes, but for now we can't safely convert
- * the random strings windows uses into
- * utf8 */
+ if (password_utf16.length == 0) {
+ break;
+ }
+
+ if (supported_enctypes & ENCTYPE_ARCFOUR_HMAC) {
+ mdfour(_password_hash.hash, password_utf16.data, password_utf16.length);
+ if (password_hash == NULL) {
+ num_keys += 1;
+ }
+ password_hash = &_password_hash;
+ }
+
+ if (!(supported_enctypes & (ENC_HMAC_SHA1_96_AES128|ENC_HMAC_SHA1_96_AES256))) {
+ break;
+ }
- /* but as it is utf16 already, we can get the NT password/arcfour-hmac-md5 key */
- mdfour(password_hash.hash, password_utf16.data, password_utf16.length);
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF16MUNGED, CH_UTF8,
+ password_utf16.data,
+ password_utf16.length,
+ (void *)&password_utf8.data,
+ &password_utf8.length);
+ if (!ok) {
+ krb5_clear_error_message(context);
+ ret = ENOMEM;
+ goto out;
+ }
+
+ if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
+ num_keys += 1;
+ }
+ if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
+ num_keys += 1;
+ }
break;
} else if (auth_array->array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
- password_hash = auth_array->array[i].AuthInfo.nt4owf.password;
- break;
+ if (supported_enctypes & ENCTYPE_ARCFOUR_HMAC) {
+ password_hash = &auth_array->array[i].AuthInfo.nt4owf.password;
+ num_keys += 1;
+ }
}
}
- if (i < auth_array->count) {
- Key key;
- /* Must have found a cleartext or MD4 password */
- entry_ex->entry.keys.val = calloc(1, sizeof(Key));
+ /* Must have found a cleartext or MD4 password */
+ if (num_keys == 0) {
+ DEBUG(1,(__location__ ": no usable key found\n"));
+ krb5_clear_error_message(context);
+ ret = HDB_ERR_NOENTRY;
+ goto out;
+ }
- key.mkvno = 0;
- key.salt = NULL; /* No salt for this enc type */
+ entry_ex->entry.keys.val = calloc(num_keys, sizeof(Key));
+ if (entry_ex->entry.keys.val == NULL) {
+ krb5_clear_error_message(context);
+ ret = ENOMEM;
+ goto out;
+ }
- if (entry_ex->entry.keys.val == NULL) {
- ret = ENOMEM;
+ if (password_utf8.length != 0) {
+ Key key = {};
+ krb5_const_principal salt_principal = principal;
+ krb5_salt salt;
+ krb5_data cleartext_data;
+
+ cleartext_data.data = password_utf8.data;
+ cleartext_data.length = password_utf8.length;
+
+ ret = krb5_get_pw_salt(context,
+ salt_principal,
+ &salt);
+ if (ret != 0) {
goto out;
}
+ if (supported_enctypes & ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
+ ret = krb5_string_to_key_data_salt(context,
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ cleartext_data,
+ salt,
+ &key.key);
+ if (ret != 0) {
+ krb5_free_salt(context, salt);
+ goto out;
+ }
+
+ entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
+ entry_ex->entry.keys.len++;
+ }
+
+ if (supported_enctypes & ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
+ ret = krb5_string_to_key_data_salt(context,
+ ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+ cleartext_data,
+ salt,
+ &key.key);
+ if (ret != 0) {
+ krb5_free_salt(context, salt);
+ goto out;
+ }
+
+ entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
+ entry_ex->entry.keys.len++;
+ }
+
+ krb5_free_salt(context, salt);
+ }
+
+ if (password_hash != NULL) {
+ Key key = {};
+
ret = krb5_keyblock_init(context,
ENCTYPE_ARCFOUR_HMAC,
- password_hash.hash, sizeof(password_hash.hash),
+ password_hash->hash,
+ sizeof(password_hash->hash),
&key.key);
if (ret != 0) {
goto out;
entry_ex->entry.keys.len++;
}
- entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal)));
-
- ret = copy_Principal(principal, entry_ex->entry.principal);
- 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 */
-
- krb5_principal_set_realm(context, entry_ex->entry.principal, realm);
entry_ex->entry.flags = int2HDBFlags(0);
entry_ex->entry.flags.immutable = 1;
entry_ex->entry.flags.invalid = 0;
struct ldb_dn *realm_dn,
struct ldb_message **pmsg)
{
- int lret;
- krb5_error_code ret;
- char *filter = NULL;
+ NTSTATUS status;
const char * const *attrs = trust_attrs;
- struct ldb_result *res = NULL;
- char *realm_encoded = ldb_binary_encode_string(mem_ctx, realm);
- if (!realm_encoded) {
- if (!filter) {
- ret = ENOMEM;
- krb5_set_error_message(context, ret, "talloc_asprintf: out of memory");
- return ret;
- }
- }
- filter = talloc_asprintf(mem_ctx, "(&(objectClass=trustedDomain)(|(flatname=%s)(trustPartner=%s)))",
- realm_encoded, realm_encoded);
-
- if (!filter) {
- talloc_free(realm_encoded);
- ret = ENOMEM;
- krb5_set_error_message(context, ret, "talloc_asprintf: out of memory");
- return ret;
- }
-
- lret = dsdb_search(ldb_ctx, mem_ctx, &res,
- ldb_get_default_basedn(ldb_ctx),
- LDB_SCOPE_SUBTREE, attrs,
- DSDB_SEARCH_NO_GLOBAL_CATALOG,
- "%s", filter);
- if (lret != LDB_SUCCESS) {
- DEBUG(3, ("Failed to search for %s: %s\n", filter, ldb_errstring(ldb_ctx)));
- return HDB_ERR_NOENTRY;
- } else if (res->count == 0 || res->count > 1) {
- DEBUG(3, ("Failed find a single entry for %s: got %d\n", filter, res->count));
- talloc_free(res);
+ status = sam_get_results_trust(ldb_ctx,
+ mem_ctx, realm, realm, attrs,
+ pmsg);
+ if (NT_STATUS_IS_OK(status)) {
+ return 0;
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
return HDB_ERR_NOENTRY;
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
+ int ret = ENOMEM;
+ krb5_set_error_message(context, ret, "get_sam_result_trust: out of memory");
+ return ret;
+ } else {
+ int ret = EINVAL;
+ krb5_set_error_message(context, ret, "get_sam_result_trust: %s", nt_errstr(status));
+ return ret;
}
- talloc_steal(mem_ctx, res->msgs);
- *pmsg = res->msgs[0];
- talloc_free(res);
- return 0;
}
static krb5_error_code samba_kdc_lookup_client(krb5_context context,
principal, direction,
realm_dn, flags, kvno, msg, entry_ex);
if (ret != 0) {
- krb5_warnx(context, "samba_kdc_fetch: trust_message2entry failed");
+ krb5_warnx(context, "samba_kdc_fetch: trust_message2entry failed for %s",
+ ldb_dn_get_linearized(msg->dn));
+ krb5_set_error_message(context, ret, "samba_kdc_fetch: "
+ "trust_message2entry failed for %s",
+ ldb_dn_get_linearized(msg->dn));
}
return ret;
}
} else {
int lret;
char *short_princ;
- const char *realm;
+ /* const char *realm; */
/* server as client principal case, but we must not lookup userPrincipalNames */
*realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
- realm = krb5_principal_get_realm(context, principal);
+ /* realm = krb5_principal_get_realm(context, principal); */
/* TODO: Check if it is our realm, otherwise give referral */
TALLOC_FREE(priv);
return ret;
}
+ krb5_free_default_realm(context, realm);
lret = dsdb_search(ldb_ctx, priv, &res,
priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs,