Commit a77e0e02 authored by Namjae Jeon's avatar Namjae Jeon Committed by Steve French
Browse files

ksmbd: add support for supplementary groups



Even though system user has a supplementary group, It gets
NT_STATUS_ACCESS_DENIED when attempting to create file or directory.
This patch add KSMBD_EVENT_LOGIN_REQUEST_EXT/RESPONSE_EXT netlink events
to get supplementary groups list. The new netlink event doesn't break
backward compatibility when using old ksmbd-tools.

Co-developed-by: default avatarAtte Heikkilä <atteh.mailbox@gmail.com>
Signed-off-by: default avatarAtte Heikkilä <atteh.mailbox@gmail.com>
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 7aa8804c
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -512,6 +512,7 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
			    int in_len, char *out_blob, int *out_len)
{
	struct ksmbd_spnego_authen_response *resp;
	struct ksmbd_login_response_ext *resp_ext = NULL;
	struct ksmbd_user *user = NULL;
	int retval;

@@ -540,7 +541,10 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
		goto out;
	}

	user = ksmbd_alloc_user(&resp->login_response);
	if (resp->login_response.status & KSMBD_USER_FLAG_EXTENSION)
		resp_ext = ksmbd_ipc_login_request_ext(resp->login_response.account);

	user = ksmbd_alloc_user(&resp->login_response, resp_ext);
	if (!user) {
		ksmbd_debug(AUTH, "login failure\n");
		retval = -ENOMEM;
+17 −0
Original line number Diff line number Diff line
@@ -51,6 +51,9 @@
 *  - KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST/RESPONSE(ksmbd_spnego_authen_request/response)
 *    This event is to make kerberos authentication to be processed in
 *    userspace.
 *
 *  - 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.
 */

#define KSMBD_GENL_NAME		"SMBD_GENL"
@@ -145,6 +148,16 @@ struct ksmbd_login_response {
	__u32	reserved[16];			/* Reserved room */
};

/*
 * IPC user login response extension.
 */
struct ksmbd_login_response_ext {
	__u32	handle;
	__s32	ngroups;			/* supplementary group count */
	__s8	reserved[128];			/* Reserved room */
	__s8	____payload[];
};

/*
 * IPC request to fetch net share config.
 */
@@ -306,6 +319,9 @@ enum ksmbd_event {
	KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST,
	KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE	= 15,

	KSMBD_EVENT_LOGIN_REQUEST_EXT,
	KSMBD_EVENT_LOGIN_RESPONSE_EXT,

	__KSMBD_EVENT_MAX,
	KSMBD_EVENT_MAX = __KSMBD_EVENT_MAX - 1
};
@@ -336,6 +352,7 @@ enum KSMBD_TREE_CONN_STATUS {
#define KSMBD_USER_FLAG_BAD_USER	BIT(3)
#define KSMBD_USER_FLAG_GUEST_ACCOUNT	BIT(4)
#define KSMBD_USER_FLAG_DELAY_SESSION	BIT(5)
#define KSMBD_USER_FLAG_EXTENSION	BIT(6)

/*
 * Share config flags.
+37 −8
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
struct ksmbd_user *ksmbd_login_user(const char *account)
{
	struct ksmbd_login_response *resp;
	struct ksmbd_login_response_ext *resp_ext = NULL;
	struct ksmbd_user *user = NULL;

	resp = ksmbd_ipc_login_request(account);
@@ -21,15 +22,19 @@ struct ksmbd_user *ksmbd_login_user(const char *account)
	if (!(resp->status & KSMBD_USER_FLAG_OK))
		goto out;

	user = ksmbd_alloc_user(resp);
	if (resp->status & KSMBD_USER_FLAG_EXTENSION)
		resp_ext = ksmbd_ipc_login_request_ext(account);

	user = ksmbd_alloc_user(resp, resp_ext);
out:
	kvfree(resp);
	return user;
}

struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp)
struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
		struct ksmbd_login_response_ext *resp_ext)
{
	struct ksmbd_user *user = NULL;
	struct ksmbd_user *user;

	user = kmalloc(sizeof(struct ksmbd_user), GFP_KERNEL);
	if (!user)
@@ -44,18 +49,42 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp)
	if (user->passkey)
		memcpy(user->passkey, resp->hash, resp->hash_sz);

	if (!user->name || !user->passkey) {
	user->ngroups = 0;
	user->sgid = NULL;

	if (!user->name || !user->passkey)
		goto err_free;

	if (resp_ext) {
		if (resp_ext->ngroups > NGROUPS_MAX) {
			pr_err("ngroups(%u) from login response exceeds max groups(%d)\n",
					resp_ext->ngroups, NGROUPS_MAX);
			goto err_free;
		}

		user->sgid = kmemdup(resp_ext->____payload,
				     resp_ext->ngroups * sizeof(gid_t),
				     GFP_KERNEL);
		if (!user->sgid)
			goto err_free;

		user->ngroups = resp_ext->ngroups;
		ksmbd_debug(SMB, "supplementary groups : %d\n", user->ngroups);
	}

	return user;

err_free:
	kfree(user->name);
	kfree(user->passkey);
	kfree(user);
		user = NULL;
	}
	return user;
	return NULL;
}

void ksmbd_free_user(struct ksmbd_user *user)
{
	ksmbd_ipc_logout_request(user->name, user->flags);
	kfree(user->sgid);
	kfree(user->name);
	kfree(user->passkey);
	kfree(user);
+4 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ struct ksmbd_user {

	size_t			passkey_sz;
	char			*passkey;
	int			ngroups;
	gid_t			*sgid;
};

static inline bool user_guest(struct ksmbd_user *user)
@@ -60,7 +62,8 @@ static inline unsigned int user_gid(struct ksmbd_user *user)
}

struct ksmbd_user *ksmbd_login_user(const char *account);
struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp);
struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
		struct ksmbd_login_response_ext *resp_ext);
void ksmbd_free_user(struct ksmbd_user *user);
int ksmbd_anonymous_user(struct ksmbd_user *user);
bool ksmbd_compare_user(struct ksmbd_user *u1, struct ksmbd_user *u2);
+12 −3
Original line number Diff line number Diff line
@@ -736,13 +736,15 @@ int __ksmbd_override_fsids(struct ksmbd_work *work,
		struct ksmbd_share_config *share)
{
	struct ksmbd_session *sess = work->sess;
	struct ksmbd_user *user = sess->user;
	struct cred *cred;
	struct group_info *gi;
	unsigned int uid;
	unsigned int gid;
	int i;

	uid = user_uid(sess->user);
	gid = user_gid(sess->user);
	uid = user_uid(user);
	gid = user_gid(user);
	if (share->force_uid != KSMBD_SHARE_INVALID_UID)
		uid = share->force_uid;
	if (share->force_gid != KSMBD_SHARE_INVALID_GID)
@@ -755,11 +757,18 @@ int __ksmbd_override_fsids(struct ksmbd_work *work,
	cred->fsuid = make_kuid(&init_user_ns, uid);
	cred->fsgid = make_kgid(&init_user_ns, gid);

	gi = groups_alloc(0);
	gi = groups_alloc(user->ngroups);
	if (!gi) {
		abort_creds(cred);
		return -ENOMEM;
	}

	for (i = 0; i < user->ngroups; i++)
		gi->gid[i] = make_kgid(&init_user_ns, user->sgid[i]);

	if (user->ngroups)
		groups_sort(gi);

	set_groups(cred, gi);
	put_group_info(gi);

Loading