#include "kdc/sdb.h"
#include "kdc/samba_kdc.h"
#include "kdc/db-glue.h"
+#include "librpc/gen_ndr/ndr_irpc_c.h"
+#include "lib/messaging/irpc.h"
+
#define SAMBA_KVNO_GET_KRBTGT(kvno) \
((uint16_t)(((uint32_t)kvno) >> 16))
NULL
};
+/*
+ send a message to the drepl server telling it to initiate a
+ REPL_SECRET getncchanges extended op to fetch the users secrets
+ */
+static void auth_sam_trigger_repl_secret(TALLOC_CTX *mem_ctx,
+ struct imessaging_context *msg_ctx,
+ struct tevent_context *event_ctx,
+ struct ldb_dn *user_dn)
+{
+ struct dcerpc_binding_handle *irpc_handle;
+ struct drepl_trigger_repl_secret r;
+ struct tevent_req *req;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return;
+ }
+
+ irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg_ctx,
+ "dreplsrv",
+ &ndr_table_irpc);
+ if (irpc_handle == NULL) {
+ DEBUG(1,(__location__ ": Unable to get binding handle for dreplsrv\n"));
+ TALLOC_FREE(tmp_ctx);
+ return;
+ }
+
+ r.in.user_dn = ldb_dn_get_linearized(user_dn);
+
+ /*
+ * This seem to rely on the current IRPC implementation,
+ * which delivers the message in the _send function.
+ *
+ * TODO: we need a ONE_WAY IRPC handle and register
+ * a callback and wait for it to be triggered!
+ */
+ req = dcerpc_drepl_trigger_repl_secret_r_send(tmp_ctx,
+ event_ctx,
+ irpc_handle,
+ &r);
+
+ /* we aren't interested in a reply */
+ talloc_free(req);
+ TALLOC_FREE(tmp_ctx);
+}
static time_t ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, const char *attr, time_t default_val)
{
return 0;
}
+/*
+ * Sort keys in descending order of strength.
+ *
+ * Explanaton from Greg Hudson:
+ *
+ * To encrypt tickets only the first returned key is used by the MIT KDC. The
+ * other keys just communicate support for session key enctypes, and aren't
+ * really used. The encryption key for the ticket enc part doesn't have
+ * to be of a type requested by the client. The session key enctype is chosen
+ * based on the client preference order, limited by the set of enctypes present
+ * in the server keys (unless the string attribute is set on the server
+ * principal overriding that set).
+ */
+static int samba_kdc_sort_encryption_keys(struct sdb_entry_ex *entry_ex)
+{
+ unsigned int i, j, idx = 0;
+ static const krb5_enctype etype_list[] = {
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+ ENCTYPE_DES3_CBC_SHA1,
+ ENCTYPE_ARCFOUR_HMAC,
+ ENCTYPE_DES_CBC_MD5,
+ ENCTYPE_DES_CBC_MD4,
+ ENCTYPE_DES_CBC_CRC,
+ ENCTYPE_NULL
+ };
+ size_t etype_len = ARRAY_SIZE(etype_list);
+ size_t keys_size = entry_ex->entry.keys.len;
+ struct sdb_key *keys = entry_ex->entry.keys.val;
+ struct sdb_key *sorted_keys;
+
+ sorted_keys = calloc(keys_size, sizeof(struct sdb_key));
+ if (sorted_keys == NULL) {
+ return -1;
+ }
+
+ for (i = 0; i < etype_len; i++) {
+ for (j = 0; j < keys_size; j++) {
+ const struct sdb_key skey = keys[j];
+
+ if (idx == keys_size) {
+ break;
+ }
+
+ if (KRB5_KEY_TYPE(&skey.key) == etype_list[i]) {
+ sorted_keys[idx] = skey;
+ idx++;
+ }
+ }
+ }
+
+ /* Paranoia: Something went wrong during data copy */
+ if (idx != keys_size) {
+ free(sorted_keys);
+ return -1;
+ }
+
+ free(entry_ex->entry.keys.val);
+ entry_ex->entry.keys.val = sorted_keys;
+
+ return 0;
+}
+
static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
struct samba_kdc_db_context *kdc_db_ctx,
TALLOC_CTX *mem_ctx,
entry_ex->entry.keys.val = NULL;
entry_ex->entry.keys.len = 0;
+ entry_ex->entry.kvno = 0;
+
+ 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;
+ }
+
+ 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, 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;
+ }
kvno = ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0);
if (is_rodc) {
}
if (scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
- NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
- ret = EINVAL;
- goto out;
+ if (scb.sub.num_packages != 0) {
+ NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
+ ret = EINVAL;
+ goto out;
+ }
}
for (i=0; i < scb.sub.num_packages; i++) {
if (allocated_keys == 0) {
if (kdc_db_ctx->rodc) {
/* We are on an RODC, but don't have keys for this account. Signal this to the caller */
- /* TODO: We need to call a generalised version of auth_sam_trigger_repl_secret from here */
+ auth_sam_trigger_repl_secret(kdc_db_ctx, kdc_db_ctx->msg_ctx,
+ kdc_db_ctx->ev_ctx, msg->dn);
return SDB_ERR_NOT_FOUND_HERE;
}
key.salt->type = KRB5_PW_SALT;
- ret = krb5_copy_data_contents(&key.salt->salt,
- salt.data,
- salt.length);
+ ret = smb_krb5_copy_data_contents(&key.salt->salt,
+ salt.data,
+ salt.length);
if (ret) {
free(key.salt);
key.salt = NULL;
}
if (ret) {
if (key.salt) {
- kerberos_free_data_contents(context, &key.salt->salt);
+ smb_krb5_free_data_contents(context, &key.salt->salt);
free(key.salt);
key.salt = NULL;
}
key.salt->type = KRB5_PW_SALT;
- ret = krb5_copy_data_contents(&key.salt->salt,
- salt.data,
- salt.length);
+ ret = smb_krb5_copy_data_contents(&key.salt->salt,
+ salt.data,
+ salt.length);
if (ret) {
free(key.salt);
key.salt = NULL;
&key.key);
if (ret) {
if (key.salt) {
- kerberos_free_data_contents(context, &key.salt->salt);
+ smb_krb5_free_data_contents(context, &key.salt->salt);
free(key.salt);
key.salt = NULL;
}
out:
if (ret != 0) {
entry_ex->entry.keys.len = 0;
+ } else if (entry_ex->entry.keys.len > 0 &&
+ entry_ex->entry.keys.val != NULL) {
+ ret = samba_kdc_sort_encryption_keys(entry_ex);
+ if (ret != 0) {
+ entry_ex->entry.keys.len = 0;
+ ret = ENOMEM;
+ }
}
if (entry_ex->entry.keys.len == 0 && entry_ex->entry.keys.val) {
free(entry_ex->entry.keys.val);
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;
} else {
NTTIME must_change_time
- = samdb_result_force_password_change(kdc_db_ctx->samdb, mem_ctx,
- realm_dn, msg);
+ = samdb_result_nttime(msg,
+ "msDS-UserPasswordExpiryTimeComputed",
+ 0);
if (must_change_time == 0x7FFFFFFFFFFFFFFFULL) {
entry_ex->entry.pw_end = NULL;
} else {
goto out;
}
- entry_ex->entry.etypes = malloc(sizeof(*(entry_ex->entry.etypes)));
- if (entry_ex->entry.etypes == NULL) {
- krb5_clear_error_message(context);
- ret = ENOMEM;
- goto out;
- }
- entry_ex->entry.etypes->len = entry_ex->entry.keys.len;
- entry_ex->entry.etypes->val = calloc(entry_ex->entry.etypes->len, sizeof(int));
- if (entry_ex->entry.etypes->val == NULL) {
- krb5_clear_error_message(context);
- ret = ENOMEM;
- goto out;
- }
- for (i=0; i < entry_ex->entry.etypes->len; i++) {
- entry_ex->entry.etypes->val[i] = KRB5_KEY_TYPE(&entry_ex->entry.keys.val[i].key);
- }
-
-
p->msg = talloc_steal(p, msg);
out:
ENCTYPE_AES256_CTS_HMAC_SHA1_96,
&key.key);
if (ret != 0) {
- kerberos_free_data_contents(context, &salt);
+ smb_krb5_free_data_contents(context, &salt);
goto out;
}
ENCTYPE_AES128_CTS_HMAC_SHA1_96,
&key.key);
if (ret != 0) {
- kerberos_free_data_contents(context, &salt);
+ smb_krb5_free_data_contents(context, &salt);
goto out;
}
entry_ex->entry.keys.len++;
}
- kerberos_free_data_contents(context, &salt);
+ smb_krb5_free_data_contents(context, &salt);
}
if (password_hash != NULL) {
entry_ex->entry.max_renew = NULL;
- entry_ex->entry.etypes = malloc(sizeof(*(entry_ex->entry.etypes)));
- if (entry_ex->entry.etypes == NULL) {
- krb5_clear_error_message(context);
- ret = ENOMEM;
- goto out;
- }
- entry_ex->entry.etypes->len = entry_ex->entry.keys.len;
- entry_ex->entry.etypes->val = calloc(entry_ex->entry.etypes->len, sizeof(int));
- if (entry_ex->entry.etypes->val == NULL) {
+ ret = samba_kdc_sort_encryption_keys(entry_ex);
+ if (ret != 0) {
krb5_clear_error_message(context);
ret = ENOMEM;
goto out;
}
- for (i=0; i < entry_ex->entry.etypes->len; i++) {
- entry_ex->entry.etypes->val[i] = KRB5_KEY_TYPE(&entry_ex->entry.keys.val[i].key);
- }
p->msg = talloc_steal(p, msg);
}
kdc_db_ctx->ev_ctx = base_ctx->ev_ctx;
kdc_db_ctx->lp_ctx = base_ctx->lp_ctx;
+ kdc_db_ctx->msg_ctx = base_ctx->msg_ctx;
/* get default kdc policy */
lpcfg_default_kdc_policy(base_ctx->lp_ctx,