24 ksmbd server fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmM/K50ACgkQiiy9cAdy T1H+JAv+KOk1oTGTDKiY/+1aEl/G1SxpgTnaemzK8U95nN2yCmddjxhwsoTI9e68 lS7C+f0M3VN6X3S3OZoQXI4+B/VEODTR9yF9J30LULBw3rF3qJsGGllzXhnOIGOB bFFBgqTxq5mK0k9QmAyrf6dvEKfkxaGAXza3sGVFB6JxQTeEhhgrNjG70NqFw+0M rFEByqi2DMAvHBIDoDVqydaah+VTBJLfa6vfXOC+MBVu/qekyB0gKnZ3pGDKMWgq uPS6DaSYXlezuPuAKB8upLcSQewH3W+fqiGz9pimimWPJQXeHbfkqiuD/Gah/Flp lMQG0jziPclt08Ygts2wUvx503OUCHy9JAPfdOxpxNy3UOqovY+mu2K+Kbj/ZfTB Ta0vifoSCxA3YgIzVViqL3aq4zfKIHwHiDmJWa1zpTcSZ+QQh7zIDHFFg9UbzfZH zDH7l40NTIlc1Zh8ddX3+kJCzKI5OLJ+0ToyoayGXzfYTUR/gta/R6Ox4hzYF8KB ovGHvOnX =zHi1 -----END PGP SIGNATURE----- Merge tag '6.1-rc-ksmbd-fixes' of git://git.samba.org/ksmbd Pull ksmbd updates from Steve French: - RDMA (smbdirect) fixes - fixes for SMB3.1.1 POSIX Extensions (especially for id mapping) - various casemapping fixes for mount and lookup - UID mapping fixes - fix confusing error message - protocol negotiation fixes, including NTLMSSP fix - two encryption fixes - directory listing fix - some cleanup fixes * tag '6.1-rc-ksmbd-fixes' of git://git.samba.org/ksmbd: (24 commits) ksmbd: validate share name from share config response ksmbd: call ib_drain_qp when disconnected ksmbd: make utf-8 file name comparison work in __caseless_lookup() ksmbd: Fix user namespace mapping ksmbd: hide socket error message when ipv6 config is disable ksmbd: reduce server smbdirect max send/receive segment sizes ksmbd: decrease the number of SMB3 smbdirect server SGEs ksmbd: Fix wrong return value and message length check in smb2_ioctl() ksmbd: set NTLMSSP_NEGOTIATE_SEAL flag to challenge blob ksmbd: fix encryption failure issue for session logoff response ksmbd: fix endless loop when encryption for response fails ksmbd: fill sids in SMB_FIND_FILE_POSIX_INFO response ksmbd: set file permission mode to match Samba server posix extension behavior ksmbd: change security id to the one samba used for posix extension ksmbd: update documentation ksmbd: casefold utf-8 share names and fix ascii lowercase conversion ksmbd: port to vfs{g,u}id_t and associated helpers ksmbd: fix incorrect handling of iterate_dir MAINTAINERS: remove Hyunchul Lee from ksmbd maintainers MAINTAINERS: Add Tom Talpey as ksmbd reviewer ...
This commit is contained in:
commit
9f4b9beeb9
|
@ -118,26 +118,44 @@ ksmbd/nfsd interoperability Planned for future. The features that ksmbd
|
||||||
How to run
|
How to run
|
||||||
==========
|
==========
|
||||||
|
|
||||||
1. Download ksmbd-tools and compile them.
|
1. Download ksmbd-tools(https://github.com/cifsd-team/ksmbd-tools/releases) and
|
||||||
- https://github.com/cifsd-team/ksmbd-tools
|
compile them.
|
||||||
|
|
||||||
2. Create user/password for SMB share.
|
- Refer README(https://github.com/cifsd-team/ksmbd-tools/blob/master/README.md)
|
||||||
|
to know how to use ksmbd.mountd/adduser/addshare/control utils
|
||||||
|
|
||||||
# mkdir /etc/ksmbd/
|
$ ./autogen.sh
|
||||||
# ksmbd.adduser -a <Enter USERNAME for SMB share access>
|
$ ./configure --with-rundir=/run
|
||||||
|
$ make && sudo make install
|
||||||
|
|
||||||
3. Create /etc/ksmbd/smb.conf file, add SMB share in smb.conf file
|
2. Create /usr/local/etc/ksmbd/ksmbd.conf file, add SMB share in ksmbd.conf file.
|
||||||
- Refer smb.conf.example and
|
|
||||||
https://github.com/cifsd-team/ksmbd-tools/blob/master/Documentation/configuration.txt
|
|
||||||
|
|
||||||
4. Insert ksmbd.ko module
|
- Refer ksmbd.conf.example in ksmbd-utils, See ksmbd.conf manpage
|
||||||
|
for details to configure shares.
|
||||||
|
|
||||||
# insmod ksmbd.ko
|
$ man ksmbd.conf
|
||||||
|
|
||||||
|
3. Create user/password for SMB share.
|
||||||
|
|
||||||
|
- See ksmbd.adduser manpage.
|
||||||
|
|
||||||
|
$ man ksmbd.adduser
|
||||||
|
$ sudo ksmbd.adduser -a <Enter USERNAME for SMB share access>
|
||||||
|
|
||||||
|
4. Insert ksmbd.ko module after build your kernel. No need to load module
|
||||||
|
if ksmbd is built into the kernel.
|
||||||
|
|
||||||
|
- Set ksmbd in menuconfig(e.g. $ make menuconfig)
|
||||||
|
[*] Network File Systems --->
|
||||||
|
<M> SMB3 server support (EXPERIMENTAL)
|
||||||
|
|
||||||
|
$ sudo modprobe ksmbd.ko
|
||||||
|
|
||||||
5. Start ksmbd user space daemon
|
5. Start ksmbd user space daemon
|
||||||
# ksmbd.mountd
|
|
||||||
|
|
||||||
6. Access share from Windows or Linux using CIFS
|
$ sudo ksmbd.mountd
|
||||||
|
|
||||||
|
6. Access share from Windows or Linux using SMB3 client (cifs.ko or smbclient of samba)
|
||||||
|
|
||||||
Shutdown KSMBD
|
Shutdown KSMBD
|
||||||
==============
|
==============
|
||||||
|
|
|
@ -11101,8 +11101,8 @@ F: tools/testing/selftests/
|
||||||
KERNEL SMB3 SERVER (KSMBD)
|
KERNEL SMB3 SERVER (KSMBD)
|
||||||
M: Namjae Jeon <linkinjeon@kernel.org>
|
M: Namjae Jeon <linkinjeon@kernel.org>
|
||||||
M: Steve French <sfrench@samba.org>
|
M: Steve French <sfrench@samba.org>
|
||||||
M: Hyunchul Lee <hyc.lee@gmail.com>
|
|
||||||
R: Sergey Senozhatsky <senozhatsky@chromium.org>
|
R: Sergey Senozhatsky <senozhatsky@chromium.org>
|
||||||
|
R: Tom Talpey <tom@talpey.com>
|
||||||
L: linux-cifs@vger.kernel.org
|
L: linux-cifs@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.samba.org/ksmbd.git
|
T: git git://git.samba.org/ksmbd.git
|
||||||
|
|
|
@ -424,6 +424,9 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
|
||||||
NTLMSSP_NEGOTIATE_56);
|
NTLMSSP_NEGOTIATE_56);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cflags & NTLMSSP_NEGOTIATE_SEAL && smb3_encryption_negotiated(conn))
|
||||||
|
flags |= NTLMSSP_NEGOTIATE_SEAL;
|
||||||
|
|
||||||
if (cflags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
|
if (cflags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
|
||||||
flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
|
flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
|
||||||
|
|
||||||
|
@ -984,13 +987,16 @@ out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ksmbd_get_encryption_key(struct ksmbd_conn *conn, __u64 ses_id,
|
static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id,
|
||||||
int enc, u8 *key)
|
int enc, u8 *key)
|
||||||
{
|
{
|
||||||
struct ksmbd_session *sess;
|
struct ksmbd_session *sess;
|
||||||
u8 *ses_enc_key;
|
u8 *ses_enc_key;
|
||||||
|
|
||||||
sess = ksmbd_session_lookup_all(conn, ses_id);
|
if (enc)
|
||||||
|
sess = work->sess;
|
||||||
|
else
|
||||||
|
sess = ksmbd_session_lookup_all(work->conn, ses_id);
|
||||||
if (!sess)
|
if (!sess)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -1078,9 +1084,10 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
|
||||||
return sg;
|
return sg;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
|
int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
|
||||||
unsigned int nvec, int enc)
|
unsigned int nvec, int enc)
|
||||||
{
|
{
|
||||||
|
struct ksmbd_conn *conn = work->conn;
|
||||||
struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base);
|
struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base);
|
||||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -1094,7 +1101,7 @@ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
|
||||||
unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
|
unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
|
||||||
struct ksmbd_crypto_ctx *ctx;
|
struct ksmbd_crypto_ctx *ctx;
|
||||||
|
|
||||||
rc = ksmbd_get_encryption_key(conn,
|
rc = ksmbd_get_encryption_key(work,
|
||||||
le64_to_cpu(tr_hdr->SessionId),
|
le64_to_cpu(tr_hdr->SessionId),
|
||||||
enc,
|
enc,
|
||||||
key);
|
key);
|
||||||
|
|
|
@ -33,9 +33,10 @@
|
||||||
|
|
||||||
struct ksmbd_session;
|
struct ksmbd_session;
|
||||||
struct ksmbd_conn;
|
struct ksmbd_conn;
|
||||||
|
struct ksmbd_work;
|
||||||
struct kvec;
|
struct kvec;
|
||||||
|
|
||||||
int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
|
int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
|
||||||
unsigned int nvec, int enc);
|
unsigned int nvec, int enc);
|
||||||
void ksmbd_copy_gss_neg_header(void *buf);
|
void ksmbd_copy_gss_neg_header(void *buf);
|
||||||
int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
|
|
|
@ -60,6 +60,12 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
|
||||||
conn->local_nls = load_nls("utf8");
|
conn->local_nls = load_nls("utf8");
|
||||||
if (!conn->local_nls)
|
if (!conn->local_nls)
|
||||||
conn->local_nls = load_nls_default();
|
conn->local_nls = load_nls_default();
|
||||||
|
if (IS_ENABLED(CONFIG_UNICODE))
|
||||||
|
conn->um = utf8_load(UNICODE_AGE(12, 1, 0));
|
||||||
|
else
|
||||||
|
conn->um = ERR_PTR(-EOPNOTSUPP);
|
||||||
|
if (IS_ERR(conn->um))
|
||||||
|
conn->um = NULL;
|
||||||
atomic_set(&conn->req_running, 0);
|
atomic_set(&conn->req_running, 0);
|
||||||
atomic_set(&conn->r_count, 0);
|
atomic_set(&conn->r_count, 0);
|
||||||
conn->total_credits = 1;
|
conn->total_credits = 1;
|
||||||
|
@ -350,6 +356,8 @@ out:
|
||||||
wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0);
|
wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0);
|
||||||
|
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_UNICODE))
|
||||||
|
utf8_unload(conn->um);
|
||||||
unload_nls(conn->local_nls);
|
unload_nls(conn->local_nls);
|
||||||
if (default_conn_ops.terminate_fn)
|
if (default_conn_ops.terminate_fn)
|
||||||
default_conn_ops.terminate_fn(conn);
|
default_conn_ops.terminate_fn(conn);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <net/request_sock.h>
|
#include <net/request_sock.h>
|
||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/nls.h>
|
#include <linux/nls.h>
|
||||||
|
#include <linux/unicode.h>
|
||||||
|
|
||||||
#include "smb_common.h"
|
#include "smb_common.h"
|
||||||
#include "ksmbd_work.h"
|
#include "ksmbd_work.h"
|
||||||
|
@ -46,6 +47,7 @@ struct ksmbd_conn {
|
||||||
char *request_buf;
|
char *request_buf;
|
||||||
struct ksmbd_transport *transport;
|
struct ksmbd_transport *transport;
|
||||||
struct nls_table *local_nls;
|
struct nls_table *local_nls;
|
||||||
|
struct unicode_map *um;
|
||||||
struct list_head conns_list;
|
struct list_head conns_list;
|
||||||
/* smb session 1 per user */
|
/* smb session 1 per user */
|
||||||
struct xarray sessions;
|
struct xarray sessions;
|
||||||
|
|
|
@ -163,7 +163,8 @@ struct ksmbd_share_config_response {
|
||||||
__u16 force_directory_mode;
|
__u16 force_directory_mode;
|
||||||
__u16 force_uid;
|
__u16 force_uid;
|
||||||
__u16 force_gid;
|
__u16 force_gid;
|
||||||
__u32 reserved[128]; /* Reserved room */
|
__s8 share_name[KSMBD_REQ_MAX_SHARE_NAME];
|
||||||
|
__u32 reserved[112]; /* Reserved room */
|
||||||
__u32 veto_list_sz;
|
__u32 veto_list_sz;
|
||||||
__s8 ____payload[];
|
__s8 ____payload[];
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "user_config.h"
|
#include "user_config.h"
|
||||||
#include "user_session.h"
|
#include "user_session.h"
|
||||||
#include "../transport_ipc.h"
|
#include "../transport_ipc.h"
|
||||||
|
#include "../misc.h"
|
||||||
|
|
||||||
#define SHARE_HASH_BITS 3
|
#define SHARE_HASH_BITS 3
|
||||||
static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
|
static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
|
||||||
|
@ -26,7 +27,7 @@ struct ksmbd_veto_pattern {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int share_name_hash(char *name)
|
static unsigned int share_name_hash(const char *name)
|
||||||
{
|
{
|
||||||
return jhash(name, strlen(name), 0);
|
return jhash(name, strlen(name), 0);
|
||||||
}
|
}
|
||||||
|
@ -72,7 +73,7 @@ __get_share_config(struct ksmbd_share_config *share)
|
||||||
return share;
|
return share;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ksmbd_share_config *__share_lookup(char *name)
|
static struct ksmbd_share_config *__share_lookup(const char *name)
|
||||||
{
|
{
|
||||||
struct ksmbd_share_config *share;
|
struct ksmbd_share_config *share;
|
||||||
unsigned int key = share_name_hash(name);
|
unsigned int key = share_name_hash(name);
|
||||||
|
@ -119,7 +120,8 @@ static int parse_veto_list(struct ksmbd_share_config *share,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ksmbd_share_config *share_config_request(char *name)
|
static struct ksmbd_share_config *share_config_request(struct unicode_map *um,
|
||||||
|
const char *name)
|
||||||
{
|
{
|
||||||
struct ksmbd_share_config_response *resp;
|
struct ksmbd_share_config_response *resp;
|
||||||
struct ksmbd_share_config *share = NULL;
|
struct ksmbd_share_config *share = NULL;
|
||||||
|
@ -133,6 +135,19 @@ static struct ksmbd_share_config *share_config_request(char *name)
|
||||||
if (resp->flags == KSMBD_SHARE_FLAG_INVALID)
|
if (resp->flags == KSMBD_SHARE_FLAG_INVALID)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (*resp->share_name) {
|
||||||
|
char *cf_resp_name;
|
||||||
|
bool equal;
|
||||||
|
|
||||||
|
cf_resp_name = ksmbd_casefold_sharename(um, resp->share_name);
|
||||||
|
if (IS_ERR(cf_resp_name))
|
||||||
|
goto out;
|
||||||
|
equal = !strcmp(cf_resp_name, name);
|
||||||
|
kfree(cf_resp_name);
|
||||||
|
if (!equal)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL);
|
share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL);
|
||||||
if (!share)
|
if (!share)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -190,20 +205,11 @@ out:
|
||||||
return share;
|
return share;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void strtolower(char *share_name)
|
struct ksmbd_share_config *ksmbd_share_config_get(struct unicode_map *um,
|
||||||
{
|
const char *name)
|
||||||
while (*share_name) {
|
|
||||||
*share_name = tolower(*share_name);
|
|
||||||
share_name++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ksmbd_share_config *ksmbd_share_config_get(char *name)
|
|
||||||
{
|
{
|
||||||
struct ksmbd_share_config *share;
|
struct ksmbd_share_config *share;
|
||||||
|
|
||||||
strtolower(name);
|
|
||||||
|
|
||||||
down_read(&shares_table_lock);
|
down_read(&shares_table_lock);
|
||||||
share = __share_lookup(name);
|
share = __share_lookup(name);
|
||||||
if (share)
|
if (share)
|
||||||
|
@ -212,7 +218,7 @@ struct ksmbd_share_config *ksmbd_share_config_get(char *name)
|
||||||
|
|
||||||
if (share)
|
if (share)
|
||||||
return share;
|
return share;
|
||||||
return share_config_request(name);
|
return share_config_request(um, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
|
bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/hashtable.h>
|
#include <linux/hashtable.h>
|
||||||
#include <linux/path.h>
|
#include <linux/path.h>
|
||||||
|
#include <linux/unicode.h>
|
||||||
|
|
||||||
struct ksmbd_share_config {
|
struct ksmbd_share_config {
|
||||||
char *name;
|
char *name;
|
||||||
|
@ -74,7 +75,8 @@ static inline void ksmbd_share_config_put(struct ksmbd_share_config *share)
|
||||||
__ksmbd_share_config_put(share);
|
__ksmbd_share_config_put(share);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ksmbd_share_config *ksmbd_share_config_get(char *name);
|
struct ksmbd_share_config *ksmbd_share_config_get(struct unicode_map *um,
|
||||||
|
const char *name);
|
||||||
bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
|
bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
#endif /* __SHARE_CONFIG_MANAGEMENT_H__ */
|
#endif /* __SHARE_CONFIG_MANAGEMENT_H__ */
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
struct ksmbd_tree_conn_status
|
struct ksmbd_tree_conn_status
|
||||||
ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
char *share_name)
|
const char *share_name)
|
||||||
{
|
{
|
||||||
struct ksmbd_tree_conn_status status = {-ENOENT, NULL};
|
struct ksmbd_tree_conn_status status = {-ENOENT, NULL};
|
||||||
struct ksmbd_tree_connect_response *resp = NULL;
|
struct ksmbd_tree_connect_response *resp = NULL;
|
||||||
|
@ -26,7 +26,7 @@ ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
struct sockaddr *peer_addr;
|
struct sockaddr *peer_addr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
sc = ksmbd_share_config_get(share_name);
|
sc = ksmbd_share_config_get(conn->um, share_name);
|
||||||
if (!sc)
|
if (!sc)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
struct ksmbd_share_config *new_sc;
|
struct ksmbd_share_config *new_sc;
|
||||||
|
|
||||||
ksmbd_share_config_del(sc);
|
ksmbd_share_config_del(sc);
|
||||||
new_sc = ksmbd_share_config_get(share_name);
|
new_sc = ksmbd_share_config_get(conn->um, share_name);
|
||||||
if (!new_sc) {
|
if (!new_sc) {
|
||||||
pr_err("Failed to update stale share config\n");
|
pr_err("Failed to update stale share config\n");
|
||||||
status.ret = -ESTALE;
|
status.ret = -ESTALE;
|
||||||
|
|
|
@ -42,7 +42,7 @@ struct ksmbd_session;
|
||||||
|
|
||||||
struct ksmbd_tree_conn_status
|
struct ksmbd_tree_conn_status
|
||||||
ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
char *share_name);
|
const char *share_name);
|
||||||
|
|
||||||
int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
|
int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
|
||||||
struct ksmbd_tree_connect *tree_conn);
|
struct ksmbd_tree_connect *tree_conn);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/xattr.h>
|
#include <linux/xattr.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <linux/unicode.h>
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "smb_common.h"
|
#include "smb_common.h"
|
||||||
|
@ -159,7 +160,7 @@ out:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char *convert_to_nt_pathname(struct ksmbd_share_config *share,
|
char *convert_to_nt_pathname(struct ksmbd_share_config *share,
|
||||||
struct path *path)
|
const struct path *path)
|
||||||
{
|
{
|
||||||
char *pathname, *ab_pathname, *nt_pathname;
|
char *pathname, *ab_pathname, *nt_pathname;
|
||||||
int share_path_len = share->path_sz;
|
int share_path_len = share->path_sz;
|
||||||
|
@ -226,26 +227,53 @@ void ksmbd_conv_path_to_windows(char *path)
|
||||||
strreplace(path, '/', '\\');
|
strreplace(path, '/', '\\');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *ksmbd_casefold_sharename(struct unicode_map *um, const char *name)
|
||||||
|
{
|
||||||
|
char *cf_name;
|
||||||
|
int cf_len;
|
||||||
|
|
||||||
|
cf_name = kzalloc(KSMBD_REQ_MAX_SHARE_NAME, GFP_KERNEL);
|
||||||
|
if (!cf_name)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_UNICODE) && um) {
|
||||||
|
const struct qstr q_name = {.name = name, .len = strlen(name)};
|
||||||
|
|
||||||
|
cf_len = utf8_casefold(um, &q_name, cf_name,
|
||||||
|
KSMBD_REQ_MAX_SHARE_NAME);
|
||||||
|
if (cf_len < 0)
|
||||||
|
goto out_ascii;
|
||||||
|
|
||||||
|
return cf_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_ascii:
|
||||||
|
cf_len = strscpy(cf_name, name, KSMBD_REQ_MAX_SHARE_NAME);
|
||||||
|
if (cf_len < 0) {
|
||||||
|
kfree(cf_name);
|
||||||
|
return ERR_PTR(-E2BIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; *cf_name; ++cf_name)
|
||||||
|
*cf_name = isascii(*cf_name) ? tolower(*cf_name) : *cf_name;
|
||||||
|
return cf_name - cf_len;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ksmbd_extract_sharename() - get share name from tree connect request
|
* ksmbd_extract_sharename() - get share name from tree connect request
|
||||||
* @treename: buffer containing tree name and share name
|
* @treename: buffer containing tree name and share name
|
||||||
*
|
*
|
||||||
* Return: share name on success, otherwise error
|
* Return: share name on success, otherwise error
|
||||||
*/
|
*/
|
||||||
char *ksmbd_extract_sharename(char *treename)
|
char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename)
|
||||||
{
|
{
|
||||||
char *name = treename;
|
const char *name = treename, *pos = strrchr(name, '\\');
|
||||||
char *dst;
|
|
||||||
char *pos = strrchr(name, '\\');
|
|
||||||
|
|
||||||
if (pos)
|
if (pos)
|
||||||
name = (pos + 1);
|
name = (pos + 1);
|
||||||
|
|
||||||
/* caller has to free the memory */
|
/* caller has to free the memory */
|
||||||
dst = kstrdup(name, GFP_KERNEL);
|
return ksmbd_casefold_sharename(um, name);
|
||||||
if (!dst)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
return dst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,12 +15,13 @@ int match_pattern(const char *str, size_t len, const char *pattern);
|
||||||
int ksmbd_validate_filename(char *filename);
|
int ksmbd_validate_filename(char *filename);
|
||||||
int parse_stream_name(char *filename, char **stream_name, int *s_type);
|
int parse_stream_name(char *filename, char **stream_name, int *s_type);
|
||||||
char *convert_to_nt_pathname(struct ksmbd_share_config *share,
|
char *convert_to_nt_pathname(struct ksmbd_share_config *share,
|
||||||
struct path *path);
|
const struct path *path);
|
||||||
int get_nlink(struct kstat *st);
|
int get_nlink(struct kstat *st);
|
||||||
void ksmbd_conv_path_to_unix(char *path);
|
void ksmbd_conv_path_to_unix(char *path);
|
||||||
void ksmbd_strip_last_slash(char *path);
|
void ksmbd_strip_last_slash(char *path);
|
||||||
void ksmbd_conv_path_to_windows(char *path);
|
void ksmbd_conv_path_to_windows(char *path);
|
||||||
char *ksmbd_extract_sharename(char *treename);
|
char *ksmbd_casefold_sharename(struct unicode_map *um, const char *name);
|
||||||
|
char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename);
|
||||||
char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name);
|
char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name);
|
||||||
|
|
||||||
#define KSMBD_DIR_INFO_ALIGNMENT 8
|
#define KSMBD_DIR_INFO_ALIGNMENT 8
|
||||||
|
|
|
@ -345,6 +345,8 @@ int ndr_encode_posix_acl(struct ndr *n,
|
||||||
{
|
{
|
||||||
unsigned int ref_id = 0x00020000;
|
unsigned int ref_id = 0x00020000;
|
||||||
int ret;
|
int ret;
|
||||||
|
vfsuid_t vfsuid;
|
||||||
|
vfsgid_t vfsgid;
|
||||||
|
|
||||||
n->offset = 0;
|
n->offset = 0;
|
||||||
n->length = 1024;
|
n->length = 1024;
|
||||||
|
@ -372,10 +374,12 @@ int ndr_encode_posix_acl(struct ndr *n,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = ndr_write_int64(n, from_kuid(&init_user_ns, i_uid_into_mnt(user_ns, inode)));
|
vfsuid = i_uid_into_vfsuid(user_ns, inode);
|
||||||
|
ret = ndr_write_int64(n, from_kuid(&init_user_ns, vfsuid_into_kuid(vfsuid)));
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ret = ndr_write_int64(n, from_kgid(&init_user_ns, i_gid_into_mnt(user_ns, inode)));
|
vfsgid = i_gid_into_vfsgid(user_ns, inode);
|
||||||
|
ret = ndr_write_int64(n, from_kgid(&init_user_ns, vfsgid_into_kgid(vfsgid)));
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ret = ndr_write_int32(n, inode->i_mode);
|
ret = ndr_write_int32(n, inode->i_mode);
|
||||||
|
|
|
@ -1609,12 +1609,18 @@ void create_posix_rsp_buf(char *cc, struct ksmbd_file *fp)
|
||||||
struct create_posix_rsp *buf;
|
struct create_posix_rsp *buf;
|
||||||
struct inode *inode = file_inode(fp->filp);
|
struct inode *inode = file_inode(fp->filp);
|
||||||
struct user_namespace *user_ns = file_mnt_user_ns(fp->filp);
|
struct user_namespace *user_ns = file_mnt_user_ns(fp->filp);
|
||||||
|
vfsuid_t vfsuid = i_uid_into_vfsuid(user_ns, inode);
|
||||||
|
vfsgid_t vfsgid = i_gid_into_vfsgid(user_ns, inode);
|
||||||
|
|
||||||
buf = (struct create_posix_rsp *)cc;
|
buf = (struct create_posix_rsp *)cc;
|
||||||
memset(buf, 0, sizeof(struct create_posix_rsp));
|
memset(buf, 0, sizeof(struct create_posix_rsp));
|
||||||
buf->ccontext.DataOffset = cpu_to_le16(offsetof
|
buf->ccontext.DataOffset = cpu_to_le16(offsetof
|
||||||
(struct create_posix_rsp, nlink));
|
(struct create_posix_rsp, nlink));
|
||||||
buf->ccontext.DataLength = cpu_to_le32(52);
|
/*
|
||||||
|
* DataLength = nlink(4) + reparse_tag(4) + mode(4) +
|
||||||
|
* domain sid(28) + unix group sid(16).
|
||||||
|
*/
|
||||||
|
buf->ccontext.DataLength = cpu_to_le32(56);
|
||||||
buf->ccontext.NameOffset = cpu_to_le16(offsetof
|
buf->ccontext.NameOffset = cpu_to_le16(offsetof
|
||||||
(struct create_posix_rsp, Name));
|
(struct create_posix_rsp, Name));
|
||||||
buf->ccontext.NameLength = cpu_to_le16(POSIX_CTXT_DATA_LEN);
|
buf->ccontext.NameLength = cpu_to_le16(POSIX_CTXT_DATA_LEN);
|
||||||
|
@ -1638,13 +1644,18 @@ void create_posix_rsp_buf(char *cc, struct ksmbd_file *fp)
|
||||||
|
|
||||||
buf->nlink = cpu_to_le32(inode->i_nlink);
|
buf->nlink = cpu_to_le32(inode->i_nlink);
|
||||||
buf->reparse_tag = cpu_to_le32(fp->volatile_id);
|
buf->reparse_tag = cpu_to_le32(fp->volatile_id);
|
||||||
buf->mode = cpu_to_le32(inode->i_mode);
|
buf->mode = cpu_to_le32(inode->i_mode & 0777);
|
||||||
id_to_sid(from_kuid_munged(&init_user_ns,
|
/*
|
||||||
i_uid_into_mnt(user_ns, inode)),
|
* SidBuffer(44) contain two sids(Domain sid(28), UNIX group sid(16)).
|
||||||
SIDNFS_USER, (struct smb_sid *)&buf->SidBuffer[0]);
|
* Domain sid(28) = revision(1) + num_subauth(1) + authority(6) +
|
||||||
id_to_sid(from_kgid_munged(&init_user_ns,
|
* sub_auth(4 * 4(num_subauth)) + RID(4).
|
||||||
i_gid_into_mnt(user_ns, inode)),
|
* UNIX group id(16) = revision(1) + num_subauth(1) + authority(6) +
|
||||||
SIDNFS_GROUP, (struct smb_sid *)&buf->SidBuffer[20]);
|
* sub_auth(4 * 1(num_subauth)) + RID(4).
|
||||||
|
*/
|
||||||
|
id_to_sid(from_kuid_munged(&init_user_ns, vfsuid_into_kuid(vfsuid)),
|
||||||
|
SIDOWNER, (struct smb_sid *)&buf->SidBuffer[0]);
|
||||||
|
id_to_sid(from_kgid_munged(&init_user_ns, vfsgid_into_kgid(vfsgid)),
|
||||||
|
SIDUNIX_GROUP, (struct smb_sid *)&buf->SidBuffer[28]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -235,10 +235,8 @@ send:
|
||||||
if (work->sess && work->sess->enc && work->encrypted &&
|
if (work->sess && work->sess->enc && work->encrypted &&
|
||||||
conn->ops->encrypt_resp) {
|
conn->ops->encrypt_resp) {
|
||||||
rc = conn->ops->encrypt_resp(work);
|
rc = conn->ops->encrypt_resp(work);
|
||||||
if (rc < 0) {
|
if (rc < 0)
|
||||||
conn->ops->set_rsp_status(work, STATUS_DATA_ERROR);
|
conn->ops->set_rsp_status(work, STATUS_DATA_ERROR);
|
||||||
goto send;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ksmbd_conn_write(work);
|
ksmbd_conn_write(work);
|
||||||
|
|
|
@ -925,7 +925,7 @@ static void decode_encrypt_ctxt(struct ksmbd_conn *conn,
|
||||||
*
|
*
|
||||||
* Return: true if connection should be encrypted, else false
|
* Return: true if connection should be encrypted, else false
|
||||||
*/
|
*/
|
||||||
static bool smb3_encryption_negotiated(struct ksmbd_conn *conn)
|
bool smb3_encryption_negotiated(struct ksmbd_conn *conn)
|
||||||
{
|
{
|
||||||
if (!conn->ops->generate_encryptionkey)
|
if (!conn->ops->generate_encryptionkey)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1883,7 +1883,7 @@ int smb2_tree_connect(struct ksmbd_work *work)
|
||||||
goto out_err1;
|
goto out_err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = ksmbd_extract_sharename(treename);
|
name = ksmbd_extract_sharename(conn->um, treename);
|
||||||
if (IS_ERR(name)) {
|
if (IS_ERR(name)) {
|
||||||
status.ret = KSMBD_TREE_CONN_STATUS_ERROR;
|
status.ret = KSMBD_TREE_CONN_STATUS_ERROR;
|
||||||
goto out_err1;
|
goto out_err1;
|
||||||
|
@ -2185,7 +2185,7 @@ out:
|
||||||
* Return: 0 on success, otherwise error
|
* Return: 0 on success, otherwise error
|
||||||
*/
|
*/
|
||||||
static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
|
static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
|
||||||
struct path *path)
|
const struct path *path)
|
||||||
{
|
{
|
||||||
struct user_namespace *user_ns = mnt_user_ns(path->mnt);
|
struct user_namespace *user_ns = mnt_user_ns(path->mnt);
|
||||||
char *attr_name = NULL, *value;
|
char *attr_name = NULL, *value;
|
||||||
|
@ -2272,7 +2272,7 @@ next:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline int smb2_set_stream_name_xattr(struct path *path,
|
static noinline int smb2_set_stream_name_xattr(const struct path *path,
|
||||||
struct ksmbd_file *fp,
|
struct ksmbd_file *fp,
|
||||||
char *stream_name, int s_type)
|
char *stream_name, int s_type)
|
||||||
{
|
{
|
||||||
|
@ -2311,7 +2311,7 @@ static noinline int smb2_set_stream_name_xattr(struct path *path,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smb2_remove_smb_xattrs(struct path *path)
|
static int smb2_remove_smb_xattrs(const struct path *path)
|
||||||
{
|
{
|
||||||
struct user_namespace *user_ns = mnt_user_ns(path->mnt);
|
struct user_namespace *user_ns = mnt_user_ns(path->mnt);
|
||||||
char *name, *xattr_list = NULL;
|
char *name, *xattr_list = NULL;
|
||||||
|
@ -2345,7 +2345,7 @@ out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smb2_create_truncate(struct path *path)
|
static int smb2_create_truncate(const struct path *path)
|
||||||
{
|
{
|
||||||
int rc = vfs_truncate(path, 0);
|
int rc = vfs_truncate(path, 0);
|
||||||
|
|
||||||
|
@ -2364,7 +2364,7 @@ static int smb2_create_truncate(struct path *path)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, struct path *path,
|
static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, const struct path *path,
|
||||||
struct ksmbd_file *fp)
|
struct ksmbd_file *fp)
|
||||||
{
|
{
|
||||||
struct xattr_dos_attrib da = {0};
|
struct xattr_dos_attrib da = {0};
|
||||||
|
@ -2387,7 +2387,7 @@ static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, struct path *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smb2_update_xattrs(struct ksmbd_tree_connect *tcon,
|
static void smb2_update_xattrs(struct ksmbd_tree_connect *tcon,
|
||||||
struct path *path, struct ksmbd_file *fp)
|
const struct path *path, struct ksmbd_file *fp)
|
||||||
{
|
{
|
||||||
struct xattr_dos_attrib da;
|
struct xattr_dos_attrib da;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -2447,7 +2447,7 @@ static int smb2_creat(struct ksmbd_work *work, struct path *path, char *name,
|
||||||
|
|
||||||
static int smb2_create_sd_buffer(struct ksmbd_work *work,
|
static int smb2_create_sd_buffer(struct ksmbd_work *work,
|
||||||
struct smb2_create_req *req,
|
struct smb2_create_req *req,
|
||||||
struct path *path)
|
const struct path *path)
|
||||||
{
|
{
|
||||||
struct create_context *context;
|
struct create_context *context;
|
||||||
struct create_sd_buf_req *sd_buf;
|
struct create_sd_buf_req *sd_buf;
|
||||||
|
@ -2477,8 +2477,11 @@ static void ksmbd_acls_fattr(struct smb_fattr *fattr,
|
||||||
struct user_namespace *mnt_userns,
|
struct user_namespace *mnt_userns,
|
||||||
struct inode *inode)
|
struct inode *inode)
|
||||||
{
|
{
|
||||||
fattr->cf_uid = i_uid_into_mnt(mnt_userns, inode);
|
vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
|
||||||
fattr->cf_gid = i_gid_into_mnt(mnt_userns, inode);
|
vfsgid_t vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
|
||||||
|
|
||||||
|
fattr->cf_uid = vfsuid_into_kuid(vfsuid);
|
||||||
|
fattr->cf_gid = vfsgid_into_kgid(vfsgid);
|
||||||
fattr->cf_mode = inode->i_mode;
|
fattr->cf_mode = inode->i_mode;
|
||||||
fattr->cf_acls = NULL;
|
fattr->cf_acls = NULL;
|
||||||
fattr->cf_dacls = NULL;
|
fattr->cf_dacls = NULL;
|
||||||
|
@ -2761,7 +2764,6 @@ int smb2_open(struct ksmbd_work *work)
|
||||||
} else {
|
} else {
|
||||||
file_present = true;
|
file_present = true;
|
||||||
user_ns = mnt_user_ns(path.mnt);
|
user_ns = mnt_user_ns(path.mnt);
|
||||||
generic_fillattr(user_ns, d_inode(path.dentry), &stat);
|
|
||||||
}
|
}
|
||||||
if (stream_name) {
|
if (stream_name) {
|
||||||
if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) {
|
if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) {
|
||||||
|
@ -2770,7 +2772,8 @@ int smb2_open(struct ksmbd_work *work)
|
||||||
rsp->hdr.Status = STATUS_NOT_A_DIRECTORY;
|
rsp->hdr.Status = STATUS_NOT_A_DIRECTORY;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (S_ISDIR(stat.mode) && s_type == DATA_STREAM) {
|
if (file_present && S_ISDIR(d_inode(path.dentry)->i_mode) &&
|
||||||
|
s_type == DATA_STREAM) {
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY;
|
rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY;
|
||||||
}
|
}
|
||||||
|
@ -2787,7 +2790,8 @@ int smb2_open(struct ksmbd_work *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_present && req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE &&
|
if (file_present && req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE &&
|
||||||
S_ISDIR(stat.mode) && !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {
|
S_ISDIR(d_inode(path.dentry)->i_mode) &&
|
||||||
|
!(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {
|
||||||
ksmbd_debug(SMB, "open() argument is a directory: %s, %x\n",
|
ksmbd_debug(SMB, "open() argument is a directory: %s, %x\n",
|
||||||
name, req->CreateOptions);
|
name, req->CreateOptions);
|
||||||
rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY;
|
rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY;
|
||||||
|
@ -2797,7 +2801,7 @@ int smb2_open(struct ksmbd_work *work)
|
||||||
|
|
||||||
if (file_present && (req->CreateOptions & FILE_DIRECTORY_FILE_LE) &&
|
if (file_present && (req->CreateOptions & FILE_DIRECTORY_FILE_LE) &&
|
||||||
!(req->CreateDisposition == FILE_CREATE_LE) &&
|
!(req->CreateDisposition == FILE_CREATE_LE) &&
|
||||||
!S_ISDIR(stat.mode)) {
|
!S_ISDIR(d_inode(path.dentry)->i_mode)) {
|
||||||
rsp->hdr.Status = STATUS_NOT_A_DIRECTORY;
|
rsp->hdr.Status = STATUS_NOT_A_DIRECTORY;
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
@ -3561,17 +3565,22 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,
|
||||||
posix_info->AllocationSize = cpu_to_le64(ksmbd_kstat->kstat->blocks << 9);
|
posix_info->AllocationSize = cpu_to_le64(ksmbd_kstat->kstat->blocks << 9);
|
||||||
posix_info->DeviceId = cpu_to_le32(ksmbd_kstat->kstat->rdev);
|
posix_info->DeviceId = cpu_to_le32(ksmbd_kstat->kstat->rdev);
|
||||||
posix_info->HardLinks = cpu_to_le32(ksmbd_kstat->kstat->nlink);
|
posix_info->HardLinks = cpu_to_le32(ksmbd_kstat->kstat->nlink);
|
||||||
posix_info->Mode = cpu_to_le32(ksmbd_kstat->kstat->mode);
|
posix_info->Mode = cpu_to_le32(ksmbd_kstat->kstat->mode & 0777);
|
||||||
posix_info->Inode = cpu_to_le64(ksmbd_kstat->kstat->ino);
|
posix_info->Inode = cpu_to_le64(ksmbd_kstat->kstat->ino);
|
||||||
posix_info->DosAttributes =
|
posix_info->DosAttributes =
|
||||||
S_ISDIR(ksmbd_kstat->kstat->mode) ?
|
S_ISDIR(ksmbd_kstat->kstat->mode) ?
|
||||||
FILE_ATTRIBUTE_DIRECTORY_LE : FILE_ATTRIBUTE_ARCHIVE_LE;
|
FILE_ATTRIBUTE_DIRECTORY_LE : FILE_ATTRIBUTE_ARCHIVE_LE;
|
||||||
if (d_info->hide_dot_file && d_info->name[0] == '.')
|
if (d_info->hide_dot_file && d_info->name[0] == '.')
|
||||||
posix_info->DosAttributes |= FILE_ATTRIBUTE_HIDDEN_LE;
|
posix_info->DosAttributes |= FILE_ATTRIBUTE_HIDDEN_LE;
|
||||||
|
/*
|
||||||
|
* SidBuffer(32) contain two sids(Domain sid(16), UNIX group sid(16)).
|
||||||
|
* UNIX sid(16) = revision(1) + num_subauth(1) + authority(6) +
|
||||||
|
* sub_auth(4 * 1(num_subauth)) + RID(4).
|
||||||
|
*/
|
||||||
id_to_sid(from_kuid_munged(&init_user_ns, ksmbd_kstat->kstat->uid),
|
id_to_sid(from_kuid_munged(&init_user_ns, ksmbd_kstat->kstat->uid),
|
||||||
SIDNFS_USER, (struct smb_sid *)&posix_info->SidBuffer[0]);
|
SIDUNIX_USER, (struct smb_sid *)&posix_info->SidBuffer[0]);
|
||||||
id_to_sid(from_kgid_munged(&init_user_ns, ksmbd_kstat->kstat->gid),
|
id_to_sid(from_kgid_munged(&init_user_ns, ksmbd_kstat->kstat->gid),
|
||||||
SIDNFS_GROUP, (struct smb_sid *)&posix_info->SidBuffer[20]);
|
SIDUNIX_GROUP, (struct smb_sid *)&posix_info->SidBuffer[16]);
|
||||||
memcpy(posix_info->name, conv_name, conv_len);
|
memcpy(posix_info->name, conv_name, conv_len);
|
||||||
posix_info->name_len = cpu_to_le32(conv_len);
|
posix_info->name_len = cpu_to_le32(conv_len);
|
||||||
posix_info->NextEntryOffset = cpu_to_le32(next_entry_offset);
|
posix_info->NextEntryOffset = cpu_to_le32(next_entry_offset);
|
||||||
|
@ -3806,11 +3815,6 @@ static bool __query_dir(struct dir_context *ctx, const char *name, int namlen,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restart_ctx(struct dir_context *ctx)
|
|
||||||
{
|
|
||||||
ctx->pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int verify_info_level(int info_level)
|
static int verify_info_level(int info_level)
|
||||||
{
|
{
|
||||||
switch (info_level) {
|
switch (info_level) {
|
||||||
|
@ -3892,8 +3896,7 @@ int smb2_query_dir(struct ksmbd_work *work)
|
||||||
inode_permission(file_mnt_user_ns(dir_fp->filp),
|
inode_permission(file_mnt_user_ns(dir_fp->filp),
|
||||||
file_inode(dir_fp->filp),
|
file_inode(dir_fp->filp),
|
||||||
MAY_READ | MAY_EXEC)) {
|
MAY_READ | MAY_EXEC)) {
|
||||||
pr_err("no right to enumerate directory (%pd)\n",
|
pr_err("no right to enumerate directory (%pD)\n", dir_fp->filp);
|
||||||
dir_fp->filp->f_path.dentry);
|
|
||||||
rc = -EACCES;
|
rc = -EACCES;
|
||||||
goto err_out2;
|
goto err_out2;
|
||||||
}
|
}
|
||||||
|
@ -3919,7 +3922,6 @@ int smb2_query_dir(struct ksmbd_work *work)
|
||||||
if (srch_flag & SMB2_REOPEN || srch_flag & SMB2_RESTART_SCANS) {
|
if (srch_flag & SMB2_REOPEN || srch_flag & SMB2_RESTART_SCANS) {
|
||||||
ksmbd_debug(SMB, "Restart directory scan\n");
|
ksmbd_debug(SMB, "Restart directory scan\n");
|
||||||
generic_file_llseek(dir_fp->filp, 0, SEEK_SET);
|
generic_file_llseek(dir_fp->filp, 0, SEEK_SET);
|
||||||
restart_ctx(&dir_fp->readdir_data.ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&d_info, 0, sizeof(struct ksmbd_dir_info));
|
memset(&d_info, 0, sizeof(struct ksmbd_dir_info));
|
||||||
|
@ -3966,11 +3968,9 @@ int smb2_query_dir(struct ksmbd_work *work)
|
||||||
*/
|
*/
|
||||||
if (!d_info.out_buf_len && !d_info.num_entry)
|
if (!d_info.out_buf_len && !d_info.num_entry)
|
||||||
goto no_buf_len;
|
goto no_buf_len;
|
||||||
if (rc == 0)
|
if (rc > 0 || rc == -ENOSPC)
|
||||||
restart_ctx(&dir_fp->readdir_data.ctx);
|
|
||||||
if (rc == -ENOSPC)
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
if (rc)
|
else if (rc)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
d_info.wptr = d_info.rptr;
|
d_info.wptr = d_info.rptr;
|
||||||
|
@ -4027,6 +4027,8 @@ err_out2:
|
||||||
rsp->hdr.Status = STATUS_NO_MEMORY;
|
rsp->hdr.Status = STATUS_NO_MEMORY;
|
||||||
else if (rc == -EFAULT)
|
else if (rc == -EFAULT)
|
||||||
rsp->hdr.Status = STATUS_INVALID_INFO_CLASS;
|
rsp->hdr.Status = STATUS_INVALID_INFO_CLASS;
|
||||||
|
else if (rc == -EIO)
|
||||||
|
rsp->hdr.Status = STATUS_FILE_CORRUPT_ERROR;
|
||||||
if (!rsp->hdr.Status)
|
if (!rsp->hdr.Status)
|
||||||
rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
|
rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
|
||||||
|
|
||||||
|
@ -4156,7 +4158,7 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||||
int rc, name_len, value_len, xattr_list_len, idx;
|
int rc, name_len, value_len, xattr_list_len, idx;
|
||||||
ssize_t buf_free_len, alignment_bytes, next_offset, rsp_data_cnt = 0;
|
ssize_t buf_free_len, alignment_bytes, next_offset, rsp_data_cnt = 0;
|
||||||
struct smb2_ea_info_req *ea_req = NULL;
|
struct smb2_ea_info_req *ea_req = NULL;
|
||||||
struct path *path;
|
const struct path *path;
|
||||||
struct user_namespace *user_ns = file_mnt_user_ns(fp->filp);
|
struct user_namespace *user_ns = file_mnt_user_ns(fp->filp);
|
||||||
|
|
||||||
if (!(fp->daccess & FILE_READ_EA_LE)) {
|
if (!(fp->daccess & FILE_READ_EA_LE)) {
|
||||||
|
@ -4493,7 +4495,7 @@ static void get_file_stream_info(struct ksmbd_work *work,
|
||||||
struct smb2_file_stream_info *file_info;
|
struct smb2_file_stream_info *file_info;
|
||||||
char *stream_name, *xattr_list = NULL, *stream_buf;
|
char *stream_name, *xattr_list = NULL, *stream_buf;
|
||||||
struct kstat stat;
|
struct kstat stat;
|
||||||
struct path *path = &fp->filp->f_path;
|
const struct path *path = &fp->filp->f_path;
|
||||||
ssize_t xattr_list_len;
|
ssize_t xattr_list_len;
|
||||||
int nbytes = 0, streamlen, stream_name_len, next, idx = 0;
|
int nbytes = 0, streamlen, stream_name_len, next, idx = 0;
|
||||||
int buf_free_len;
|
int buf_free_len;
|
||||||
|
@ -4718,7 +4720,11 @@ static int find_file_posix_info(struct smb2_query_info_rsp *rsp,
|
||||||
{
|
{
|
||||||
struct smb311_posix_qinfo *file_info;
|
struct smb311_posix_qinfo *file_info;
|
||||||
struct inode *inode = file_inode(fp->filp);
|
struct inode *inode = file_inode(fp->filp);
|
||||||
|
struct user_namespace *user_ns = file_mnt_user_ns(fp->filp);
|
||||||
|
vfsuid_t vfsuid = i_uid_into_vfsuid(user_ns, inode);
|
||||||
|
vfsgid_t vfsgid = i_gid_into_vfsgid(user_ns, inode);
|
||||||
u64 time;
|
u64 time;
|
||||||
|
int out_buf_len = sizeof(struct smb311_posix_qinfo) + 32;
|
||||||
|
|
||||||
file_info = (struct smb311_posix_qinfo *)rsp->Buffer;
|
file_info = (struct smb311_posix_qinfo *)rsp->Buffer;
|
||||||
file_info->CreationTime = cpu_to_le64(fp->create_time);
|
file_info->CreationTime = cpu_to_le64(fp->create_time);
|
||||||
|
@ -4733,12 +4739,22 @@ static int find_file_posix_info(struct smb2_query_info_rsp *rsp,
|
||||||
file_info->EndOfFile = cpu_to_le64(inode->i_size);
|
file_info->EndOfFile = cpu_to_le64(inode->i_size);
|
||||||
file_info->AllocationSize = cpu_to_le64(inode->i_blocks << 9);
|
file_info->AllocationSize = cpu_to_le64(inode->i_blocks << 9);
|
||||||
file_info->HardLinks = cpu_to_le32(inode->i_nlink);
|
file_info->HardLinks = cpu_to_le32(inode->i_nlink);
|
||||||
file_info->Mode = cpu_to_le32(inode->i_mode);
|
file_info->Mode = cpu_to_le32(inode->i_mode & 0777);
|
||||||
file_info->DeviceId = cpu_to_le32(inode->i_rdev);
|
file_info->DeviceId = cpu_to_le32(inode->i_rdev);
|
||||||
rsp->OutputBufferLength =
|
|
||||||
cpu_to_le32(sizeof(struct smb311_posix_qinfo));
|
/*
|
||||||
inc_rfc1001_len(rsp_org, sizeof(struct smb311_posix_qinfo));
|
* Sids(32) contain two sids(Domain sid(16), UNIX group sid(16)).
|
||||||
return 0;
|
* UNIX sid(16) = revision(1) + num_subauth(1) + authority(6) +
|
||||||
|
* sub_auth(4 * 1(num_subauth)) + RID(4).
|
||||||
|
*/
|
||||||
|
id_to_sid(from_kuid_munged(&init_user_ns, vfsuid_into_kuid(vfsuid)),
|
||||||
|
SIDUNIX_USER, (struct smb_sid *)&file_info->Sids[0]);
|
||||||
|
id_to_sid(from_kgid_munged(&init_user_ns, vfsgid_into_kgid(vfsgid)),
|
||||||
|
SIDUNIX_GROUP, (struct smb_sid *)&file_info->Sids[16]);
|
||||||
|
|
||||||
|
rsp->OutputBufferLength = cpu_to_le32(out_buf_len);
|
||||||
|
inc_rfc1001_len(rsp_org, out_buf_len);
|
||||||
|
return out_buf_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smb2_get_info_file(struct ksmbd_work *work,
|
static int smb2_get_info_file(struct ksmbd_work *work,
|
||||||
|
@ -4858,8 +4874,8 @@ static int smb2_get_info_file(struct ksmbd_work *work,
|
||||||
pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n");
|
pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n");
|
||||||
rc = -EOPNOTSUPP;
|
rc = -EOPNOTSUPP;
|
||||||
} else {
|
} else {
|
||||||
rc = find_file_posix_info(rsp, fp, work->response_buf);
|
file_infoclass_size = find_file_posix_info(rsp, fp,
|
||||||
file_infoclass_size = sizeof(struct smb311_posix_qinfo);
|
work->response_buf);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -5411,7 +5427,7 @@ static int smb2_rename(struct ksmbd_work *work,
|
||||||
if (!pathname)
|
if (!pathname)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
abs_oldname = d_path(&fp->filp->f_path, pathname, PATH_MAX);
|
abs_oldname = file_path(fp->filp, pathname, PATH_MAX);
|
||||||
if (IS_ERR(abs_oldname)) {
|
if (IS_ERR(abs_oldname)) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -5546,7 +5562,7 @@ static int smb2_create_link(struct ksmbd_work *work,
|
||||||
}
|
}
|
||||||
|
|
||||||
ksmbd_debug(SMB, "link name is %s\n", link_name);
|
ksmbd_debug(SMB, "link name is %s\n", link_name);
|
||||||
target_name = d_path(&filp->f_path, pathname, PATH_MAX);
|
target_name = file_path(filp, pathname, PATH_MAX);
|
||||||
if (IS_ERR(target_name)) {
|
if (IS_ERR(target_name)) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -6264,8 +6280,8 @@ int smb2_read(struct ksmbd_work *work)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ksmbd_debug(SMB, "filename %pd, offset %lld, len %zu\n",
|
ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n",
|
||||||
fp->filp->f_path.dentry, offset, length);
|
fp->filp, offset, length);
|
||||||
|
|
||||||
work->aux_payload_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO);
|
work->aux_payload_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO);
|
||||||
if (!work->aux_payload_buf) {
|
if (!work->aux_payload_buf) {
|
||||||
|
@ -6529,8 +6545,8 @@ int smb2_write(struct ksmbd_work *work)
|
||||||
data_buf = (char *)(((char *)&req->hdr.ProtocolId) +
|
data_buf = (char *)(((char *)&req->hdr.ProtocolId) +
|
||||||
le16_to_cpu(req->DataOffset));
|
le16_to_cpu(req->DataOffset));
|
||||||
|
|
||||||
ksmbd_debug(SMB, "filename %pd, offset %lld, len %zu\n",
|
ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n",
|
||||||
fp->filp->f_path.dentry, offset, length);
|
fp->filp, offset, length);
|
||||||
err = ksmbd_vfs_write(work, fp, data_buf, length, &offset,
|
err = ksmbd_vfs_write(work, fp, data_buf, length, &offset,
|
||||||
writethrough, &nbytes);
|
writethrough, &nbytes);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -7641,11 +7657,16 @@ int smb2_ioctl(struct ksmbd_work *work)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_buf_len < sizeof(struct validate_negotiate_info_req))
|
if (in_buf_len < offsetof(struct validate_negotiate_info_req,
|
||||||
return -EINVAL;
|
Dialects)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (out_buf_len < sizeof(struct validate_negotiate_info_rsp))
|
if (out_buf_len < sizeof(struct validate_negotiate_info_rsp)) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = fsctl_validate_negotiate_info(conn,
|
ret = fsctl_validate_negotiate_info(conn,
|
||||||
(struct validate_negotiate_info_req *)&req->Buffer[0],
|
(struct validate_negotiate_info_req *)&req->Buffer[0],
|
||||||
|
@ -8571,7 +8592,7 @@ int smb3_encrypt_resp(struct ksmbd_work *work)
|
||||||
buf_size += iov[1].iov_len;
|
buf_size += iov[1].iov_len;
|
||||||
work->resp_hdr_sz = iov[1].iov_len;
|
work->resp_hdr_sz = iov[1].iov_len;
|
||||||
|
|
||||||
rc = ksmbd_crypt_message(work->conn, iov, rq_nvec, 1);
|
rc = ksmbd_crypt_message(work, iov, rq_nvec, 1);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@ -8590,7 +8611,6 @@ bool smb3_is_transform_hdr(void *buf)
|
||||||
|
|
||||||
int smb3_decrypt_req(struct ksmbd_work *work)
|
int smb3_decrypt_req(struct ksmbd_work *work)
|
||||||
{
|
{
|
||||||
struct ksmbd_conn *conn = work->conn;
|
|
||||||
struct ksmbd_session *sess;
|
struct ksmbd_session *sess;
|
||||||
char *buf = work->request_buf;
|
char *buf = work->request_buf;
|
||||||
unsigned int pdu_length = get_rfc1002_len(buf);
|
unsigned int pdu_length = get_rfc1002_len(buf);
|
||||||
|
@ -8610,7 +8630,7 @@ int smb3_decrypt_req(struct ksmbd_work *work)
|
||||||
return -ECONNABORTED;
|
return -ECONNABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
sess = ksmbd_session_lookup_all(conn, le64_to_cpu(tr_hdr->SessionId));
|
sess = ksmbd_session_lookup_all(work->conn, le64_to_cpu(tr_hdr->SessionId));
|
||||||
if (!sess) {
|
if (!sess) {
|
||||||
pr_err("invalid session id(%llx) in transform header\n",
|
pr_err("invalid session id(%llx) in transform header\n",
|
||||||
le64_to_cpu(tr_hdr->SessionId));
|
le64_to_cpu(tr_hdr->SessionId));
|
||||||
|
@ -8621,7 +8641,7 @@ int smb3_decrypt_req(struct ksmbd_work *work)
|
||||||
iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4;
|
iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4;
|
||||||
iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr) + 4;
|
iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr) + 4;
|
||||||
iov[1].iov_len = buf_data_size;
|
iov[1].iov_len = buf_data_size;
|
||||||
rc = ksmbd_crypt_message(conn, iov, 2, 0);
|
rc = ksmbd_crypt_message(work, iov, 2, 0);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,8 @@ struct create_posix_rsp {
|
||||||
__le32 nlink;
|
__le32 nlink;
|
||||||
__le32 reparse_tag;
|
__le32 reparse_tag;
|
||||||
__le32 mode;
|
__le32 mode;
|
||||||
u8 SidBuffer[40];
|
/* SidBuffer contain two sids(Domain sid(28), UNIX group sid(16)) */
|
||||||
|
u8 SidBuffer[44];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct smb2_buffer_desc_v1 {
|
struct smb2_buffer_desc_v1 {
|
||||||
|
@ -439,7 +440,8 @@ struct smb2_posix_info {
|
||||||
__le32 HardLinks;
|
__le32 HardLinks;
|
||||||
__le32 ReparseTag;
|
__le32 ReparseTag;
|
||||||
__le32 Mode;
|
__le32 Mode;
|
||||||
u8 SidBuffer[40];
|
/* SidBuffer contain two sids (UNIX user sid(16), UNIX group sid(16)) */
|
||||||
|
u8 SidBuffer[32];
|
||||||
__le32 name_len;
|
__le32 name_len;
|
||||||
u8 name[1];
|
u8 name[1];
|
||||||
/*
|
/*
|
||||||
|
@ -492,6 +494,7 @@ int smb3_decrypt_req(struct ksmbd_work *work);
|
||||||
int smb3_encrypt_resp(struct ksmbd_work *work);
|
int smb3_encrypt_resp(struct ksmbd_work *work);
|
||||||
bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work);
|
bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work);
|
||||||
int smb2_set_rsp_credits(struct ksmbd_work *work);
|
int smb2_set_rsp_credits(struct ksmbd_work *work);
|
||||||
|
bool smb3_encryption_negotiated(struct ksmbd_conn *conn);
|
||||||
|
|
||||||
/* smb2 misc functions */
|
/* smb2 misc functions */
|
||||||
int ksmbd_smb2_check_message(struct ksmbd_work *work);
|
int ksmbd_smb2_check_message(struct ksmbd_work *work);
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
* Copyright (C) 2018 Namjae Jeon <linkinjeon@kernel.org>
|
* Copyright (C) 2018 Namjae Jeon <linkinjeon@kernel.org>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/user_namespace.h>
|
||||||
|
|
||||||
#include "smb_common.h"
|
#include "smb_common.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
@ -625,8 +627,8 @@ int ksmbd_override_fsids(struct ksmbd_work *work)
|
||||||
if (!cred)
|
if (!cred)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
cred->fsuid = make_kuid(current_user_ns(), uid);
|
cred->fsuid = make_kuid(&init_user_ns, uid);
|
||||||
cred->fsgid = make_kgid(current_user_ns(), gid);
|
cred->fsgid = make_kgid(&init_user_ns, gid);
|
||||||
|
|
||||||
gi = groups_alloc(0);
|
gi = groups_alloc(0);
|
||||||
if (!gi) {
|
if (!gi) {
|
||||||
|
|
|
@ -275,7 +275,8 @@ static int sid_to_id(struct user_namespace *user_ns,
|
||||||
uid_t id;
|
uid_t id;
|
||||||
|
|
||||||
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
|
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
|
||||||
uid = mapped_kuid_user(user_ns, &init_user_ns, KUIDT_INIT(id));
|
uid = KUIDT_INIT(id);
|
||||||
|
uid = from_vfsuid(user_ns, &init_user_ns, VFSUIDT_INIT(uid));
|
||||||
if (uid_valid(uid)) {
|
if (uid_valid(uid)) {
|
||||||
fattr->cf_uid = uid;
|
fattr->cf_uid = uid;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
@ -285,7 +286,8 @@ static int sid_to_id(struct user_namespace *user_ns,
|
||||||
gid_t id;
|
gid_t id;
|
||||||
|
|
||||||
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
|
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
|
||||||
gid = mapped_kgid_user(user_ns, &init_user_ns, KGIDT_INIT(id));
|
gid = KGIDT_INIT(id);
|
||||||
|
gid = from_vfsgid(user_ns, &init_user_ns, VFSGIDT_INIT(gid));
|
||||||
if (gid_valid(gid)) {
|
if (gid_valid(gid)) {
|
||||||
fattr->cf_gid = gid;
|
fattr->cf_gid = gid;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
@ -991,7 +993,7 @@ static void smb_set_ace(struct smb_ace *ace, const struct smb_sid *sid, u8 type,
|
||||||
}
|
}
|
||||||
|
|
||||||
int smb_inherit_dacl(struct ksmbd_conn *conn,
|
int smb_inherit_dacl(struct ksmbd_conn *conn,
|
||||||
struct path *path,
|
const struct path *path,
|
||||||
unsigned int uid, unsigned int gid)
|
unsigned int uid, unsigned int gid)
|
||||||
{
|
{
|
||||||
const struct smb_sid *psid, *creator = NULL;
|
const struct smb_sid *psid, *creator = NULL;
|
||||||
|
@ -1185,7 +1187,7 @@ bool smb_inherit_flags(int flags, bool is_dir)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
|
int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
|
||||||
__le32 *pdaccess, int uid)
|
__le32 *pdaccess, int uid)
|
||||||
{
|
{
|
||||||
struct user_namespace *user_ns = mnt_user_ns(path->mnt);
|
struct user_namespace *user_ns = mnt_user_ns(path->mnt);
|
||||||
|
@ -1352,7 +1354,7 @@ err_out:
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
|
int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
|
||||||
struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
|
const struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
|
||||||
bool type_check)
|
bool type_check)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
|
@ -201,12 +201,12 @@ void posix_state_to_acl(struct posix_acl_state *state,
|
||||||
struct posix_acl_entry *pace);
|
struct posix_acl_entry *pace);
|
||||||
int compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid);
|
int compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid);
|
||||||
bool smb_inherit_flags(int flags, bool is_dir);
|
bool smb_inherit_flags(int flags, bool is_dir);
|
||||||
int smb_inherit_dacl(struct ksmbd_conn *conn, struct path *path,
|
int smb_inherit_dacl(struct ksmbd_conn *conn, const struct path *path,
|
||||||
unsigned int uid, unsigned int gid);
|
unsigned int uid, unsigned int gid);
|
||||||
int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
|
int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
|
||||||
__le32 *pdaccess, int uid);
|
__le32 *pdaccess, int uid);
|
||||||
int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
|
int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
|
||||||
struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
|
const struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
|
||||||
bool type_check);
|
bool type_check);
|
||||||
void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid);
|
void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid);
|
||||||
void ksmbd_init_domain(u32 *sub_auth);
|
void ksmbd_init_domain(u32 *sub_auth);
|
||||||
|
@ -214,25 +214,25 @@ void ksmbd_init_domain(u32 *sub_auth);
|
||||||
static inline uid_t posix_acl_uid_translate(struct user_namespace *mnt_userns,
|
static inline uid_t posix_acl_uid_translate(struct user_namespace *mnt_userns,
|
||||||
struct posix_acl_entry *pace)
|
struct posix_acl_entry *pace)
|
||||||
{
|
{
|
||||||
kuid_t kuid;
|
vfsuid_t vfsuid;
|
||||||
|
|
||||||
/* If this is an idmapped mount, apply the idmapping. */
|
/* If this is an idmapped mount, apply the idmapping. */
|
||||||
kuid = mapped_kuid_fs(mnt_userns, &init_user_ns, pace->e_uid);
|
vfsuid = make_vfsuid(mnt_userns, &init_user_ns, pace->e_uid);
|
||||||
|
|
||||||
/* Translate the kuid into a userspace id ksmbd would see. */
|
/* Translate the kuid into a userspace id ksmbd would see. */
|
||||||
return from_kuid(&init_user_ns, kuid);
|
return from_kuid(&init_user_ns, vfsuid_into_kuid(vfsuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline gid_t posix_acl_gid_translate(struct user_namespace *mnt_userns,
|
static inline gid_t posix_acl_gid_translate(struct user_namespace *mnt_userns,
|
||||||
struct posix_acl_entry *pace)
|
struct posix_acl_entry *pace)
|
||||||
{
|
{
|
||||||
kgid_t kgid;
|
vfsgid_t vfsgid;
|
||||||
|
|
||||||
/* If this is an idmapped mount, apply the idmapping. */
|
/* If this is an idmapped mount, apply the idmapping. */
|
||||||
kgid = mapped_kgid_fs(mnt_userns, &init_user_ns, pace->e_gid);
|
vfsgid = make_vfsgid(mnt_userns, &init_user_ns, pace->e_gid);
|
||||||
|
|
||||||
/* Translate the kgid into a userspace id ksmbd would see. */
|
/* Translate the kgid into a userspace id ksmbd would see. */
|
||||||
return from_kgid(&init_user_ns, kgid);
|
return from_kgid(&init_user_ns, vfsgid_into_kgid(vfsgid));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _SMBACL_H */
|
#endif /* _SMBACL_H */
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
/* SMB_DIRECT negotiation timeout in seconds */
|
/* SMB_DIRECT negotiation timeout in seconds */
|
||||||
#define SMB_DIRECT_NEGOTIATE_TIMEOUT 120
|
#define SMB_DIRECT_NEGOTIATE_TIMEOUT 120
|
||||||
|
|
||||||
#define SMB_DIRECT_MAX_SEND_SGES 8
|
#define SMB_DIRECT_MAX_SEND_SGES 6
|
||||||
#define SMB_DIRECT_MAX_RECV_SGES 1
|
#define SMB_DIRECT_MAX_RECV_SGES 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -62,13 +62,13 @@ static int smb_direct_receive_credit_max = 255;
|
||||||
static int smb_direct_send_credit_target = 255;
|
static int smb_direct_send_credit_target = 255;
|
||||||
|
|
||||||
/* The maximum single message size can be sent to remote peer */
|
/* The maximum single message size can be sent to remote peer */
|
||||||
static int smb_direct_max_send_size = 8192;
|
static int smb_direct_max_send_size = 1364;
|
||||||
|
|
||||||
/* The maximum fragmented upper-layer payload receive size supported */
|
/* The maximum fragmented upper-layer payload receive size supported */
|
||||||
static int smb_direct_max_fragmented_recv_size = 1024 * 1024;
|
static int smb_direct_max_fragmented_recv_size = 1024 * 1024;
|
||||||
|
|
||||||
/* The maximum single-message size which can be received */
|
/* The maximum single-message size which can be received */
|
||||||
static int smb_direct_max_receive_size = 8192;
|
static int smb_direct_max_receive_size = 1364;
|
||||||
|
|
||||||
static int smb_direct_max_read_write_size = SMBD_DEFAULT_IOSIZE;
|
static int smb_direct_max_read_write_size = SMBD_DEFAULT_IOSIZE;
|
||||||
|
|
||||||
|
@ -1527,6 +1527,8 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id,
|
||||||
}
|
}
|
||||||
case RDMA_CM_EVENT_DEVICE_REMOVAL:
|
case RDMA_CM_EVENT_DEVICE_REMOVAL:
|
||||||
case RDMA_CM_EVENT_DISCONNECTED: {
|
case RDMA_CM_EVENT_DISCONNECTED: {
|
||||||
|
ib_drain_qp(t->qp);
|
||||||
|
|
||||||
t->status = SMB_DIRECT_CS_DISCONNECTED;
|
t->status = SMB_DIRECT_CS_DISCONNECTED;
|
||||||
wake_up_interruptible(&t->wait_status);
|
wake_up_interruptible(&t->wait_status);
|
||||||
wake_up_interruptible(&t->wait_reassembly_queue);
|
wake_up_interruptible(&t->wait_reassembly_queue);
|
||||||
|
|
|
@ -399,7 +399,8 @@ static int create_socket(struct interface *iface)
|
||||||
|
|
||||||
ret = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &ksmbd_socket);
|
ret = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &ksmbd_socket);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Can't create socket for ipv6, try ipv4: %d\n", ret);
|
if (ret != -EAFNOSUPPORT)
|
||||||
|
pr_err("Can't create socket for ipv6, fallback to ipv4: %d\n", ret);
|
||||||
ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,
|
ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,
|
||||||
&ksmbd_socket);
|
&ksmbd_socket);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/nls.h>
|
#include <linux/nls.h>
|
||||||
|
#include <linux/unicode.h>
|
||||||
|
|
||||||
#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
|
#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
|
||||||
|
|
||||||
|
@ -69,7 +70,7 @@ char *smb_strndup_from_utf16(const char *src, const int maxlen,
|
||||||
const struct nls_table *codepage);
|
const struct nls_table *codepage);
|
||||||
int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
|
int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
|
||||||
const struct nls_table *cp, int mapchars);
|
const struct nls_table *cp, int mapchars);
|
||||||
char *ksmbd_extract_sharename(char *treename);
|
char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -377,8 +377,7 @@ int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count,
|
||||||
|
|
||||||
if (work->conn->connection_type) {
|
if (work->conn->connection_type) {
|
||||||
if (!(fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) {
|
if (!(fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) {
|
||||||
pr_err("no right to read(%pd)\n",
|
pr_err("no right to read(%pD)\n", fp->filp);
|
||||||
fp->filp->f_path.dentry);
|
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,8 +486,7 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||||
|
|
||||||
if (work->conn->connection_type) {
|
if (work->conn->connection_type) {
|
||||||
if (!(fp->daccess & FILE_WRITE_DATA_LE)) {
|
if (!(fp->daccess & FILE_WRITE_DATA_LE)) {
|
||||||
pr_err("no right to write(%pd)\n",
|
pr_err("no right to write(%pD)\n", fp->filp);
|
||||||
fp->filp->f_path.dentry);
|
|
||||||
err = -EACCES;
|
err = -EACCES;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -527,8 +525,8 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||||
if (sync) {
|
if (sync) {
|
||||||
err = vfs_fsync_range(filp, offset, offset + *written, 0);
|
err = vfs_fsync_range(filp, offset, offset + *written, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
pr_err("fsync failed for filename = %pd, err = %d\n",
|
pr_err("fsync failed for filename = %pD, err = %d\n",
|
||||||
fp->filp->f_path.dentry, err);
|
fp->filp, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -543,7 +541,7 @@ out:
|
||||||
*
|
*
|
||||||
* Return: 0 on success, otherwise error
|
* Return: 0 on success, otherwise error
|
||||||
*/
|
*/
|
||||||
int ksmbd_vfs_getattr(struct path *path, struct kstat *stat)
|
int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -1145,12 +1143,23 @@ static bool __caseless_lookup(struct dir_context *ctx, const char *name,
|
||||||
unsigned int d_type)
|
unsigned int d_type)
|
||||||
{
|
{
|
||||||
struct ksmbd_readdir_data *buf;
|
struct ksmbd_readdir_data *buf;
|
||||||
|
int cmp = -EINVAL;
|
||||||
|
|
||||||
buf = container_of(ctx, struct ksmbd_readdir_data, ctx);
|
buf = container_of(ctx, struct ksmbd_readdir_data, ctx);
|
||||||
|
|
||||||
if (buf->used != namlen)
|
if (buf->used != namlen)
|
||||||
return true;
|
return true;
|
||||||
if (!strncasecmp((char *)buf->private, name, namlen)) {
|
if (IS_ENABLED(CONFIG_UNICODE) && buf->um) {
|
||||||
|
const struct qstr q_buf = {.name = buf->private,
|
||||||
|
.len = buf->used};
|
||||||
|
const struct qstr q_name = {.name = name,
|
||||||
|
.len = namlen};
|
||||||
|
|
||||||
|
cmp = utf8_strncasecmp(buf->um, &q_buf, &q_name);
|
||||||
|
}
|
||||||
|
if (cmp < 0)
|
||||||
|
cmp = strncasecmp((char *)buf->private, name, namlen);
|
||||||
|
if (!cmp) {
|
||||||
memcpy((char *)buf->private, name, namlen);
|
memcpy((char *)buf->private, name, namlen);
|
||||||
buf->dirent_count = 1;
|
buf->dirent_count = 1;
|
||||||
return false;
|
return false;
|
||||||
|
@ -1166,7 +1175,8 @@ static bool __caseless_lookup(struct dir_context *ctx, const char *name,
|
||||||
*
|
*
|
||||||
* Return: 0 on success, otherwise error
|
* Return: 0 on success, otherwise error
|
||||||
*/
|
*/
|
||||||
static int ksmbd_vfs_lookup_in_dir(struct path *dir, char *name, size_t namelen)
|
static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name,
|
||||||
|
size_t namelen, struct unicode_map *um)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct file *dfilp;
|
struct file *dfilp;
|
||||||
|
@ -1176,6 +1186,7 @@ static int ksmbd_vfs_lookup_in_dir(struct path *dir, char *name, size_t namelen)
|
||||||
.private = name,
|
.private = name,
|
||||||
.used = namelen,
|
.used = namelen,
|
||||||
.dirent_count = 0,
|
.dirent_count = 0,
|
||||||
|
.um = um,
|
||||||
};
|
};
|
||||||
|
|
||||||
dfilp = dentry_open(dir, flags, current_cred());
|
dfilp = dentry_open(dir, flags, current_cred());
|
||||||
|
@ -1238,7 +1249,8 @@ int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *name,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
err = ksmbd_vfs_lookup_in_dir(&parent, filename,
|
err = ksmbd_vfs_lookup_in_dir(&parent, filename,
|
||||||
filename_len);
|
filename_len,
|
||||||
|
work->conn->um);
|
||||||
path_put(&parent);
|
path_put(&parent);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1741,11 +1753,11 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
|
||||||
*total_size_written = 0;
|
*total_size_written = 0;
|
||||||
|
|
||||||
if (!(src_fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) {
|
if (!(src_fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) {
|
||||||
pr_err("no right to read(%pd)\n", src_fp->filp->f_path.dentry);
|
pr_err("no right to read(%pD)\n", src_fp->filp);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
if (!(dst_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE))) {
|
if (!(dst_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE))) {
|
||||||
pr_err("no right to write(%pd)\n", dst_fp->filp->f_path.dentry);
|
pr_err("no right to write(%pD)\n", dst_fp->filp);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/namei.h>
|
#include <linux/namei.h>
|
||||||
#include <uapi/linux/xattr.h>
|
#include <uapi/linux/xattr.h>
|
||||||
#include <linux/posix_acl.h>
|
#include <linux/posix_acl.h>
|
||||||
|
#include <linux/unicode.h>
|
||||||
|
|
||||||
#include "smbacl.h"
|
#include "smbacl.h"
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
|
@ -60,6 +61,7 @@ struct ksmbd_readdir_data {
|
||||||
unsigned int used;
|
unsigned int used;
|
||||||
unsigned int dirent_count;
|
unsigned int dirent_count;
|
||||||
unsigned int file_attr;
|
unsigned int file_attr;
|
||||||
|
struct unicode_map *um;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ksmbd kstat wrapper to get valid create time when reading dir entry */
|
/* ksmbd kstat wrapper to get valid create time when reading dir entry */
|
||||||
|
@ -85,7 +87,7 @@ int ksmbd_vfs_fsync(struct ksmbd_work *work, u64 fid, u64 p_id);
|
||||||
int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name);
|
int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name);
|
||||||
int ksmbd_vfs_link(struct ksmbd_work *work,
|
int ksmbd_vfs_link(struct ksmbd_work *work,
|
||||||
const char *oldname, const char *newname);
|
const char *oldname, const char *newname);
|
||||||
int ksmbd_vfs_getattr(struct path *path, struct kstat *stat);
|
int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat);
|
||||||
int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
|
int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||||
char *newname);
|
char *newname);
|
||||||
int ksmbd_vfs_truncate(struct ksmbd_work *work,
|
int ksmbd_vfs_truncate(struct ksmbd_work *work,
|
||||||
|
|
Loading…
Reference in New Issue