* [PATCH 1/2] ksmbd: pass through NTLM authentication to a domain controller
2026-10-18 17:53 [PATCH 0/2] ksmbd: NTLM pass-through to a domain controller Jan Koester
@ 2026-10-18 17:53 ` Jan Koester
2026-10-19 1:48 ` Namjae Jeon
2026-10-18 17:53 ` [PATCH 2/2] ksmbd: put the workgroup into the NTLMSSP target info's domain names Jan Koester
2026-10-19 1:31 ` [PATCH 0/2] ksmbd: NTLM pass-through to a domain controller Namjae Jeon
2 siblings, 1 reply; 6+ messages in thread
From: Jan Koester @ 2026-10-18 17:53 UTC (permalink / raw)
To: Namjae Jeon, Steve French
Cc: Sergey Senozhatsky, Tom Talpey, ChenXiaoSong, linux-cifs,
samba-technical, linux-kernel
A ksmbd server that is a member of an Active Directory domain cannot
check the NTLM response of a domain user on its own: it has no password
hash for that user. Add a way to defer the check to user space, which
can ask a domain controller over NETLOGON (NetrLogonSamLogonEx).
When the login response for a user carries the new
KSMBD_USER_FLAG_PASSTHROUGH flag, ksmbd no longer computes the NTLMv2
response from a local hash. Instead ksmbd_decode_ntlmssp_auth_blob()
hands the server challenge and the client's user name, domain name,
workstation and NT/LM responses to user space through the new
KSMBD_EVENT_NTLM_AUTHEN_REQUEST event and takes the session base key
from the KSMBD_EVENT_NTLM_AUTHEN_RESPONSE, then continues with the
existing key-exchange path.
The two new events get a strict netlink policy and are validated in
ipc_validate_msg(); ksmbd_nl_init_fixup() keeps strict validation for
commands at or after resv_start_op so the new fixed-size response is
checked.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Jan Koester <jan.koester@gmx.net>
---
fs/smb/server/auth.c | 68 ++++++++++++++++++++++++++++++++
fs/smb/server/ksmbd_netlink.h | 41 ++++++++++++++++++++
fs/smb/server/transport_ipc.c | 73 ++++++++++++++++++++++++++++++++++-
fs/smb/server/transport_ipc.h | 3 ++
4 files changed, 183 insertions(+), 2 deletions(-)
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index 1b24eb3f39..9a2a3c6a37 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -79,6 +79,16 @@ static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess,
__le16 *uniname = NULL;
struct hmac_md5_ctx ctx;
+ /*
+ * A pass-through user (KSMBD_USER_FLAG_PASSTHROUGH) has no local
+ * password hash and must never reach the NTLMv2 code -- it is handled
+ * in ksmbd_decode_ntlmssp_auth_blob() instead. Guard against a NULL
+ * passkey anyway so a user space that sets KSMBD_USER_FLAG_OK without a
+ * hash can only fail the login, not crash the kernel.
+ */
+ if (!user_passkey(sess->user))
+ return -EINVAL;
+
hmac_md5_init_usingrawkey(&ctx, user_passkey(sess->user),
CIFS_ENCPWD_SIZE);
@@ -184,6 +194,55 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
return rc;
}
+/**
+ * ksmbd_auth_ntlm_passthrough() - NTLM authentication by user space
+ * @conn: connection
+ * @authblob: authenticate blob
+ * @blob_len: length of @authblob
+ * @sess_key: session base key output buffer
+ *
+ * For a user that user space has no password hash for (a domain user): it
+ * checks the response, e.g. with a domain controller, and returns the
+ * session base key.
+ *
+ * Return: 0 on success, error number on error
+ */
+static int ksmbd_auth_ntlm_passthrough(struct ksmbd_conn *conn,
+ struct authenticate_message *authblob,
+ int blob_len, char *sess_key)
+{
+ const struct security_buffer *bufs[5] = {
+ &authblob->UserName, &authblob->DomainName,
+ &authblob->WorkstationName, &authblob->NtChallengeResponse,
+ &authblob->LmChallengeResponse,
+ };
+ struct ksmbd_ntlm_authen_response *resp;
+ const char *parts[5];
+ unsigned short lens[5];
+ int i, rc;
+
+ for (i = 0; i < 5; i++) {
+ unsigned int off = le32_to_cpu(bufs[i]->BufferOffset);
+
+ lens[i] = le16_to_cpu(bufs[i]->Length);
+ if (blob_len < (u64)off + lens[i])
+ return -EINVAL;
+ parts[i] = (const char *)authblob + off;
+ }
+
+ resp = ksmbd_ipc_ntlm_authen_request(conn->ntlmssp.cryptkey, parts,
+ lens);
+ if (!resp)
+ return -EINVAL;
+
+ rc = resp->status & KSMBD_USER_FLAG_OK ? 0 : -EINVAL;
+ if (!rc)
+ memcpy(sess_key, resp->session_key, SMB2_NTLMV2_SESSKEY_SIZE);
+ memzero_explicit(resp->session_key, sizeof(resp->session_key));
+ kvfree(resp);
+ return rc;
+}
+
/**
* ksmbd_decode_ntlmssp_auth_blob() - helper function to construct
* authenticate blob
@@ -225,6 +284,14 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
nt_len < CIFS_ENCPWD_SIZE)
return -EINVAL;
+ if (test_user_flag(sess->user, KSMBD_USER_FLAG_PASSTHROUGH)) {
+ ret = ksmbd_auth_ntlm_passthrough(conn, authblob, blob_len,
+ sess_key);
+ if (ret)
+ return ret;
+ goto key_exchange;
+ }
+
/* TODO : use domain name that imported from configuration file */
domain_name = smb_strndup_from_utf16((const char *)authblob + dn_off,
dn_len, true, conn->local_nls);
@@ -242,6 +309,7 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
if (ret)
return ret;
+key_exchange:
/* The recovered secondary session key */
if (conn->ntlmssp.client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) {
struct arc4_ctx *ctx_arc4;
diff --git a/fs/smb/server/ksmbd_netlink.h b/fs/smb/server/ksmbd_netlink.h
index 2673522c76..7438e0b0ba 100644
--- a/fs/smb/server/ksmbd_netlink.h
+++ b/fs/smb/server/ksmbd_netlink.h
@@ -54,6 +54,11 @@
*
* - KSMBD_EVENT_LOGIN_REQUEST_EXT/RESPONSE_EXT(ksmbd_login_request_ext/response_ext)
* This event is to get user account extension info to user IPC daemon.
+ *
+ * - KSMBD_EVENT_NTLM_AUTHEN_REQUEST/RESPONSE(ksmbd_ntlm_authen_request/response)
+ * This event is to make NTLM authentication of a user the login response
+ * marked KSMBD_USER_FLAG_PASSTHROUGH to be processed in userspace, e.g.
+ * by a domain controller.
*/
#define KSMBD_GENL_NAME "SMBD_GENL"
@@ -161,6 +166,38 @@ struct ksmbd_login_response_ext {
__s8 ____payload[];
};
+/*
+ * IPC request to check the NTLM response of a user whose login response
+ * had KSMBD_USER_FLAG_PASSTHROUGH: user space has no password hash for it
+ * and asks someone who has, e.g. a domain controller (NETLOGON).
+ */
+struct ksmbd_ntlm_authen_request {
+ __u32 handle;
+ __u8 challenge[8]; /* the server challenge */
+ __u16 user_name_len; /* lengths of the payload parts */
+ __u16 domain_name_len;
+ __u16 workstation_len;
+ __u16 nt_response_len;
+ __u16 lm_response_len;
+ __u16 reserved16;
+ __u32 reserved[16]; /* Reserved room */
+ __u8 payload[]; /*
+ * user name, domain name, workstation
+ * (UTF-16LE, as the client sent them),
+ * NT response, LM response
+ */
+};
+
+/*
+ * IPC response to an NTLM authentication request
+ */
+struct ksmbd_ntlm_authen_response {
+ __u32 handle;
+ __u32 status; /* KSMBD_USER_FLAG_OK or _BAD_PASSWORD */
+ __u8 session_key[16]; /* the session base key */
+ __u32 reserved[16]; /* Reserved room */
+};
+
/*
* IPC request to fetch net share config.
*/
@@ -326,6 +363,9 @@ enum ksmbd_event {
KSMBD_EVENT_LOGIN_REQUEST_EXT,
KSMBD_EVENT_LOGIN_RESPONSE_EXT,
+ KSMBD_EVENT_NTLM_AUTHEN_REQUEST,
+ KSMBD_EVENT_NTLM_AUTHEN_RESPONSE,
+
__KSMBD_EVENT_MAX,
KSMBD_EVENT_MAX = __KSMBD_EVENT_MAX - 1
};
@@ -357,6 +397,7 @@ enum KSMBD_TREE_CONN_STATUS {
#define KSMBD_USER_FLAG_GUEST_ACCOUNT BIT(4)
#define KSMBD_USER_FLAG_DELAY_SESSION BIT(5)
#define KSMBD_USER_FLAG_EXTENSION BIT(6)
+#define KSMBD_USER_FLAG_PASSTHROUGH BIT(7)
/*
* Share config flags.
diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c
index e550aa41ad..578a22dbff 100644
--- a/fs/smb/server/transport_ipc.c
+++ b/fs/smb/server/transport_ipc.c
@@ -127,6 +127,10 @@ static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = {
[KSMBD_EVENT_LOGIN_RESPONSE_EXT] = {
.len = sizeof(struct ksmbd_login_response_ext),
},
+ [KSMBD_EVENT_NTLM_AUTHEN_REQUEST] =
+ NLA_POLICY_MIN_LEN(sizeof(struct ksmbd_ntlm_authen_request)),
+ [KSMBD_EVENT_NTLM_AUTHEN_RESPONSE] =
+ NLA_POLICY_EXACT_LEN(sizeof(struct ksmbd_ntlm_authen_response)),
};
static struct genl_ops ksmbd_genl_ops[] = {
@@ -202,6 +206,14 @@ static struct genl_ops ksmbd_genl_ops[] = {
.cmd = KSMBD_EVENT_LOGIN_RESPONSE_EXT,
.doit = handle_generic_event,
},
+ {
+ .cmd = KSMBD_EVENT_NTLM_AUTHEN_REQUEST,
+ .doit = handle_unsupported_event,
+ },
+ {
+ .cmd = KSMBD_EVENT_NTLM_AUTHEN_RESPONSE,
+ .doit = handle_generic_event,
+ },
};
static struct genl_family ksmbd_genl_family = {
@@ -220,9 +232,11 @@ static void ksmbd_nl_init_fixup(void)
{
int i;
+ /* the commands from resv_start_op on are validated strictly */
for (i = 0; i < ARRAY_SIZE(ksmbd_genl_ops); i++)
- ksmbd_genl_ops[i].validate = GENL_DONT_VALIDATE_STRICT |
- GENL_DONT_VALIDATE_DUMP;
+ if (ksmbd_genl_ops[i].cmd < ksmbd_genl_family.resv_start_op)
+ ksmbd_genl_ops[i].validate = GENL_DONT_VALIDATE_STRICT |
+ GENL_DONT_VALIDATE_DUMP;
ksmbd_genl_family.policy = ksmbd_nl_policy;
}
@@ -549,6 +563,10 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
return -EINVAL;
break;
}
+ case KSMBD_EVENT_NTLM_AUTHEN_REQUEST:
+ if (entry->msg_sz != sizeof(struct ksmbd_ntlm_authen_response))
+ return -EINVAL;
+ break;
case KSMBD_EVENT_LOGIN_REQUEST_EXT:
{
struct ksmbd_login_response_ext *resp = entry->response;
@@ -702,6 +720,57 @@ ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len)
return resp;
}
+/**
+ * ksmbd_ipc_ntlm_authen_request() - have user space check an NTLM response
+ * @challenge: the server challenge (CIFS_CRYPTO_KEY_SIZE bytes)
+ * @parts: user name, domain name, workstation (UTF-16LE),
+ * NT response, LM response
+ * @lens: their lengths
+ *
+ * For a user whose login response had KSMBD_USER_FLAG_PASSTHROUGH.
+ *
+ * Return: the response (kvfree() it), NULL on error
+ */
+struct ksmbd_ntlm_authen_response *
+ksmbd_ipc_ntlm_authen_request(const char *challenge, const char *parts[5],
+ const unsigned short lens[5])
+{
+ struct ksmbd_ipc_msg *msg;
+ struct ksmbd_ntlm_authen_request *req;
+ struct ksmbd_ntlm_authen_response *resp;
+ size_t payload_sz = 0, off = 0;
+ int i;
+
+ for (i = 0; i < 5; i++)
+ payload_sz += lens[i];
+ if (payload_sz > KSMBD_IPC_MAX_PAYLOAD)
+ return NULL;
+
+ msg = ipc_msg_alloc(sizeof(struct ksmbd_ntlm_authen_request) +
+ payload_sz);
+ if (!msg)
+ return NULL;
+
+ msg->type = KSMBD_EVENT_NTLM_AUTHEN_REQUEST;
+ req = (struct ksmbd_ntlm_authen_request *)msg->payload;
+ req->handle = ksmbd_acquire_id(&ipc_ida);
+ memcpy(req->challenge, challenge, sizeof(req->challenge));
+ req->user_name_len = lens[0];
+ req->domain_name_len = lens[1];
+ req->workstation_len = lens[2];
+ req->nt_response_len = lens[3];
+ req->lm_response_len = lens[4];
+ for (i = 0; i < 5; i++) {
+ memcpy(req->payload + off, parts[i], lens[i]);
+ off += lens[i];
+ }
+
+ resp = ipc_msg_send_request(msg, req->handle);
+ ipc_msg_handle_free(req->handle);
+ ipc_msg_free(msg);
+ return resp;
+}
+
struct ksmbd_tree_connect_response *
ksmbd_ipc_tree_connect_request(struct ksmbd_session *sess,
struct ksmbd_share_config *share,
diff --git a/fs/smb/server/transport_ipc.h b/fs/smb/server/transport_ipc.h
index e51850f142..f957a33ae3 100644
--- a/fs/smb/server/transport_ipc.h
+++ b/fs/smb/server/transport_ipc.h
@@ -32,6 +32,9 @@ struct ksmbd_share_config_response *
ksmbd_ipc_share_config_request(const char *name);
struct ksmbd_spnego_authen_response *
ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len);
+struct ksmbd_ntlm_authen_response *
+ksmbd_ipc_ntlm_authen_request(const char *challenge, const char *parts[5],
+ const unsigned short lens[5]);
int ksmbd_ipc_id_alloc(void);
void ksmbd_rpc_id_free(int handle);
struct ksmbd_rpc_command *ksmbd_rpc_open(struct ksmbd_session *sess, int handle);
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 2/2] ksmbd: put the workgroup into the NTLMSSP target info's domain names
2026-10-18 17:53 [PATCH 0/2] ksmbd: NTLM pass-through to a domain controller Jan Koester
2026-10-18 17:53 ` [PATCH 1/2] ksmbd: pass through NTLM authentication " Jan Koester
@ 2026-10-18 17:53 ` Jan Koester
2026-10-19 2:00 ` Namjae Jeon
2026-10-19 1:31 ` [PATCH 0/2] ksmbd: NTLM pass-through to a domain controller Namjae Jeon
2 siblings, 1 reply; 6+ messages in thread
From: Jan Koester @ 2026-10-18 17:53 UTC (permalink / raw)
To: Namjae Jeon, Steve French
Cc: Sergey Senozhatsky, Tom Talpey, ChenXiaoSong, linux-cifs,
samba-technical, linux-kernel
ksmbd_build_ntlmssp_challenge_blob() writes the netbios name into all
four AV pairs of the challenge's target info, the domain names
(MsvAvNbDomainName, MsvAvDnsDomainName) included. The client copies
them into its NTLMv2 response.
With NTLM pass-through, a domain controller verifies that response over
NETLOGON, and Samba (NTLMv2_RESPONSE_verify_workstation()) refuses it
with NT_STATUS_LOGON_FAILURE unless MsvAvNbComputerName is the secure
channel's computer account and MsvAvNbDomainName its workgroup. Every
pass-through login of a domain user then fails.
Put the workgroup into the two domain names. Size the challenge blob
from both names in one helper, ntlmssp_challenge_size(), and check that
the blob fits into the response buffer when it is built in place
without SPNEGO: the workgroup may be longer than the netbios name.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Jan Koester <jan.koester@gmx.net>
---
fs/smb/server/auth.c | 41 ++++++++++++++++++++++++++++++++++-------
fs/smb/server/smb2pdu.c | 21 +++++++++++++++++++--
2 files changed, 53 insertions(+), 9 deletions(-)
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index 9a2a3c6a37..8639997080 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -376,10 +376,10 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
struct ksmbd_conn *conn)
{
struct target_info *tinfo;
- wchar_t *name;
+ wchar_t *name, *domain;
__u8 *target_name;
unsigned int flags, blob_off, blob_len, type, target_info_len = 0;
- int len, uni_len, conv_len;
+ int len, uni_len, dom_len, conv_len;
int cflags = conn->ntlmssp.client_flags;
memcpy(chgblob->Signature, NTLMSSP_SIGNATURE, 8);
@@ -426,6 +426,23 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
uni_len = UNICODE_LEN(conv_len);
+ len = strlen(ksmbd_work_group());
+ domain = kmalloc(2 + UNICODE_LEN(len), KSMBD_DEFAULT_GFP);
+ if (!domain) {
+ kfree(name);
+ return -ENOMEM;
+ }
+
+ conv_len = smb_strtoUTF16((__le16 *)domain, ksmbd_work_group(), len,
+ conn->local_nls);
+ if (conv_len < 0 || conv_len > len) {
+ kfree(domain);
+ kfree(name);
+ return -EINVAL;
+ }
+
+ dom_len = UNICODE_LEN(conv_len);
+
blob_off = sizeof(struct challenge_message);
blob_len = blob_off + uni_len;
@@ -446,14 +463,23 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
tinfo = (struct target_info *)(target_name + uni_len);
chgblob->TargetInfoArray.Length = 0;
- /* Add target info list for NetBIOS/DNS settings */
+ /*
+ * Add target info list for NetBIOS/DNS settings: the computer names
+ * are the netbios name, the domain names the workgroup. A domain
+ * controller checks the latter when it is asked to verify the
+ * NTLMv2 response of a domain user (NETLOGON pass-through).
+ */
for (type = NTLMSSP_AV_NB_COMPUTER_NAME;
type <= NTLMSSP_AV_DNS_DOMAIN_NAME; type++) {
+ bool is_domain = type == NTLMSSP_AV_NB_DOMAIN_NAME ||
+ type == NTLMSSP_AV_DNS_DOMAIN_NAME;
+ int av_len = is_domain ? dom_len : uni_len;
+
tinfo->Type = cpu_to_le16(type);
- tinfo->Length = cpu_to_le16(uni_len);
- memcpy(tinfo->Content, name, uni_len);
- tinfo = (struct target_info *)((char *)tinfo + 4 + uni_len);
- target_info_len += 4 + uni_len;
+ tinfo->Length = cpu_to_le16(av_len);
+ memcpy(tinfo->Content, is_domain ? domain : name, av_len);
+ tinfo = (struct target_info *)((char *)tinfo + 4 + av_len);
+ target_info_len += 4 + av_len;
}
/* Add terminator subblock */
@@ -464,6 +490,7 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
chgblob->TargetInfoArray.Length = cpu_to_le16(target_info_len);
chgblob->TargetInfoArray.MaximumLength = cpu_to_le16(target_info_len);
blob_len += target_info_len;
+ kfree(domain);
kfree(name);
ksmbd_debug(AUTH, "NTLMSSP SecurityBufferLength %d\n", blob_len);
return blob_len;
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 6b8809f67b..704c694fe7 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -1822,6 +1822,20 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
return status;
}
+/*
+ * ntlmssp_challenge_size() - room for the challenge blob: the netbios name as
+ * target name and the two computer names, the workgroup as the two domain
+ * names (UTF-16, each with its 4-byte AV pair header), the terminator
+ */
+static size_t ntlmssp_challenge_size(void)
+{
+ size_t nb = strlen(ksmbd_netbios_name()) * 2;
+ size_t wg = strlen(ksmbd_work_group()) * 2;
+
+ return sizeof(struct challenge_message) + nb + 2 * (4 + nb) +
+ 2 * (4 + wg) + 4;
+}
+
/**
* smb2_handle_negotiate() - handler for smb2 negotiate command
* @work: smb work containing smb request buffer
@@ -2096,6 +2110,10 @@ static int ntlm_negotiate(struct ksmbd_work *work,
memset(chgblob, 0, sizeof(struct challenge_message));
if (!work->conn->use_spnego) {
+ if ((char *)rsp->Buffer + ntlmssp_challenge_size() >
+ (char *)work->response_buf + work->response_sz)
+ return -EINVAL;
+
sz = ksmbd_build_ntlmssp_challenge_blob(chgblob, work->conn);
if (sz < 0)
return -ENOMEM;
@@ -2104,8 +2122,7 @@ static int ntlm_negotiate(struct ksmbd_work *work,
return 0;
}
- sz = sizeof(struct challenge_message);
- sz += (strlen(ksmbd_netbios_name()) * 2 + 1 + 4) * 6;
+ sz = ntlmssp_challenge_size();
neg_blob = kzalloc(sz, KSMBD_DEFAULT_GFP);
if (!neg_blob)
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH 0/2] ksmbd: NTLM pass-through to a domain controller
2026-10-18 17:53 [PATCH 0/2] ksmbd: NTLM pass-through to a domain controller Jan Koester
2026-10-18 17:53 ` [PATCH 1/2] ksmbd: pass through NTLM authentication " Jan Koester
2026-10-18 17:53 ` [PATCH 2/2] ksmbd: put the workgroup into the NTLMSSP target info's domain names Jan Koester
@ 2026-10-19 1:31 ` Namjae Jeon
2 siblings, 0 replies; 6+ messages in thread
From: Namjae Jeon @ 2026-10-19 1:31 UTC (permalink / raw)
To: Jan Koester
Cc: Steve French, Sergey Senozhatsky, Tom Talpey, ChenXiaoSong,
linux-cifs, samba-technical, linux-kernel, wang zhaolong,
Wang Zhaolong
On Mon, Oct 19, 2026 at 2:53 AM Jan Koester <jan.koester@gmx.net> wrote:
>
> Hi,
>
> a ksmbd server joined to an Active Directory domain can authenticate
> domain users with Kerberos, but not with NTLM: it has no password hash
> for them, so the NTLMv2 response can't be checked locally. Clients that
> fall back to NTLM (access by IP address, machines outside the domain,
> mount.cifs with user name and password) are refused.
>
> Samba solves this by forwarding the response to a domain controller
> over NETLOGON (NetrLogonSamLogonEx on a schannel connection). These two
> patches give ksmbd the kernel half of that, and leave the NETLOGON client
> to user space, like the rest of ksmbd's user handling:
>
> 1/2 adds a KSMBD_USER_FLAG_PASSTHROUGH login flag. For such a user,
> ksmbd_decode_ntlmssp_auth_blob() doesn't compute the response from a
> local hash. It sends the server challenge, the user, domain and
> workstation names and the NT/LM responses to user space in a new
> KSMBD_EVENT_NTLM_AUTHEN_REQUEST event, then takes the session base
> key from KSMBD_EVENT_NTLM_AUTHEN_RESPONSE and goes on with the
> existing key exchange. Both events have a strict netlink policy and
> are checked in ipc_validate_msg().
>
> 2/2 puts the workgroup, not the netbios name, into MsvAvNbDomainName and
> MsvAvDnsDomainName of the challenge's target info. A domain
> controller checks these when it verifies the NTLMv2 response (Samba
> in NTLMv2_RESPONSE_verify_workstation()), so without this patch
> every pass-through login fails with NT_STATUS_LOGON_FAILURE. The
> patch also checks that the challenge blob fits the response buffer,
> since the workgroup can be longer than the netbios name.
>
> Logins of users without the new flag are checked as before. The only
> change they see is the domain names in the challenge's target info
> (patch 2/2). ksmbd-tools doesn't set the flag yet. The user space side
> we tested with is sharedd/adconnect from FenrirOS: it marks domain users
> without a local hash as pass-through, and it answers the event through
> a NETLOGON schannel client, tested against a Samba 4.22 AD DC.
>
> I can send the matching ksmbd-tools change if the interface looks
> acceptable.
Okay, Please send a PR to ksmbd-tools. Wang is also currently
implementing AD/DC features in ksmbd and might be interested, so I'm
adding him to CC.
Thanks for the patches!
^ permalink raw reply [flat|nested] 6+ messages in thread