[RFC PATCH 5/6] ksmbd: show classic users as S-1-22-1-<uid> on every server

From: Jan Koester

Date: Wed Oct 28 2026 - 02:21:28 EST


A classic uid appeared in security descriptors as the server's own
domain SID + uid. That domain SID comes from user space and differs from
server to server (ksmbd-tools and sharedd derive it per machine), so
the same owner had a different SID on every file server, and the RID
looked like a domain account's.

Show them as S-1-22-1-<uid>, the SID ksmbd already used for root and
that S-1-22-2-<gid> pairs with for groups. Keep taking the old form when
a client sets it, and keep it in the session's SIDs, so descriptors
stored before still match.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Jan Koester <jan.koester@xxxxxxxxx>
---
fs/smb/server/smbacl.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
index d6be65e3a9..769864d64e 100644
--- a/fs/smb/server/smbacl.c
+++ b/fs/smb/server/smbacl.c
@@ -300,14 +300,16 @@ static u32 sid_to_id_r(const struct smb_sid *psid, u8 *id)
}

/*
- * The SID ksmbd itself gives an id: a classic one the usual SIDs, a UUID
- * or GUID S-1-22-<kind>-w0-w1-w2-w3.
+ * The SID ksmbd itself gives an id: a classic uid S-1-22-1-<uid>, the same
+ * on every server (it used to be the server's own domain SID + uid), a
+ * classic gid S-1-22-2-<gid>, a UUID or GUID S-1-22-<kind>-w0-w1-w2-w3.
*/
static void native_uid_sid(kuid_t uid, uint sidtype, struct smb_sid *ssid)
{
- if (uid_is_legacy(uid) || sidtype == SIDCREATOR_OWNER ||
- sidtype == SIDCREATOR_GROUP)
+ if (sidtype == SIDCREATOR_OWNER || sidtype == SIDCREATOR_GROUP)
id_to_sid(from_kuid_munged(&init_user_ns, uid), sidtype, ssid);
+ else if (uid_is_legacy(uid))
+ id_to_sid(from_kuid_munged(&init_user_ns, uid), SIDUNIX_USER, ssid);
else if (uid.type == KID_UUID)
id_r_to_sid(SID_UNIX_UUID_USER, uid.uuid.b, ssid);
else
@@ -373,13 +375,14 @@ static bool sid_equal(const struct smb_sid *a, const struct smb_sid *b)
/*
* The SIDs a user's ACL entries may name, like a Windows access token: the
* user's and its groups', each the account's own SID (if user space maps
- * one) and ksmbd's. Built at login; a
+ * one) and ksmbd's -- for a classic uid also the server's domain SID + uid
+ * of older ksmbd, which stored descriptors may hold. Built at login; a
* mapping user space couldn't give then is missing for the session (its
* ACL entries don't match: access is denied, not granted).
*/
void ksmbd_user_set_token(struct ksmbd_user *user)
{
- int i, n = 0, max = 2 + 2 * (user->ngroups + 1);
+ int i, n = 0, max = 3 + 2 * (user->ngroups + 1);
struct smb_sid *sids;

sids = kcalloc(max, sizeof(*sids), KSMBD_DEFAULT_GFP);
@@ -388,6 +391,9 @@ void ksmbd_user_set_token(struct ksmbd_user *user)
if (!mapped_uid_sid(user->kuid, &sids[n]))
n++;
native_uid_sid(user->kuid, SIDOWNER, &sids[n++]);
+ if (uid_is_legacy(user->kuid) && !uid_eq(user->kuid, GLOBAL_ROOT_UID))
+ id_to_sid(from_kuid_munged(&init_user_ns, user->kuid), SIDOWNER,
+ &sids[n++]);
for (i = -1; i < user->ngroups; i++) {
kgid_t gid = i < 0 ? user->kgid : user->sgid[i];

@@ -519,8 +525,15 @@ static int sid_to_id(struct mnt_idmap *idmap,
kuid_t uid;
uid_t id;

- /* Only the server domain RID has a local uid representation. */
- sid_prefix = &server_conf.domain_sid;
+ /*
+ * A local uid: S-1-22-1-<uid>, or the server's domain SID +
+ * uid that ksmbd used to show (stored descriptors have it).
+ */
+ if (psid->num_subauth == sid_unix_users.num_subauth + 1 &&
+ !compare_sids(psid, &sid_unix_users))
+ sid_prefix = &sid_unix_users;
+ else
+ sid_prefix = &server_conf.domain_sid;
if (psid->num_subauth != sid_prefix->num_subauth + 1 ||
compare_sids(psid, sid_prefix))
return -EINVAL;
--
2.56.0