Skip to content

Commit a77e0e0

Browse files
namjaejeonSteve French
authored andcommitted
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ä <[email protected]> Signed-off-by: Atte Heikkilä <[email protected]> Signed-off-by: Namjae Jeon <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 7aa8804 commit a77e0e0

File tree

7 files changed

+137
-17
lines changed

7 files changed

+137
-17
lines changed

fs/smb/server/auth.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,7 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
512512
int in_len, char *out_blob, int *out_len)
513513
{
514514
struct ksmbd_spnego_authen_response *resp;
515+
struct ksmbd_login_response_ext *resp_ext = NULL;
515516
struct ksmbd_user *user = NULL;
516517
int retval;
517518

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

543-
user = ksmbd_alloc_user(&resp->login_response);
544+
if (resp->login_response.status & KSMBD_USER_FLAG_EXTENSION)
545+
resp_ext = ksmbd_ipc_login_request_ext(resp->login_response.account);
546+
547+
user = ksmbd_alloc_user(&resp->login_response, resp_ext);
544548
if (!user) {
545549
ksmbd_debug(AUTH, "login failure\n");
546550
retval = -ENOMEM;

fs/smb/server/ksmbd_netlink.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
* - KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST/RESPONSE(ksmbd_spnego_authen_request/response)
5252
* This event is to make kerberos authentication to be processed in
5353
* userspace.
54+
*
55+
* - KSMBD_EVENT_LOGIN_REQUEST_EXT/RESPONSE_EXT(ksmbd_login_request_ext/response_ext)
56+
* This event is to get user account extension info to user IPC daemon.
5457
*/
5558

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

151+
/*
152+
* IPC user login response extension.
153+
*/
154+
struct ksmbd_login_response_ext {
155+
__u32 handle;
156+
__s32 ngroups; /* supplementary group count */
157+
__s8 reserved[128]; /* Reserved room */
158+
__s8 ____payload[];
159+
};
160+
148161
/*
149162
* IPC request to fetch net share config.
150163
*/
@@ -306,6 +319,9 @@ enum ksmbd_event {
306319
KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST,
307320
KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE = 15,
308321

322+
KSMBD_EVENT_LOGIN_REQUEST_EXT,
323+
KSMBD_EVENT_LOGIN_RESPONSE_EXT,
324+
309325
__KSMBD_EVENT_MAX,
310326
KSMBD_EVENT_MAX = __KSMBD_EVENT_MAX - 1
311327
};
@@ -336,6 +352,7 @@ enum KSMBD_TREE_CONN_STATUS {
336352
#define KSMBD_USER_FLAG_BAD_USER BIT(3)
337353
#define KSMBD_USER_FLAG_GUEST_ACCOUNT BIT(4)
338354
#define KSMBD_USER_FLAG_DELAY_SESSION BIT(5)
355+
#define KSMBD_USER_FLAG_EXTENSION BIT(6)
339356

340357
/*
341358
* Share config flags.

fs/smb/server/mgmt/user_config.c

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
struct ksmbd_user *ksmbd_login_user(const char *account)
1313
{
1414
struct ksmbd_login_response *resp;
15+
struct ksmbd_login_response_ext *resp_ext = NULL;
1516
struct ksmbd_user *user = NULL;
1617

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

24-
user = ksmbd_alloc_user(resp);
25+
if (resp->status & KSMBD_USER_FLAG_EXTENSION)
26+
resp_ext = ksmbd_ipc_login_request_ext(account);
27+
28+
user = ksmbd_alloc_user(resp, resp_ext);
2529
out:
2630
kvfree(resp);
2731
return user;
2832
}
2933

30-
struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp)
34+
struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
35+
struct ksmbd_login_response_ext *resp_ext)
3136
{
32-
struct ksmbd_user *user = NULL;
37+
struct ksmbd_user *user;
3338

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

47-
if (!user->name || !user->passkey) {
48-
kfree(user->name);
49-
kfree(user->passkey);
50-
kfree(user);
51-
user = NULL;
52+
user->ngroups = 0;
53+
user->sgid = NULL;
54+
55+
if (!user->name || !user->passkey)
56+
goto err_free;
57+
58+
if (resp_ext) {
59+
if (resp_ext->ngroups > NGROUPS_MAX) {
60+
pr_err("ngroups(%u) from login response exceeds max groups(%d)\n",
61+
resp_ext->ngroups, NGROUPS_MAX);
62+
goto err_free;
63+
}
64+
65+
user->sgid = kmemdup(resp_ext->____payload,
66+
resp_ext->ngroups * sizeof(gid_t),
67+
GFP_KERNEL);
68+
if (!user->sgid)
69+
goto err_free;
70+
71+
user->ngroups = resp_ext->ngroups;
72+
ksmbd_debug(SMB, "supplementary groups : %d\n", user->ngroups);
5273
}
74+
5375
return user;
76+
77+
err_free:
78+
kfree(user->name);
79+
kfree(user->passkey);
80+
kfree(user);
81+
return NULL;
5482
}
5583

5684
void ksmbd_free_user(struct ksmbd_user *user)
5785
{
5886
ksmbd_ipc_logout_request(user->name, user->flags);
87+
kfree(user->sgid);
5988
kfree(user->name);
6089
kfree(user->passkey);
6190
kfree(user);

fs/smb/server/mgmt/user_config.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ struct ksmbd_user {
1818

1919
size_t passkey_sz;
2020
char *passkey;
21+
int ngroups;
22+
gid_t *sgid;
2123
};
2224

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

6264
struct ksmbd_user *ksmbd_login_user(const char *account);
63-
struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp);
65+
struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
66+
struct ksmbd_login_response_ext *resp_ext);
6467
void ksmbd_free_user(struct ksmbd_user *user);
6568
int ksmbd_anonymous_user(struct ksmbd_user *user);
6669
bool ksmbd_compare_user(struct ksmbd_user *u1, struct ksmbd_user *u2);

fs/smb/server/smb_common.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -736,13 +736,15 @@ int __ksmbd_override_fsids(struct ksmbd_work *work,
736736
struct ksmbd_share_config *share)
737737
{
738738
struct ksmbd_session *sess = work->sess;
739+
struct ksmbd_user *user = sess->user;
739740
struct cred *cred;
740741
struct group_info *gi;
741742
unsigned int uid;
742743
unsigned int gid;
744+
int i;
743745

744-
uid = user_uid(sess->user);
745-
gid = user_gid(sess->user);
746+
uid = user_uid(user);
747+
gid = user_gid(user);
746748
if (share->force_uid != KSMBD_SHARE_INVALID_UID)
747749
uid = share->force_uid;
748750
if (share->force_gid != KSMBD_SHARE_INVALID_GID)
@@ -755,11 +757,18 @@ int __ksmbd_override_fsids(struct ksmbd_work *work,
755757
cred->fsuid = make_kuid(&init_user_ns, uid);
756758
cred->fsgid = make_kgid(&init_user_ns, gid);
757759

758-
gi = groups_alloc(0);
760+
gi = groups_alloc(user->ngroups);
759761
if (!gi) {
760762
abort_creds(cred);
761763
return -ENOMEM;
762764
}
765+
766+
for (i = 0; i < user->ngroups; i++)
767+
gi->gid[i] = make_kgid(&init_user_ns, user->sgid[i]);
768+
769+
if (user->ngroups)
770+
groups_sort(gi);
771+
763772
set_groups(cred, gi);
764773
put_group_info(gi);
765774

fs/smb/server/transport_ipc.c

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = {
120120
},
121121
[KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE] = {
122122
},
123+
[KSMBD_EVENT_LOGIN_REQUEST_EXT] = {
124+
.len = sizeof(struct ksmbd_login_request),
125+
},
126+
[KSMBD_EVENT_LOGIN_RESPONSE_EXT] = {
127+
.len = sizeof(struct ksmbd_login_response_ext),
128+
},
123129
};
124130

125131
static struct genl_ops ksmbd_genl_ops[] = {
@@ -187,6 +193,14 @@ static struct genl_ops ksmbd_genl_ops[] = {
187193
.cmd = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE,
188194
.doit = handle_generic_event,
189195
},
196+
{
197+
.cmd = KSMBD_EVENT_LOGIN_REQUEST_EXT,
198+
.doit = handle_unsupported_event,
199+
},
200+
{
201+
.cmd = KSMBD_EVENT_LOGIN_RESPONSE_EXT,
202+
.doit = handle_generic_event,
203+
},
190204
};
191205

192206
static struct genl_family ksmbd_genl_family = {
@@ -198,7 +212,7 @@ static struct genl_family ksmbd_genl_family = {
198212
.module = THIS_MODULE,
199213
.ops = ksmbd_genl_ops,
200214
.n_ops = ARRAY_SIZE(ksmbd_genl_ops),
201-
.resv_start_op = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE + 1,
215+
.resv_start_op = KSMBD_EVENT_LOGIN_RESPONSE_EXT + 1,
202216
};
203217

204218
static void ksmbd_nl_init_fixup(void)
@@ -459,16 +473,24 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
459473
{
460474
unsigned int msg_sz = entry->msg_sz;
461475

462-
if (entry->type == KSMBD_EVENT_RPC_REQUEST) {
476+
switch (entry->type) {
477+
case KSMBD_EVENT_RPC_REQUEST:
478+
{
463479
struct ksmbd_rpc_command *resp = entry->response;
464480

465481
msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
466-
} else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) {
482+
break;
483+
}
484+
case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST:
485+
{
467486
struct ksmbd_spnego_authen_response *resp = entry->response;
468487

469488
msg_sz = sizeof(struct ksmbd_spnego_authen_response) +
470489
resp->session_key_len + resp->spnego_blob_len;
471-
} else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) {
490+
break;
491+
}
492+
case KSMBD_EVENT_SHARE_CONFIG_REQUEST:
493+
{
472494
struct ksmbd_share_config_response *resp = entry->response;
473495

474496
if (resp->payload_sz) {
@@ -478,6 +500,17 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
478500
msg_sz = sizeof(struct ksmbd_share_config_response) +
479501
resp->payload_sz;
480502
}
503+
break;
504+
}
505+
case KSMBD_EVENT_LOGIN_REQUEST_EXT:
506+
{
507+
struct ksmbd_login_response_ext *resp = entry->response;
508+
509+
if (resp->ngroups) {
510+
msg_sz = sizeof(struct ksmbd_login_response_ext) +
511+
resp->ngroups * sizeof(gid_t);
512+
}
513+
}
481514
}
482515

483516
return entry->msg_sz != msg_sz ? -EINVAL : 0;
@@ -560,6 +593,29 @@ struct ksmbd_login_response *ksmbd_ipc_login_request(const char *account)
560593
return resp;
561594
}
562595

596+
struct ksmbd_login_response_ext *ksmbd_ipc_login_request_ext(const char *account)
597+
{
598+
struct ksmbd_ipc_msg *msg;
599+
struct ksmbd_login_request *req;
600+
struct ksmbd_login_response_ext *resp;
601+
602+
if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)
603+
return NULL;
604+
605+
msg = ipc_msg_alloc(sizeof(struct ksmbd_login_request));
606+
if (!msg)
607+
return NULL;
608+
609+
msg->type = KSMBD_EVENT_LOGIN_REQUEST_EXT;
610+
req = (struct ksmbd_login_request *)msg->payload;
611+
req->handle = ksmbd_acquire_id(&ipc_ida);
612+
strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);
613+
resp = ipc_msg_send_request(msg, req->handle);
614+
ipc_msg_handle_free(req->handle);
615+
ipc_msg_free(msg);
616+
return resp;
617+
}
618+
563619
struct ksmbd_spnego_authen_response *
564620
ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len)
565621
{

fs/smb/server/transport_ipc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
struct ksmbd_login_response *
1414
ksmbd_ipc_login_request(const char *account);
15+
struct ksmbd_login_response_ext *
16+
ksmbd_ipc_login_request_ext(const char *account);
1517

1618
struct ksmbd_session;
1719
struct ksmbd_share_config;

0 commit comments

Comments
 (0)