mirror of
https://github.com/torvalds/linux.git
synced 2026-05-26 16:12:59 +02:00
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: Atte Heikkilä <atteh.mailbox@gmail.com> Signed-off-by: Atte Heikkilä <atteh.mailbox@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
7aa8804c0b
commit
a77e0e02af
|
|
@ -512,6 +512,7 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
|
||||||
int in_len, char *out_blob, int *out_len)
|
int in_len, char *out_blob, int *out_len)
|
||||||
{
|
{
|
||||||
struct ksmbd_spnego_authen_response *resp;
|
struct ksmbd_spnego_authen_response *resp;
|
||||||
|
struct ksmbd_login_response_ext *resp_ext = NULL;
|
||||||
struct ksmbd_user *user = NULL;
|
struct ksmbd_user *user = NULL;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
|
@ -540,7 +541,10 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
|
||||||
goto out;
|
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) {
|
if (!user) {
|
||||||
ksmbd_debug(AUTH, "login failure\n");
|
ksmbd_debug(AUTH, "login failure\n");
|
||||||
retval = -ENOMEM;
|
retval = -ENOMEM;
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@
|
||||||
* - KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST/RESPONSE(ksmbd_spnego_authen_request/response)
|
* - KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST/RESPONSE(ksmbd_spnego_authen_request/response)
|
||||||
* This event is to make kerberos authentication to be processed in
|
* This event is to make kerberos authentication to be processed in
|
||||||
* userspace.
|
* 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"
|
#define KSMBD_GENL_NAME "SMBD_GENL"
|
||||||
|
|
@ -145,6 +148,16 @@ struct ksmbd_login_response {
|
||||||
__u32 reserved[16]; /* Reserved room */
|
__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.
|
* IPC request to fetch net share config.
|
||||||
*/
|
*/
|
||||||
|
|
@ -306,6 +319,9 @@ enum ksmbd_event {
|
||||||
KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST,
|
KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST,
|
||||||
KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE = 15,
|
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 = __KSMBD_EVENT_MAX - 1
|
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_BAD_USER BIT(3)
|
||||||
#define KSMBD_USER_FLAG_GUEST_ACCOUNT BIT(4)
|
#define KSMBD_USER_FLAG_GUEST_ACCOUNT BIT(4)
|
||||||
#define KSMBD_USER_FLAG_DELAY_SESSION BIT(5)
|
#define KSMBD_USER_FLAG_DELAY_SESSION BIT(5)
|
||||||
|
#define KSMBD_USER_FLAG_EXTENSION BIT(6)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Share config flags.
|
* Share config flags.
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
struct ksmbd_user *ksmbd_login_user(const char *account)
|
struct ksmbd_user *ksmbd_login_user(const char *account)
|
||||||
{
|
{
|
||||||
struct ksmbd_login_response *resp;
|
struct ksmbd_login_response *resp;
|
||||||
|
struct ksmbd_login_response_ext *resp_ext = NULL;
|
||||||
struct ksmbd_user *user = NULL;
|
struct ksmbd_user *user = NULL;
|
||||||
|
|
||||||
resp = ksmbd_ipc_login_request(account);
|
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))
|
if (!(resp->status & KSMBD_USER_FLAG_OK))
|
||||||
goto out;
|
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:
|
out:
|
||||||
kvfree(resp);
|
kvfree(resp);
|
||||||
return user;
|
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);
|
user = kmalloc(sizeof(struct ksmbd_user), GFP_KERNEL);
|
||||||
if (!user)
|
if (!user)
|
||||||
|
|
@ -44,18 +49,42 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp)
|
||||||
if (user->passkey)
|
if (user->passkey)
|
||||||
memcpy(user->passkey, resp->hash, resp->hash_sz);
|
memcpy(user->passkey, resp->hash, resp->hash_sz);
|
||||||
|
|
||||||
if (!user->name || !user->passkey) {
|
user->ngroups = 0;
|
||||||
kfree(user->name);
|
user->sgid = NULL;
|
||||||
kfree(user->passkey);
|
|
||||||
kfree(user);
|
if (!user->name || !user->passkey)
|
||||||
user = NULL;
|
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;
|
return user;
|
||||||
|
|
||||||
|
err_free:
|
||||||
|
kfree(user->name);
|
||||||
|
kfree(user->passkey);
|
||||||
|
kfree(user);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksmbd_free_user(struct ksmbd_user *user)
|
void ksmbd_free_user(struct ksmbd_user *user)
|
||||||
{
|
{
|
||||||
ksmbd_ipc_logout_request(user->name, user->flags);
|
ksmbd_ipc_logout_request(user->name, user->flags);
|
||||||
|
kfree(user->sgid);
|
||||||
kfree(user->name);
|
kfree(user->name);
|
||||||
kfree(user->passkey);
|
kfree(user->passkey);
|
||||||
kfree(user);
|
kfree(user);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ struct ksmbd_user {
|
||||||
|
|
||||||
size_t passkey_sz;
|
size_t passkey_sz;
|
||||||
char *passkey;
|
char *passkey;
|
||||||
|
int ngroups;
|
||||||
|
gid_t *sgid;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool user_guest(struct ksmbd_user *user)
|
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_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);
|
void ksmbd_free_user(struct ksmbd_user *user);
|
||||||
int ksmbd_anonymous_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);
|
bool ksmbd_compare_user(struct ksmbd_user *u1, struct ksmbd_user *u2);
|
||||||
|
|
|
||||||
|
|
@ -736,13 +736,15 @@ int __ksmbd_override_fsids(struct ksmbd_work *work,
|
||||||
struct ksmbd_share_config *share)
|
struct ksmbd_share_config *share)
|
||||||
{
|
{
|
||||||
struct ksmbd_session *sess = work->sess;
|
struct ksmbd_session *sess = work->sess;
|
||||||
|
struct ksmbd_user *user = sess->user;
|
||||||
struct cred *cred;
|
struct cred *cred;
|
||||||
struct group_info *gi;
|
struct group_info *gi;
|
||||||
unsigned int uid;
|
unsigned int uid;
|
||||||
unsigned int gid;
|
unsigned int gid;
|
||||||
|
int i;
|
||||||
|
|
||||||
uid = user_uid(sess->user);
|
uid = user_uid(user);
|
||||||
gid = user_gid(sess->user);
|
gid = user_gid(user);
|
||||||
if (share->force_uid != KSMBD_SHARE_INVALID_UID)
|
if (share->force_uid != KSMBD_SHARE_INVALID_UID)
|
||||||
uid = share->force_uid;
|
uid = share->force_uid;
|
||||||
if (share->force_gid != KSMBD_SHARE_INVALID_GID)
|
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->fsuid = make_kuid(&init_user_ns, uid);
|
||||||
cred->fsgid = make_kgid(&init_user_ns, gid);
|
cred->fsgid = make_kgid(&init_user_ns, gid);
|
||||||
|
|
||||||
gi = groups_alloc(0);
|
gi = groups_alloc(user->ngroups);
|
||||||
if (!gi) {
|
if (!gi) {
|
||||||
abort_creds(cred);
|
abort_creds(cred);
|
||||||
return -ENOMEM;
|
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);
|
set_groups(cred, gi);
|
||||||
put_group_info(gi);
|
put_group_info(gi);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,12 @@ static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = {
|
||||||
},
|
},
|
||||||
[KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE] = {
|
[KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE] = {
|
||||||
},
|
},
|
||||||
|
[KSMBD_EVENT_LOGIN_REQUEST_EXT] = {
|
||||||
|
.len = sizeof(struct ksmbd_login_request),
|
||||||
|
},
|
||||||
|
[KSMBD_EVENT_LOGIN_RESPONSE_EXT] = {
|
||||||
|
.len = sizeof(struct ksmbd_login_response_ext),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct genl_ops ksmbd_genl_ops[] = {
|
static struct genl_ops ksmbd_genl_ops[] = {
|
||||||
|
|
@ -187,6 +193,14 @@ static struct genl_ops ksmbd_genl_ops[] = {
|
||||||
.cmd = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE,
|
.cmd = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE,
|
||||||
.doit = handle_generic_event,
|
.doit = handle_generic_event,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.cmd = KSMBD_EVENT_LOGIN_REQUEST_EXT,
|
||||||
|
.doit = handle_unsupported_event,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.cmd = KSMBD_EVENT_LOGIN_RESPONSE_EXT,
|
||||||
|
.doit = handle_generic_event,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct genl_family ksmbd_genl_family = {
|
static struct genl_family ksmbd_genl_family = {
|
||||||
|
|
@ -198,7 +212,7 @@ static struct genl_family ksmbd_genl_family = {
|
||||||
.module = THIS_MODULE,
|
.module = THIS_MODULE,
|
||||||
.ops = ksmbd_genl_ops,
|
.ops = ksmbd_genl_ops,
|
||||||
.n_ops = ARRAY_SIZE(ksmbd_genl_ops),
|
.n_ops = ARRAY_SIZE(ksmbd_genl_ops),
|
||||||
.resv_start_op = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE + 1,
|
.resv_start_op = KSMBD_EVENT_LOGIN_RESPONSE_EXT + 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ksmbd_nl_init_fixup(void)
|
static void ksmbd_nl_init_fixup(void)
|
||||||
|
|
@ -459,16 +473,24 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
|
||||||
{
|
{
|
||||||
unsigned int msg_sz = entry->msg_sz;
|
unsigned int msg_sz = entry->msg_sz;
|
||||||
|
|
||||||
if (entry->type == KSMBD_EVENT_RPC_REQUEST) {
|
switch (entry->type) {
|
||||||
|
case KSMBD_EVENT_RPC_REQUEST:
|
||||||
|
{
|
||||||
struct ksmbd_rpc_command *resp = entry->response;
|
struct ksmbd_rpc_command *resp = entry->response;
|
||||||
|
|
||||||
msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
|
msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
|
||||||
} else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) {
|
break;
|
||||||
|
}
|
||||||
|
case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST:
|
||||||
|
{
|
||||||
struct ksmbd_spnego_authen_response *resp = entry->response;
|
struct ksmbd_spnego_authen_response *resp = entry->response;
|
||||||
|
|
||||||
msg_sz = sizeof(struct ksmbd_spnego_authen_response) +
|
msg_sz = sizeof(struct ksmbd_spnego_authen_response) +
|
||||||
resp->session_key_len + resp->spnego_blob_len;
|
resp->session_key_len + resp->spnego_blob_len;
|
||||||
} else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) {
|
break;
|
||||||
|
}
|
||||||
|
case KSMBD_EVENT_SHARE_CONFIG_REQUEST:
|
||||||
|
{
|
||||||
struct ksmbd_share_config_response *resp = entry->response;
|
struct ksmbd_share_config_response *resp = entry->response;
|
||||||
|
|
||||||
if (resp->payload_sz) {
|
if (resp->payload_sz) {
|
||||||
|
|
@ -478,6 +500,17 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
|
||||||
msg_sz = sizeof(struct ksmbd_share_config_response) +
|
msg_sz = sizeof(struct ksmbd_share_config_response) +
|
||||||
resp->payload_sz;
|
resp->payload_sz;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KSMBD_EVENT_LOGIN_REQUEST_EXT:
|
||||||
|
{
|
||||||
|
struct ksmbd_login_response_ext *resp = entry->response;
|
||||||
|
|
||||||
|
if (resp->ngroups) {
|
||||||
|
msg_sz = sizeof(struct ksmbd_login_response_ext) +
|
||||||
|
resp->ngroups * sizeof(gid_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry->msg_sz != msg_sz ? -EINVAL : 0;
|
return entry->msg_sz != msg_sz ? -EINVAL : 0;
|
||||||
|
|
@ -560,6 +593,29 @@ struct ksmbd_login_response *ksmbd_ipc_login_request(const char *account)
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ksmbd_login_response_ext *ksmbd_ipc_login_request_ext(const char *account)
|
||||||
|
{
|
||||||
|
struct ksmbd_ipc_msg *msg;
|
||||||
|
struct ksmbd_login_request *req;
|
||||||
|
struct ksmbd_login_response_ext *resp;
|
||||||
|
|
||||||
|
if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
msg = ipc_msg_alloc(sizeof(struct ksmbd_login_request));
|
||||||
|
if (!msg)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
msg->type = KSMBD_EVENT_LOGIN_REQUEST_EXT;
|
||||||
|
req = (struct ksmbd_login_request *)msg->payload;
|
||||||
|
req->handle = ksmbd_acquire_id(&ipc_ida);
|
||||||
|
strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);
|
||||||
|
resp = ipc_msg_send_request(msg, req->handle);
|
||||||
|
ipc_msg_handle_free(req->handle);
|
||||||
|
ipc_msg_free(msg);
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
struct ksmbd_spnego_authen_response *
|
struct ksmbd_spnego_authen_response *
|
||||||
ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len)
|
ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
struct ksmbd_login_response *
|
struct ksmbd_login_response *
|
||||||
ksmbd_ipc_login_request(const char *account);
|
ksmbd_ipc_login_request(const char *account);
|
||||||
|
struct ksmbd_login_response_ext *
|
||||||
|
ksmbd_ipc_login_request_ext(const char *account);
|
||||||
|
|
||||||
struct ksmbd_session;
|
struct ksmbd_session;
|
||||||
struct ksmbd_share_config;
|
struct ksmbd_share_config;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user