*/
#include "includes.h"
-#include "auth/auth.h"
-#include "auth/credentials/credentials.h"
+#include "kdc/kdc-glue.h"
+#include "kdc/db-glue.h"
+#include "auth/auth_sam.h"
+#include "auth/common_auth.h"
+#include <ldb.h>
+#include "sdb.h"
+#include "sdb_hdb.h"
#include "dsdb/samdb/samdb.h"
#include "param/param.h"
-#include "kdc/kdc.h"
-#include "kdc/db-glue.h"
+#include "../lib/tsocket/tsocket.h"
static krb5_error_code hdb_samba4_open(krb5_context context, HDB *db, int flags, mode_t mode)
{
return HDB_ERR_DB_INUSE;
}
-static krb5_error_code hdb_samba4_fetch(krb5_context context, HDB *db,
- krb5_const_principal principal,
- unsigned flags,
- hdb_entry_ex *entry_ex)
+static krb5_error_code hdb_samba4_fetch_kvno(krb5_context context, HDB *db,
+ krb5_const_principal principal,
+ unsigned flags,
+ krb5_kvno kvno,
+ hdb_entry_ex *entry_ex)
{
struct samba_kdc_db_context *kdc_db_ctx;
+ struct sdb_entry_ex sdb_entry_ex = {};
+ krb5_error_code code, ret;
kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
struct samba_kdc_db_context);
- return samba_kdc_fetch(context, kdc_db_ctx, principal, flags, entry_ex);
+ ret = samba_kdc_fetch(context,
+ kdc_db_ctx,
+ principal,
+ flags,
+ kvno,
+ &sdb_entry_ex);
+ switch (ret) {
+ case 0:
+ code = 0;
+ break;
+ case SDB_ERR_WRONG_REALM:
+ /*
+ * If SDB_ERR_WRONG_REALM is returned we need to process the
+ * sdb_entry to fill the principal in the HDB entry.
+ */
+ code = HDB_ERR_WRONG_REALM;
+ break;
+ case SDB_ERR_NOENTRY:
+ return HDB_ERR_NOENTRY;
+ default:
+ return HDB_ERR_NOT_FOUND_HERE;
+ }
+
+ ret = sdb_entry_ex_to_hdb_entry_ex(context, &sdb_entry_ex, entry_ex);
+ sdb_free_entry(&sdb_entry_ex);
+
+ if (code != 0 && ret != 0) {
+ code = ret;
+ }
+
+ return code;
}
static krb5_error_code hdb_samba4_firstkey(krb5_context context, HDB *db, unsigned flags,
hdb_entry_ex *entry)
{
struct samba_kdc_db_context *kdc_db_ctx;
+ struct sdb_entry_ex sdb_entry_ex = {};
+ krb5_error_code ret;
kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
struct samba_kdc_db_context);
- return samba_kdc_firstkey(context, kdc_db_ctx, entry);
+ ret = samba_kdc_firstkey(context, kdc_db_ctx, &sdb_entry_ex);
+ switch (ret) {
+ case 0:
+ break;
+ case SDB_ERR_WRONG_REALM:
+ return HDB_ERR_WRONG_REALM;
+ case SDB_ERR_NOENTRY:
+ return HDB_ERR_NOENTRY;
+ default:
+ return HDB_ERR_NOT_FOUND_HERE;
+ }
+
+ ret = sdb_entry_ex_to_hdb_entry_ex(context, &sdb_entry_ex, entry);
+ sdb_free_entry(&sdb_entry_ex);
+ return ret;
}
static krb5_error_code hdb_samba4_nextkey(krb5_context context, HDB *db, unsigned flags,
hdb_entry_ex *entry)
{
struct samba_kdc_db_context *kdc_db_ctx;
+ struct sdb_entry_ex sdb_entry_ex = {};
+ krb5_error_code ret;
kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
struct samba_kdc_db_context);
- return samba_kdc_nextkey(context, kdc_db_ctx, entry);
+ ret = samba_kdc_nextkey(context, kdc_db_ctx, &sdb_entry_ex);
+ switch (ret) {
+ case 0:
+ break;
+ case SDB_ERR_WRONG_REALM:
+ return HDB_ERR_WRONG_REALM;
+ case SDB_ERR_NOENTRY:
+ return HDB_ERR_NOENTRY;
+ default:
+ return HDB_ERR_NOT_FOUND_HERE;
+ }
+
+ ret = sdb_entry_ex_to_hdb_entry_ex(context, &sdb_entry_ex, entry);
+ sdb_free_entry(&sdb_entry_ex);
+ return ret;
}
static krb5_error_code hdb_samba4_destroy(krb5_context context, HDB *db)
{
- struct samba_kdc_db_context *kdc_db_ctx;
-
- kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
- struct samba_kdc_db_context);
-
- if (kdc_db_ctx) {
- talloc_free(kdc_db_ctx->samdb);
- kdc_db_ctx->samdb = NULL;
- }
-
talloc_free(db);
return 0;
}
krb5_const_principal target_principal)
{
struct samba_kdc_db_context *kdc_db_ctx;
+ struct samba_kdc_entry *skdc_entry;
+ krb5_error_code ret;
kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
struct samba_kdc_db_context);
+ skdc_entry = talloc_get_type_abort(entry->ctx,
+ struct samba_kdc_entry);
+
+ ret = samba_kdc_check_s4u2proxy(context, kdc_db_ctx,
+ skdc_entry,
+ target_principal);
+ switch (ret) {
+ case 0:
+ break;
+ case SDB_ERR_WRONG_REALM:
+ ret = HDB_ERR_WRONG_REALM;
+ break;
+ case SDB_ERR_NOENTRY:
+ ret = HDB_ERR_NOENTRY;
+ break;
+ default:
+ ret = HDB_ERR_NOT_FOUND_HERE;
+ break;
+ }
- return samba_kdc_check_constrained_delegation(context, kdc_db_ctx,
- entry,
- target_principal);
+ return ret;
}
static krb5_error_code
krb5_const_principal certificate_principal)
{
struct samba_kdc_db_context *kdc_db_ctx;
+ struct samba_kdc_entry *skdc_entry;
+ krb5_error_code ret;
+
+ kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
+ struct samba_kdc_db_context);
+ skdc_entry = talloc_get_type_abort(entry->ctx,
+ struct samba_kdc_entry);
+
+ ret = samba_kdc_check_pkinit_ms_upn_match(context, kdc_db_ctx,
+ skdc_entry,
+ certificate_principal);
+ switch (ret) {
+ case 0:
+ break;
+ case SDB_ERR_WRONG_REALM:
+ ret = HDB_ERR_WRONG_REALM;
+ break;
+ case SDB_ERR_NOENTRY:
+ ret = HDB_ERR_NOENTRY;
+ break;
+ default:
+ ret = HDB_ERR_NOT_FOUND_HERE;
+ break;
+ }
+
+ return ret;
+}
+
+static krb5_error_code
+hdb_samba4_check_s4u2self(krb5_context context, HDB *db,
+ hdb_entry_ex *entry,
+ krb5_const_principal target_principal)
+{
+ struct samba_kdc_db_context *kdc_db_ctx;
+ struct samba_kdc_entry *skdc_entry;
+ krb5_error_code ret;
kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
struct samba_kdc_db_context);
+ skdc_entry = talloc_get_type_abort(entry->ctx,
+ struct samba_kdc_entry);
+
+ ret = samba_kdc_check_s4u2self(context, kdc_db_ctx,
+ skdc_entry,
+ target_principal);
+ switch (ret) {
+ case 0:
+ break;
+ case SDB_ERR_WRONG_REALM:
+ ret = HDB_ERR_WRONG_REALM;
+ break;
+ case SDB_ERR_NOENTRY:
+ ret = HDB_ERR_NOENTRY;
+ break;
+ default:
+ ret = HDB_ERR_NOT_FOUND_HERE;
+ break;
+ }
+
+ return ret;
+}
- return samba_kdc_check_pkinit_ms_upn_match(context, kdc_db_ctx,
- entry,
- certificate_principal);
+static krb5_error_code hdb_samba4_auth_status(krb5_context context, HDB *db,
+ hdb_entry_ex *entry,
+ struct sockaddr *from_addr,
+ const char *original_client_name,
+ const char *auth_type,
+ int hdb_auth_status)
+{
+ struct samba_kdc_db_context *kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
+ struct samba_kdc_db_context);
+
+ struct ldb_dn *domain_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
+
+ /*
+ * Forcing this via the NTLM auth structure is not ideal, but
+ * it is the most practical option right now, and ensures the
+ * logs are consistent, even if some elements are always NULL.
+ */
+ struct auth_usersupplied_info ui = {
+ .mapped_state = true,
+ .was_mapped = true,
+ .client = {
+ .account_name = original_client_name,
+ .domain_name = NULL,
+ },
+ .service_description = "Kerberos KDC",
+ .auth_description = "ENC-TS Pre-authentication",
+ .password_type = auth_type
+ };
+
+ size_t sa_socklen = 0;
+
+ switch (from_addr->sa_family) {
+ case AF_INET:
+ sa_socklen = sizeof(struct sockaddr_in);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ sa_socklen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ }
+
+ switch (hdb_auth_status) {
+ case HDB_AUTHZ_SUCCESS:
+ {
+ struct samba_kdc_entry *p = talloc_get_type(entry->ctx,
+ struct samba_kdc_entry);
+
+ /*
+ * TODO: We could log the AS-REQ authorization success here as
+ * well. However before we do that, we need to pass
+ * in the PAC here or re-calculate it.
+ */
+ authsam_logon_success_accounting(kdc_db_ctx->samdb, p->msg,
+ domain_dn, true);
+ break;
+ }
+ case HDB_AUTH_INVALID_SIGNATURE:
+ break;
+ case HDB_AUTH_CORRECT_PASSWORD:
+ case HDB_AUTH_WRONG_PASSWORD:
+ {
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samba_kdc_entry *p = talloc_get_type(entry->ctx,
+ struct samba_kdc_entry);
+ struct dom_sid *sid
+ = samdb_result_dom_sid(frame, p->msg, "objectSid");
+ const char *account_name
+ = ldb_msg_find_attr_as_string(p->msg, "sAMAccountName", NULL);
+ const char *domain_name = lpcfg_sam_name(p->kdc_db_ctx->lp_ctx);
+ struct tsocket_address *remote_host;
+ NTSTATUS status;
+ int ret;
+
+ if (hdb_auth_status == HDB_AUTH_WRONG_PASSWORD) {
+ authsam_update_bad_pwd_count(kdc_db_ctx->samdb, p->msg, domain_dn);
+ status = NT_STATUS_WRONG_PASSWORD;
+ } else {
+ status = NT_STATUS_OK;
+ }
+
+ ret = tsocket_address_bsd_from_sockaddr(frame, from_addr,
+ sa_socklen,
+ &remote_host);
+ if (ret != 0) {
+ ui.remote_host = NULL;
+ } else {
+ ui.remote_host = remote_host;
+ }
+
+ ui.mapped.account_name = account_name;
+ ui.mapped.domain_name = domain_name;
+
+ log_authentication_event(kdc_db_ctx->msg_ctx,
+ kdc_db_ctx->lp_ctx,
+ &ui,
+ status,
+ domain_name,
+ account_name,
+ NULL,
+ sid);
+ TALLOC_FREE(frame);
+ break;
+ }
+ case HDB_AUTH_CLIENT_UNKNOWN:
+ {
+ struct tsocket_address *remote_host;
+ int ret;
+ TALLOC_CTX *frame = talloc_stackframe();
+ ret = tsocket_address_bsd_from_sockaddr(frame, from_addr,
+ sa_socklen,
+ &remote_host);
+ if (ret != 0) {
+ ui.remote_host = NULL;
+ } else {
+ ui.remote_host = remote_host;
+ }
+
+ log_authentication_event(kdc_db_ctx->msg_ctx,
+ kdc_db_ctx->lp_ctx,
+ &ui,
+ NT_STATUS_NO_SUCH_USER,
+ NULL, NULL,
+ NULL, NULL);
+ TALLOC_FREE(frame);
+ break;
+ }
+ }
+ return 0;
}
/* This interface is to be called by the KDC and libnet_keytab_dump,
krb5_context context, struct HDB **db)
{
struct samba_kdc_db_context *kdc_db_ctx;
- struct auth_session_info *session_info;
NTSTATUS nt_status;
+ if (hdb_interface_version != HDB_INTERFACE_VERSION) {
+ krb5_set_error_message(context, EINVAL, "Heimdal HDB interface version mismatch between build-time and run-time libraries!");
+ return NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION;
+ }
+
*db = talloc(base_ctx, HDB);
if (!*db) {
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
(*db)->hdb_master_key_set = 0;
(*db)->hdb_db = NULL;
- (*db)->hdb_capability_flags = 0;
-
-#if 1
- /* we would prefer to use system_session(), as that would
- * allow us to share the samdb backend context with other parts of the
- * system. For now we can't as we need to override the
- * credentials to set CRED_DONT_USE_KERBEROS, which would
- * break other users of the system_session */
- DEBUG(0,("FIXME: Using new system session for hdb\n"));
- nt_status = auth_system_session_info(*db, base_ctx->lp_ctx, &session_info);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-#else
- session_info = system_session(kdc_db_ctx->lp_ctx);
- if (session_info == NULL) {
- return NT_STATUS_INTERNAL_ERROR;
- }
-#endif
-
- /* The idea here is very simple. Using Kerberos to
- * authenticate the KDC to the LDAP server is higly likely to
- * be circular.
- *
- * In future we may set this up to use EXERNAL and SSL
- * certificates, for now it will almost certainly be NTLMSSP_SET_USERNAME
- */
+ (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL;
- cli_credentials_set_kerberos_state(session_info->credentials,
- CRED_DONT_USE_KERBEROS);
-
- kdc_db_ctx = talloc_zero(*db, struct samba_kdc_db_context);
- if (kdc_db_ctx == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- kdc_db_ctx->ev_ctx = base_ctx->ev_ctx;
- kdc_db_ctx->lp_ctx = base_ctx->lp_ctx;
- kdc_db_ctx->ic_ctx = lp_iconv_convenience(base_ctx->lp_ctx);
-
- /* Setup the link to LDB */
- kdc_db_ctx->samdb = samdb_connect(kdc_db_ctx, base_ctx->ev_ctx,
- base_ctx->lp_ctx, session_info);
- if (kdc_db_ctx->samdb == NULL) {
- DEBUG(1, ("hdb_samba4_create: Cannot open samdb for KDC backend!"));
- return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ nt_status = samba_kdc_setup_db_ctx(*db, base_ctx, &kdc_db_ctx);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(*db);
+ return nt_status;
}
-
(*db)->hdb_db = kdc_db_ctx;
(*db)->hdb_dbc = NULL;
(*db)->hdb_open = hdb_samba4_open;
(*db)->hdb_close = hdb_samba4_close;
- (*db)->hdb_fetch = hdb_samba4_fetch;
+ (*db)->hdb_fetch_kvno = hdb_samba4_fetch_kvno;
(*db)->hdb_store = hdb_samba4_store;
(*db)->hdb_remove = hdb_samba4_remove;
(*db)->hdb_firstkey = hdb_samba4_firstkey;
(*db)->hdb__del = NULL;
(*db)->hdb_destroy = hdb_samba4_destroy;
- (*db)->hdb_auth_status = NULL;
+ (*db)->hdb_auth_status = hdb_samba4_auth_status;
(*db)->hdb_check_constrained_delegation = hdb_samba4_check_constrained_delegation;
(*db)->hdb_check_pkinit_ms_upn_match = hdb_samba4_check_pkinit_ms_upn_match;
+ (*db)->hdb_check_s4u2self = hdb_samba4_check_s4u2self;
return NT_STATUS_OK;
}
-
-static krb5_error_code hdb_samba4_create(krb5_context context, struct HDB **db, const char *arg)
-{
- NTSTATUS nt_status;
- void *ptr;
- struct samba_kdc_base_context *base_ctx;
-
- if (sscanf(arg, "&%p", &ptr) != 1) {
- return EINVAL;
- }
- base_ctx = talloc_get_type_abort(ptr, struct samba_kdc_base_context);
- /* The global kdc_mem_ctx and kdc_lp_ctx, Disgusting, ugly hack, but it means one less private hook */
- nt_status = hdb_samba4_create_kdc(base_ctx, context, db);
-
- if (NT_STATUS_IS_OK(nt_status)) {
- return 0;
- }
- return EINVAL;
-}
-
-/* Only used in the hdb-backed keytab code
- * for a keytab of 'samba4&<address>', to find
- * kpasswd's key in the main DB, and to
- * copy all the keys into a file (libnet_keytab_export)
- *
- * The <address> is the string form of a pointer to a talloced struct hdb_samba_context
- */
-struct hdb_method hdb_samba4 = {
- .interface_version = HDB_INTERFACE_VERSION,
- .prefix = "samba4",
- .create = hdb_samba4_create
-};