#include "includes.h"
#include "system/time.h"
-#include "kdc.h"
#include "dsdb/common/flags.h"
-#include "hdb.h"
-#include "krb5_locl.h"
#include "lib/ldb/include/ldb.h"
#include "lib/ldb/include/ldb_errors.h"
#include "librpc/gen_ndr/netlogon.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
#include "libcli/auth/libcli_auth.h"
#include "param/param.h"
+#include "events/events.h"
+#include "kdc/kdc.h"
enum hdb_ldb_ent_type
{ HDB_LDB_ENT_TYPE_CLIENT, HDB_LDB_ENT_TYPE_SERVER,
struct samr_Password *hash;
const struct ldb_val *sc_val;
struct supplementalCredentialsBlob scb;
- struct supplementalCredentialsPackage *scp = NULL;
+ struct supplementalCredentialsPackage *scpk = NULL;
+ bool newer_keys = false;
struct package_PrimaryKerberosBlob _pkb;
struct package_PrimaryKerberosCtr3 *pkb3 = NULL;
+ struct package_PrimaryKerberosCtr4 *pkb4 = NULL;
uint32_t i;
uint32_t allocated_keys = 0;
goto out;
}
- for (i=0; i < scb.sub.num_packages; i++) {
- if (scb.sub.packages[i].unknown1 != 0x00000001) {
- continue;
- }
-
- if (strcmp("Primary:Kerberos", scb.sub.packages[i].name) != 0) {
- continue;
- }
+ if (scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
+ NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
+ ret = EINVAL;
+ goto out;
+ }
- if (!scb.sub.packages[i].data || !scb.sub.packages[i].data[0]) {
- continue;
+ for (i=0; i < scb.sub.num_packages; i++) {
+ if (strcmp("Primary:Kerberos-Newer-Keys", scb.sub.packages[i].name) == 0) {
+ scpk = &scb.sub.packages[i];
+ if (!scpk->data || !scpk->data[0]) {
+ scpk = NULL;
+ continue;
+ }
+ newer_keys = true;
+ break;
+ } else if (strcmp("Primary:Kerberos", scb.sub.packages[i].name) == 0) {
+ scpk = &scb.sub.packages[i];
+ if (!scpk->data || !scpk->data[0]) {
+ scpk = NULL;
+ }
+ /*
+ * we don't break here in hope to find
+ * a Kerberos-Newer-Keys package
+ */
}
-
- scp = &scb.sub.packages[i];
- break;
}
}
- /* Primary:Kerberos element of supplementalCredentials */
- if (scp) {
+ /*
+ * Primary:Kerberos-Newer-Keys or Primary:Kerberos element
+ * of supplementalCredentials
+ */
+ if (scpk) {
DATA_BLOB blob;
- blob = strhex_to_data_blob(scp->data);
+ blob = strhex_to_data_blob(scpk->data);
if (!blob.data) {
ret = ENOMEM;
goto out;
}
talloc_steal(mem_ctx, blob.data);
- /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
+ /* we cannot use ndr_pull_struct_blob_all() here, as w2k and w2k3 add padding bytes */
ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, iconv_convenience, &_pkb,
(ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
goto out;
}
- if (_pkb.version != 3) {
- krb5_set_error_string(context, "LDB_message2entry_keys: could not parse PrimaryKerberos not version 3");
- krb5_warnx(context, "LDB_message2entry_keys: could not parse PrimaryKerberos not version 3");
+ if (newer_keys && _pkb.version != 4) {
+ krb5_set_error_string(context, "LDB_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4");
+ krb5_warnx(context, "LDB_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4");
+ ret = EINVAL;
+ goto out;
+ }
+
+ if (!newer_keys && _pkb.version != 3) {
+ krb5_set_error_string(context, "LDB_message2entry_keys: could not parse Primary:Kerberos not version 3");
+ krb5_warnx(context, "LDB_message2entry_keys: could not parse Primary:Kerberos not version 3");
ret = EINVAL;
goto out;
}
-
- pkb3 = &_pkb.ctr.ctr3;
- allocated_keys += pkb3->num_keys;
+ if (_pkb.version == 4) {
+ pkb4 = &_pkb.ctr.ctr4;
+ allocated_keys += pkb4->num_keys;
+ } else if (_pkb.version == 3) {
+ pkb3 = &_pkb.ctr.ctr3;
+ allocated_keys += pkb3->num_keys;
+ }
}
if (allocated_keys == 0) {
entry_ex->entry.keys.len++;
}
- if (pkb3) {
+ if (pkb4) {
+ for (i=0; i < pkb4->num_keys; i++) {
+ bool use = true;
+ Key key;
+
+ if (!pkb4->keys[i].value) continue;
+
+ if (userAccountControl & UF_USE_DES_KEY_ONLY) {
+ switch (pkb4->keys[i].keytype) {
+ case ENCTYPE_DES_CBC_CRC:
+ case ENCTYPE_DES_CBC_MD5:
+ break;
+ default:
+ use = false;
+ break;
+ }
+ }
+
+ if (!use) continue;
+
+ key.mkvno = 0;
+ key.salt = NULL;
+
+ if (pkb4->salt.string) {
+ DATA_BLOB salt;
+
+ salt = data_blob_string_const(pkb4->salt.string);
+
+ key.salt = calloc(1, sizeof(*key.salt));
+ if (key.salt == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ key.salt->type = hdb_pw_salt;
+
+ ret = krb5_data_copy(&key.salt->salt, salt.data, salt.length);
+ if (ret) {
+ free(key.salt);
+ key.salt = NULL;
+ goto out;
+ }
+ }
+
+ /* TODO: maybe pass the iteration_count somehow... */
+
+ ret = krb5_keyblock_init(context,
+ pkb4->keys[i].keytype,
+ pkb4->keys[i].value->data,
+ pkb4->keys[i].value->length,
+ &key.key);
+ if (ret) {
+ if (key.salt) {
+ free_Salt(key.salt);
+ free(key.salt);
+ key.salt = NULL;
+ }
+ goto out;
+ }
+
+ entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
+ entry_ex->entry.keys.len++;
+ }
+ } else if (pkb3) {
for (i=0; i < pkb3->num_keys; i++) {
bool use = true;
Key key;
if (!use) continue;
key.mkvno = 0;
+ key.salt = NULL;
if (pkb3->salt.string) {
DATA_BLOB salt;
entry_ex->entry.valid_start = NULL;
- acct_expiry = samdb_result_nttime(msg, "accountExpires", (NTTIME)-1);
- if ((acct_expiry == (NTTIME)-1) ||
- (acct_expiry == 0x7FFFFFFFFFFFFFFFULL)) {
+ acct_expiry = samdb_result_account_expires(msg);
+ if (acct_expiry == 0x7FFFFFFFFFFFFFFFULL) {
entry_ex->entry.valid_end = NULL;
} else {
entry_ex->entry.valid_end = malloc(sizeof(*entry_ex->entry.valid_end));
{
krb5_error_code ret;
struct ldb_message **msg = NULL;
- struct ldb_message **realm_ref_msg = NULL;
+ struct ldb_message **realm_ref_msg_1 = NULL;
+ struct ldb_message **realm_ref_msg_2 = NULL;
struct ldb_dn *realm_dn;
krb5_principal alloc_principal = NULL;
}
/* krbtgt case. Either us or a trusted realm */
+
if ((LDB_lookup_realm(context, (struct ldb_context *)db->hdb_db,
- mem_ctx, principal->name.name_string.val[1], &realm_ref_msg) == 0)) {
+ mem_ctx, principal->realm, &realm_ref_msg_1) == 0)
+ && (LDB_lookup_realm(context, (struct ldb_context *)db->hdb_db,
+ mem_ctx, principal->name.name_string.val[1], &realm_ref_msg_2) == 0)
+ && (ldb_dn_cmp(realm_ref_msg_1[0]->dn, realm_ref_msg_1[0]->dn) == 0)) {
/* us */
/* Cludge, cludge cludge. If the realm part of krbtgt/realm,
* is in our db, then direct the caller at our primary
- * krgtgt */
+ * krbtgt */
- const char *dnsdomain = ldb_msg_find_attr_as_string(realm_ref_msg[0], "dnsRoot", NULL);
+ const char *dnsdomain = ldb_msg_find_attr_as_string(realm_ref_msg_1[0], "dnsRoot", NULL);
char *realm_fixed = strupper_talloc(mem_ctx, dnsdomain);
if (!realm_fixed) {
krb5_set_error_string(context, "strupper_talloc: out of memory");
return ENOMEM;
}
principal = alloc_principal;
- realm_dn = samdb_result_dn((struct ldb_context *)db->hdb_db, mem_ctx, realm_ref_msg[0], "nCName", NULL);
+ realm_dn = samdb_result_dn((struct ldb_context *)db->hdb_db, mem_ctx, realm_ref_msg_1[0], "nCName", NULL);
} else {
+ enum direction {
+ INBOUND,
+ OUTBOUND
+ }
+
+ struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"), struct loadparm_context *);
+ /* Either an inbound or outbound trust */
+
+ if (strcasecmp(lp_realm(lp_ctx), principal->realm) == 0) {
+ /* look for inbound trust */
+ }
+
+ if (strcasecmp(lp_realm(lp_ctx), principal->name.name_string.val[1]) == 0) {
+ /* look for outbound trust */
+ }
+
+ /* Trusted domains are under CN=system */
+
/* we should lookup trusted domains */
return HDB_ERR_NOENTRY;
}
if (ret != HDB_ERR_NOENTRY) goto done;
}
if (flags & HDB_F_GET_SERVER) {
- ret = LDB_fetch_server(context, db, mem_ctx, principal, flags, entry_ex);
- if (ret != HDB_ERR_NOENTRY) goto done;
+ /* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */
ret = LDB_fetch_krbtgt(context, db, mem_ctx, principal, flags, entry_ex);
if (ret != HDB_ERR_NOENTRY) goto done;
+
+ /* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */
+ ret = LDB_fetch_server(context, db, mem_ctx, principal, flags, entry_ex);
+ if (ret != HDB_ERR_NOENTRY) goto done;
}
if (flags & HDB_F_GET_KRBTGT) {
ret = LDB_fetch_krbtgt(context, db, mem_ctx, principal, flags, entry_ex);
* code */
NTSTATUS kdc_hdb_ldb_create(TALLOC_CTX *mem_ctx,
+ struct event_context *ev_ctx,
struct loadparm_context *lp_ctx,
krb5_context context, struct HDB **db, const char *arg)
{
CRED_DONT_USE_KERBEROS);
/* Setup the link to LDB */
- (*db)->hdb_db = samdb_connect(*db, lp_ctx, session_info);
+ (*db)->hdb_db = samdb_connect(*db, ev_ctx, lp_ctx, session_info);
if ((*db)->hdb_db == NULL) {
DEBUG(1, ("hdb_ldb_create: Cannot open samdb for KDC backend!"));
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
{
NTSTATUS nt_status;
/* The global kdc_mem_ctx and kdc_lp_ctx, Disgusting, ugly hack, but it means one less private hook */
- nt_status = kdc_hdb_ldb_create(kdc_mem_ctx, kdc_lp_ctx,
+ nt_status = kdc_hdb_ldb_create(kdc_mem_ctx, event_context_find(kdc_mem_ctx), kdc_lp_ctx,
context, db, arg);
if (NT_STATUS_IS_OK(nt_status)) {