diff options
author | Steve French <stfrench@microsoft.com> | 2023-05-21 20:46:30 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-06-28 11:12:40 +0200 |
commit | 29429a1f5871dbe54ee0da81bb12db8567f15379 (patch) | |
tree | 2ca619330d1d853a878075d14244aece3031b751 /fs/ksmbd | |
parent | 9d3e4bca4b92bb64491ce7b83482494fe70455bf (diff) | |
download | linux-29429a1f5871dbe54ee0da81bb12db8567f15379.tar.gz |
smb: move client and server files to common directory fs/smb
commit 38c8a9a52082579090e34c033d439ed2cd1a462d upstream. Move CIFS/SMB3 related client and server files (cifs.ko and ksmbd.ko and helper modules) to new fs/smb subdirectory: fs/cifs --> fs/smb/client fs/ksmbd --> fs/smb/server fs/smbfs_common --> fs/smb/common Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Acked-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com> [ added to stable trees to handle the directory change to handle the future stable patches due to the constant churn in this filesystem at the moment - gregkh ] Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/ksmbd')
60 files changed, 0 insertions, 31768 deletions
diff --git a/fs/ksmbd/Kconfig b/fs/ksmbd/Kconfig deleted file mode 100644 index e1fe17747ed6..000000000000 --- a/fs/ksmbd/Kconfig +++ /dev/null @@ -1,68 +0,0 @@ -config SMB_SERVER - tristate "SMB3 server support (EXPERIMENTAL)" - depends on INET - depends on MULTIUSER - depends on FILE_LOCKING - select NLS - select NLS_UTF8 - select CRYPTO - select CRYPTO_MD5 - select CRYPTO_HMAC - select CRYPTO_ECB - select CRYPTO_LIB_DES - select CRYPTO_SHA256 - select CRYPTO_CMAC - select CRYPTO_SHA512 - select CRYPTO_AEAD2 - select CRYPTO_CCM - select CRYPTO_GCM - select ASN1 - select OID_REGISTRY - select CRC32 - default n - help - Choose Y here if you want to allow SMB3 compliant clients - to access files residing on this system using SMB3 protocol. - To compile the SMB3 server support as a module, - choose M here: the module will be called ksmbd. - - You may choose to use a samba server instead, in which - case you can choose N here. - - You also need to install user space programs which can be found - in ksmbd-tools, available from - https://github.com/cifsd-team/ksmbd-tools. - More detail about how to run the ksmbd kernel server is - available via README file - (https://github.com/cifsd-team/ksmbd-tools/blob/master/README). - - ksmbd kernel server includes support for auto-negotiation, - Secure negotiate, Pre-authentication integrity, oplock/lease, - compound requests, multi-credit, packet signing, RDMA(smbdirect), - smb3 encryption, copy-offload, secure per-user session - establishment via NTLM or NTLMv2. - -config SMB_SERVER_SMBDIRECT - bool "Support for SMB Direct protocol" - depends on SMB_SERVER=m && INFINIBAND && INFINIBAND_ADDR_TRANS || SMB_SERVER=y && INFINIBAND=y && INFINIBAND_ADDR_TRANS=y - select SG_POOL - default n - - help - Enables SMB Direct support for SMB 3.0, 3.02 and 3.1.1. - - SMB Direct allows transferring SMB packets over RDMA. If unsure, - say N. - -config SMB_SERVER_CHECK_CAP_NET_ADMIN - bool "Enable check network administration capability" - depends on SMB_SERVER - default y - - help - Prevent unprivileged processes to start the ksmbd kernel server. - -config SMB_SERVER_KERBEROS5 - bool "Support for Kerberos 5" - depends on SMB_SERVER - default n diff --git a/fs/ksmbd/Makefile b/fs/ksmbd/Makefile deleted file mode 100644 index 7d6337a7dee4..000000000000 --- a/fs/ksmbd/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# Makefile for Linux SMB3 kernel server -# -obj-$(CONFIG_SMB_SERVER) += ksmbd.o - -ksmbd-y := unicode.o auth.o vfs.o vfs_cache.o server.o ndr.o \ - misc.o oplock.o connection.o ksmbd_work.o crypto_ctx.o \ - mgmt/ksmbd_ida.o mgmt/user_config.o mgmt/share_config.o \ - mgmt/tree_connect.o mgmt/user_session.o smb_common.o \ - transport_tcp.o transport_ipc.o smbacl.o smb2pdu.o \ - smb2ops.o smb2misc.o ksmbd_spnego_negtokeninit.asn1.o \ - ksmbd_spnego_negtokentarg.asn1.o asn1.o - -$(obj)/asn1.o: $(obj)/ksmbd_spnego_negtokeninit.asn1.h $(obj)/ksmbd_spnego_negtokentarg.asn1.h - -$(obj)/ksmbd_spnego_negtokeninit.asn1.o: $(obj)/ksmbd_spnego_negtokeninit.asn1.c $(obj)/ksmbd_spnego_negtokeninit.asn1.h -$(obj)/ksmbd_spnego_negtokentarg.asn1.o: $(obj)/ksmbd_spnego_negtokentarg.asn1.c $(obj)/ksmbd_spnego_negtokentarg.asn1.h - -ksmbd-$(CONFIG_SMB_SERVER_SMBDIRECT) += transport_rdma.o diff --git a/fs/ksmbd/asn1.c b/fs/ksmbd/asn1.c deleted file mode 100644 index c03eba090368..000000000000 --- a/fs/ksmbd/asn1.c +++ /dev/null @@ -1,239 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in - * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich - * - * Copyright (c) 2000 RP Internet (www.rpi.net.au). - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/oid_registry.h> - -#include "glob.h" - -#include "asn1.h" -#include "connection.h" -#include "auth.h" -#include "ksmbd_spnego_negtokeninit.asn1.h" -#include "ksmbd_spnego_negtokentarg.asn1.h" - -#define NTLMSSP_OID_LEN 10 - -static char NTLMSSP_OID_STR[NTLMSSP_OID_LEN] = { 0x2b, 0x06, 0x01, 0x04, 0x01, - 0x82, 0x37, 0x02, 0x02, 0x0a }; - -int -ksmbd_decode_negTokenInit(unsigned char *security_blob, int length, - struct ksmbd_conn *conn) -{ - return asn1_ber_decoder(&ksmbd_spnego_negtokeninit_decoder, conn, - security_blob, length); -} - -int -ksmbd_decode_negTokenTarg(unsigned char *security_blob, int length, - struct ksmbd_conn *conn) -{ - return asn1_ber_decoder(&ksmbd_spnego_negtokentarg_decoder, conn, - security_blob, length); -} - -static int compute_asn_hdr_len_bytes(int len) -{ - if (len > 0xFFFFFF) - return 4; - else if (len > 0xFFFF) - return 3; - else if (len > 0xFF) - return 2; - else if (len > 0x7F) - return 1; - else - return 0; -} - -static void encode_asn_tag(char *buf, unsigned int *ofs, char tag, char seq, - int length) -{ - int i; - int index = *ofs; - char hdr_len = compute_asn_hdr_len_bytes(length); - int len = length + 2 + hdr_len; - - /* insert tag */ - buf[index++] = tag; - - if (!hdr_len) { - buf[index++] = len; - } else { - buf[index++] = 0x80 | hdr_len; - for (i = hdr_len - 1; i >= 0; i--) - buf[index++] = (len >> (i * 8)) & 0xFF; - } - - /* insert seq */ - len = len - (index - *ofs); - buf[index++] = seq; - - if (!hdr_len) { - buf[index++] = len; - } else { - buf[index++] = 0x80 | hdr_len; - for (i = hdr_len - 1; i >= 0; i--) - buf[index++] = (len >> (i * 8)) & 0xFF; - } - - *ofs += (index - *ofs); -} - -int build_spnego_ntlmssp_neg_blob(unsigned char **pbuffer, u16 *buflen, - char *ntlm_blob, int ntlm_blob_len) -{ - char *buf; - unsigned int ofs = 0; - int neg_result_len = 4 + compute_asn_hdr_len_bytes(1) * 2 + 1; - int oid_len = 4 + compute_asn_hdr_len_bytes(NTLMSSP_OID_LEN) * 2 + - NTLMSSP_OID_LEN; - int ntlmssp_len = 4 + compute_asn_hdr_len_bytes(ntlm_blob_len) * 2 + - ntlm_blob_len; - int total_len = 4 + compute_asn_hdr_len_bytes(neg_result_len + - oid_len + ntlmssp_len) * 2 + - neg_result_len + oid_len + ntlmssp_len; - - buf = kmalloc(total_len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* insert main gss header */ - encode_asn_tag(buf, &ofs, 0xa1, 0x30, neg_result_len + oid_len + - ntlmssp_len); - - /* insert neg result */ - encode_asn_tag(buf, &ofs, 0xa0, 0x0a, 1); - buf[ofs++] = 1; - - /* insert oid */ - encode_asn_tag(buf, &ofs, 0xa1, 0x06, NTLMSSP_OID_LEN); - memcpy(buf + ofs, NTLMSSP_OID_STR, NTLMSSP_OID_LEN); - ofs += NTLMSSP_OID_LEN; - - /* insert response token - ntlmssp blob */ - encode_asn_tag(buf, &ofs, 0xa2, 0x04, ntlm_blob_len); - memcpy(buf + ofs, ntlm_blob, ntlm_blob_len); - ofs += ntlm_blob_len; - - *pbuffer = buf; - *buflen = total_len; - return 0; -} - -int build_spnego_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, - int neg_result) -{ - char *buf; - unsigned int ofs = 0; - int neg_result_len = 4 + compute_asn_hdr_len_bytes(1) * 2 + 1; - int total_len = 4 + compute_asn_hdr_len_bytes(neg_result_len) * 2 + - neg_result_len; - - buf = kmalloc(total_len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* insert main gss header */ - encode_asn_tag(buf, &ofs, 0xa1, 0x30, neg_result_len); - - /* insert neg result */ - encode_asn_tag(buf, &ofs, 0xa0, 0x0a, 1); - if (neg_result) - buf[ofs++] = 2; - else - buf[ofs++] = 0; - - *pbuffer = buf; - *buflen = total_len; - return 0; -} - -int ksmbd_gssapi_this_mech(void *context, size_t hdrlen, unsigned char tag, - const void *value, size_t vlen) -{ - enum OID oid; - - oid = look_up_OID(value, vlen); - if (oid != OID_spnego) { - char buf[50]; - - sprint_oid(value, vlen, buf, sizeof(buf)); - ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf); - return -EBADMSG; - } - - return 0; -} - -int ksmbd_neg_token_init_mech_type(void *context, size_t hdrlen, - unsigned char tag, const void *value, - size_t vlen) -{ - struct ksmbd_conn *conn = context; - enum OID oid; - int mech_type; - - oid = look_up_OID(value, vlen); - if (oid == OID_ntlmssp) { - mech_type = KSMBD_AUTH_NTLMSSP; - } else if (oid == OID_mskrb5) { - mech_type = KSMBD_AUTH_MSKRB5; - } else if (oid == OID_krb5) { - mech_type = KSMBD_AUTH_KRB5; - } else if (oid == OID_krb5u2u) { - mech_type = KSMBD_AUTH_KRB5U2U; - } else { - char buf[50]; - - sprint_oid(value, vlen, buf, sizeof(buf)); - ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf); - return -EBADMSG; - } - - conn->auth_mechs |= mech_type; - if (conn->preferred_auth_mech == 0) - conn->preferred_auth_mech = mech_type; - - return 0; -} - -int ksmbd_neg_token_init_mech_token(void *context, size_t hdrlen, - unsigned char tag, const void *value, - size_t vlen) -{ - struct ksmbd_conn *conn = context; - - conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL); - if (!conn->mechToken) - return -ENOMEM; - - memcpy(conn->mechToken, value, vlen); - conn->mechToken[vlen] = '\0'; - return 0; -} - -int ksmbd_neg_token_targ_resp_token(void *context, size_t hdrlen, - unsigned char tag, const void *value, - size_t vlen) -{ - struct ksmbd_conn *conn = context; - - conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL); - if (!conn->mechToken) - return -ENOMEM; - - memcpy(conn->mechToken, value, vlen); - conn->mechToken[vlen] = '\0'; - return 0; -} diff --git a/fs/ksmbd/asn1.h b/fs/ksmbd/asn1.h deleted file mode 100644 index ce105f4ce305..000000000000 --- a/fs/ksmbd/asn1.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in - * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich - * - * Copyright (c) 2000 RP Internet (www.rpi.net.au). - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __ASN1_H__ -#define __ASN1_H__ - -int ksmbd_decode_negTokenInit(unsigned char *security_blob, int length, - struct ksmbd_conn *conn); -int ksmbd_decode_negTokenTarg(unsigned char *security_blob, int length, - struct ksmbd_conn *conn); -int build_spnego_ntlmssp_neg_blob(unsigned char **pbuffer, u16 *buflen, - char *ntlm_blob, int ntlm_blob_len); -int build_spnego_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, - int neg_result); -#endif /* __ASN1_H__ */ diff --git a/fs/ksmbd/auth.c b/fs/ksmbd/auth.c deleted file mode 100644 index df8fb076f6f1..000000000000 --- a/fs/ksmbd/auth.c +++ /dev/null @@ -1,1206 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/uaccess.h> -#include <linux/backing-dev.h> -#include <linux/writeback.h> -#include <linux/uio.h> -#include <linux/xattr.h> -#include <crypto/hash.h> -#include <crypto/aead.h> -#include <linux/random.h> -#include <linux/scatterlist.h> - -#include "auth.h" -#include "glob.h" - -#include <linux/fips.h> -#include <crypto/des.h> - -#include "server.h" -#include "smb_common.h" -#include "connection.h" -#include "mgmt/user_session.h" -#include "mgmt/user_config.h" -#include "crypto_ctx.h" -#include "transport_ipc.h" -#include "../smbfs_common/arc4.h" - -/* - * Fixed format data defining GSS header and fixed string - * "not_defined_in_RFC4178@please_ignore". - * So sec blob data in neg phase could be generated statically. - */ -static char NEGOTIATE_GSS_HEADER[AUTH_GSS_LENGTH] = { -#ifdef CONFIG_SMB_SERVER_KERBEROS5 - 0x60, 0x5e, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, - 0x05, 0x02, 0xa0, 0x54, 0x30, 0x52, 0xa0, 0x24, - 0x30, 0x22, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02, - 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, - 0x37, 0x02, 0x02, 0x0a, 0xa3, 0x2a, 0x30, 0x28, - 0xa0, 0x26, 0x1b, 0x24, 0x6e, 0x6f, 0x74, 0x5f, - 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, - 0x69, 0x6e, 0x5f, 0x52, 0x46, 0x43, 0x34, 0x31, - 0x37, 0x38, 0x40, 0x70, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x5f, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65 -#else - 0x60, 0x48, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, - 0x05, 0x02, 0xa0, 0x3e, 0x30, 0x3c, 0xa0, 0x0e, - 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, - 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a, 0xa3, 0x2a, - 0x30, 0x28, 0xa0, 0x26, 0x1b, 0x24, 0x6e, 0x6f, - 0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, - 0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x52, 0x46, 0x43, - 0x34, 0x31, 0x37, 0x38, 0x40, 0x70, 0x6c, 0x65, - 0x61, 0x73, 0x65, 0x5f, 0x69, 0x67, 0x6e, 0x6f, - 0x72, 0x65 -#endif -}; - -void ksmbd_copy_gss_neg_header(void *buf) -{ - memcpy(buf, NEGOTIATE_GSS_HEADER, AUTH_GSS_LENGTH); -} - -/** - * ksmbd_gen_sess_key() - function to generate session key - * @sess: session of connection - * @hash: source hash value to be used for find session key - * @hmac: source hmac value to be used for finding session key - * - */ -static int ksmbd_gen_sess_key(struct ksmbd_session *sess, char *hash, - char *hmac) -{ - struct ksmbd_crypto_ctx *ctx; - int rc; - - ctx = ksmbd_crypto_ctx_find_hmacmd5(); - if (!ctx) { - ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); - return -ENOMEM; - } - - rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx), - hash, - CIFS_HMAC_MD5_HASH_SIZE); - if (rc) { - ksmbd_debug(AUTH, "hmacmd5 set key fail error %d\n", rc); - goto out; - } - - rc = crypto_shash_init(CRYPTO_HMACMD5(ctx)); - if (rc) { - ksmbd_debug(AUTH, "could not init hmacmd5 error %d\n", rc); - goto out; - } - - rc = crypto_shash_update(CRYPTO_HMACMD5(ctx), - hmac, - SMB2_NTLMV2_SESSKEY_SIZE); - if (rc) { - ksmbd_debug(AUTH, "Could not update with response error %d\n", rc); - goto out; - } - - rc = crypto_shash_final(CRYPTO_HMACMD5(ctx), sess->sess_key); - if (rc) { - ksmbd_debug(AUTH, "Could not generate hmacmd5 hash error %d\n", rc); - goto out; - } - -out: - ksmbd_release_crypto_ctx(ctx); - return rc; -} - -static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess, - char *ntlmv2_hash, char *dname) -{ - int ret, len, conv_len; - wchar_t *domain = NULL; - __le16 *uniname = NULL; - struct ksmbd_crypto_ctx *ctx; - - ctx = ksmbd_crypto_ctx_find_hmacmd5(); - if (!ctx) { - ksmbd_debug(AUTH, "can't generate ntlmv2 hash\n"); - return -ENOMEM; - } - - ret = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx), - user_passkey(sess->user), - CIFS_ENCPWD_SIZE); - if (ret) { - ksmbd_debug(AUTH, "Could not set NT Hash as a key\n"); - goto out; - } - - ret = crypto_shash_init(CRYPTO_HMACMD5(ctx)); - if (ret) { - ksmbd_debug(AUTH, "could not init hmacmd5\n"); - goto out; - } - - /* convert user_name to unicode */ - len = strlen(user_name(sess->user)); - uniname = kzalloc(2 + UNICODE_LEN(len), GFP_KERNEL); - if (!uniname) { - ret = -ENOMEM; - goto out; - } - - conv_len = smb_strtoUTF16(uniname, user_name(sess->user), len, - conn->local_nls); - if (conv_len < 0 || conv_len > len) { - ret = -EINVAL; - goto out; - } - UniStrupr(uniname); - - ret = crypto_shash_update(CRYPTO_HMACMD5(ctx), - (char *)uniname, - UNICODE_LEN(conv_len)); - if (ret) { - ksmbd_debug(AUTH, "Could not update with user\n"); - goto out; - } - - /* Convert domain name or conn name to unicode and uppercase */ - len = strlen(dname); - domain = kzalloc(2 + UNICODE_LEN(len), GFP_KERNEL); - if (!domain) { - ret = -ENOMEM; - goto out; - } - - conv_len = smb_strtoUTF16((__le16 *)domain, dname, len, - conn->local_nls); - if (conv_len < 0 || conv_len > len) { - ret = -EINVAL; - goto out; - } - - ret = crypto_shash_update(CRYPTO_HMACMD5(ctx), - (char *)domain, - UNICODE_LEN(conv_len)); - if (ret) { - ksmbd_debug(AUTH, "Could not update with domain\n"); - goto out; - } - - ret = crypto_shash_final(CRYPTO_HMACMD5(ctx), ntlmv2_hash); - if (ret) - ksmbd_debug(AUTH, "Could not generate md5 hash\n"); -out: - kfree(uniname); - kfree(domain); - ksmbd_release_crypto_ctx(ctx); - return ret; -} - -/** - * ksmbd_auth_ntlmv2() - NTLMv2 authentication handler - * @sess: session of connection - * @ntlmv2: NTLMv2 challenge response - * @blen: NTLMv2 blob length - * @domain_name: domain name - * - * Return: 0 on success, error number on error - */ -int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, - struct ntlmv2_resp *ntlmv2, int blen, char *domain_name, - char *cryptkey) -{ - char ntlmv2_hash[CIFS_ENCPWD_SIZE]; - char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE]; - struct ksmbd_crypto_ctx *ctx = NULL; - char *construct = NULL; - int rc, len; - - rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name); - if (rc) { - ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc); - goto out; - } - - ctx = ksmbd_crypto_ctx_find_hmacmd5(); - if (!ctx) { - ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); - return -ENOMEM; - } - - rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx), - ntlmv2_hash, - CIFS_HMAC_MD5_HASH_SIZE); - if (rc) { - ksmbd_debug(AUTH, "Could not set NTLMV2 Hash as a key\n"); - goto out; - } - - rc = crypto_shash_init(CRYPTO_HMACMD5(ctx)); - if (rc) { - ksmbd_debug(AUTH, "Could not init hmacmd5\n"); - goto out; - } - - len = CIFS_CRYPTO_KEY_SIZE + blen; - construct = kzalloc(len, GFP_KERNEL); - if (!construct) { - rc = -ENOMEM; - goto out; - } - - memcpy(construct, cryptkey, CIFS_CRYPTO_KEY_SIZE); - memcpy(construct + CIFS_CRYPTO_KEY_SIZE, &ntlmv2->blob_signature, blen); - - rc = crypto_shash_update(CRYPTO_HMACMD5(ctx), construct, len); - if (rc) { - ksmbd_debug(AUTH, "Could not update with response\n"); - goto out; - } - - rc = crypto_shash_final(CRYPTO_HMACMD5(ctx), ntlmv2_rsp); - if (rc) { - ksmbd_debug(AUTH, "Could not generate md5 hash\n"); - goto out; - } - ksmbd_release_crypto_ctx(ctx); - ctx = NULL; - - rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp); - if (rc) { - ksmbd_debug(AUTH, "Could not generate sess key\n"); - goto out; - } - - if (memcmp(ntlmv2->ntlmv2_hash, ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE) != 0) - rc = -EINVAL; -out: - if (ctx) - ksmbd_release_crypto_ctx(ctx); - kfree(construct); - return rc; -} - -/** - * ksmbd_decode_ntlmssp_auth_blob() - helper function to construct - * authenticate blob - * @authblob: authenticate blob source pointer - * @usr: user details - * @sess: session of connection - * - * Return: 0 on success, error number on error - */ -int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob, - int blob_len, struct ksmbd_conn *conn, - struct ksmbd_session *sess) -{ - char *domain_name; - unsigned int nt_off, dn_off; - unsigned short nt_len, dn_len; - int ret; - - if (blob_len < sizeof(struct authenticate_message)) { - ksmbd_debug(AUTH, "negotiate blob len %d too small\n", - blob_len); - return -EINVAL; - } - - if (memcmp(authblob->Signature, "NTLMSSP", 8)) { - ksmbd_debug(AUTH, "blob signature incorrect %s\n", - authblob->Signature); - return -EINVAL; - } - - nt_off = le32_to_cpu(authblob->NtChallengeResponse.BufferOffset); - nt_len = le16_to_cpu(authblob->NtChallengeResponse.Length); - dn_off = le32_to_cpu(authblob->DomainName.BufferOffset); - dn_len = le16_to_cpu(authblob->DomainName.Length); - - if (blob_len < (u64)dn_off + dn_len || blob_len < (u64)nt_off + nt_len || - nt_len < CIFS_ENCPWD_SIZE) - return -EINVAL; - - /* TODO : use domain name that imported from configuration file */ - domain_name = smb_strndup_from_utf16((const char *)authblob + dn_off, - dn_len, true, conn->local_nls); - if (IS_ERR(domain_name)) - return PTR_ERR(domain_name); - - /* process NTLMv2 authentication */ - ksmbd_debug(AUTH, "decode_ntlmssp_authenticate_blob dname%s\n", - domain_name); - ret = ksmbd_auth_ntlmv2(conn, sess, - (struct ntlmv2_resp *)((char *)authblob + nt_off), - nt_len - CIFS_ENCPWD_SIZE, - domain_name, conn->ntlmssp.cryptkey); - kfree(domain_name); - - /* The recovered secondary session key */ - if (conn->ntlmssp.client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) { - struct arc4_ctx *ctx_arc4; - unsigned int sess_key_off, sess_key_len; - - sess_key_off = le32_to_cpu(authblob->SessionKey.BufferOffset); - sess_key_len = le16_to_cpu(authblob->SessionKey.Length); - - if (blob_len < (u64)sess_key_off + sess_key_len) - return -EINVAL; - - ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL); - if (!ctx_arc4) - return -ENOMEM; - - cifs_arc4_setkey(ctx_arc4, sess->sess_key, - SMB2_NTLMV2_SESSKEY_SIZE); - cifs_arc4_crypt(ctx_arc4, sess->sess_key, - (char *)authblob + sess_key_off, sess_key_len); - kfree_sensitive(ctx_arc4); - } - - return ret; -} - -/** - * ksmbd_decode_ntlmssp_neg_blob() - helper function to construct - * negotiate blob - * @negblob: negotiate blob source pointer - * @rsp: response header pointer to be updated - * @sess: session of connection - * - */ -int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob, - int blob_len, struct ksmbd_conn *conn) -{ - if (blob_len < sizeof(struct negotiate_message)) { - ksmbd_debug(AUTH, "negotiate blob len %d too small\n", - blob_len); - return -EINVAL; - } - - if (memcmp(negblob->Signature, "NTLMSSP", 8)) { - ksmbd_debug(AUTH, "blob signature incorrect %s\n", - negblob->Signature); - return -EINVAL; - } - - conn->ntlmssp.client_flags = le32_to_cpu(negblob->NegotiateFlags); - return 0; -} - -/** - * ksmbd_build_ntlmssp_challenge_blob() - helper function to construct - * challenge blob - * @chgblob: challenge blob source pointer to initialize - * @rsp: response header pointer to be updated - * @sess: session of connection - * - */ -unsigned int -ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob, - struct ksmbd_conn *conn) -{ - struct target_info *tinfo; - wchar_t *name; - __u8 *target_name; - unsigned int flags, blob_off, blob_len, type, target_info_len = 0; - int len, uni_len, conv_len; - int cflags = conn->ntlmssp.client_flags; - - memcpy(chgblob->Signature, NTLMSSP_SIGNATURE, 8); - chgblob->MessageType = NtLmChallenge; - - flags = NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_TARGET_TYPE_SERVER | - NTLMSSP_NEGOTIATE_TARGET_INFO; - - if (cflags & NTLMSSP_NEGOTIATE_SIGN) { - flags |= NTLMSSP_NEGOTIATE_SIGN; - flags |= cflags & (NTLMSSP_NEGOTIATE_128 | - NTLMSSP_NEGOTIATE_56); - } - - if (cflags & NTLMSSP_NEGOTIATE_SEAL && smb3_encryption_negotiated(conn)) - flags |= NTLMSSP_NEGOTIATE_SEAL; - - if (cflags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) - flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; - - if (cflags & NTLMSSP_REQUEST_TARGET) - flags |= NTLMSSP_REQUEST_TARGET; - - if (conn->use_spnego && - (cflags & NTLMSSP_NEGOTIATE_EXTENDED_SEC)) - flags |= NTLMSSP_NEGOTIATE_EXTENDED_SEC; - - if (cflags & NTLMSSP_NEGOTIATE_KEY_XCH) - flags |= NTLMSSP_NEGOTIATE_KEY_XCH; - - chgblob->NegotiateFlags = cpu_to_le32(flags); - len = strlen(ksmbd_netbios_name()); - name = kmalloc(2 + UNICODE_LEN(len), GFP_KERNEL); - if (!name) - return -ENOMEM; - - conv_len = smb_strtoUTF16((__le16 *)name, ksmbd_netbios_name(), len, - conn->local_nls); - if (conv_len < 0 || conv_len > len) { - kfree(name); - return -EINVAL; - } - - uni_len = UNICODE_LEN(conv_len); - - blob_off = sizeof(struct challenge_message); - blob_len = blob_off + uni_len; - - chgblob->TargetName.Length = cpu_to_le16(uni_len); - chgblob->TargetName.MaximumLength = cpu_to_le16(uni_len); - chgblob->TargetName.BufferOffset = cpu_to_le32(blob_off); - - /* Initialize random conn challenge */ - get_random_bytes(conn->ntlmssp.cryptkey, sizeof(__u64)); - memcpy(chgblob->Challenge, conn->ntlmssp.cryptkey, - CIFS_CRYPTO_KEY_SIZE); - - /* Add Target Information to security buffer */ - chgblob->TargetInfoArray.BufferOffset = cpu_to_le32(blob_len); - - target_name = (__u8 *)chgblob + blob_off; - memcpy(target_name, name, uni_len); - tinfo = (struct target_info *)(target_name + uni_len); - - chgblob->TargetInfoArray.Length = 0; - /* Add target info list for NetBIOS/DNS settings */ - for (type = NTLMSSP_AV_NB_COMPUTER_NAME; - type <= NTLMSSP_AV_DNS_DOMAIN_NAME; type++) { - tinfo->Type = cpu_to_le16(type); - tinfo->Length = cpu_to_le16(uni_len); - memcpy(tinfo->Content, name, uni_len); - tinfo = (struct target_info *)((char *)tinfo + 4 + uni_len); - target_info_len += 4 + uni_len; - } - - /* Add terminator subblock */ - tinfo->Type = 0; - tinfo->Length = 0; - target_info_len += 4; - - chgblob->TargetInfoArray.Length = cpu_to_le16(target_info_len); - chgblob->TargetInfoArray.MaximumLength = cpu_to_le16(target_info_len); - blob_len += target_info_len; - kfree(name); - ksmbd_debug(AUTH, "NTLMSSP SecurityBufferLength %d\n", blob_len); - return blob_len; -} - -#ifdef CONFIG_SMB_SERVER_KERBEROS5 -int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, - int in_len, char *out_blob, int *out_len) -{ - struct ksmbd_spnego_authen_response *resp; - struct ksmbd_user *user = NULL; - int retval; - - resp = ksmbd_ipc_spnego_authen_request(in_blob, in_len); - if (!resp) { - ksmbd_debug(AUTH, "SPNEGO_AUTHEN_REQUEST failure\n"); - return -EINVAL; - } - - if (!(resp->login_response.status & KSMBD_USER_FLAG_OK)) { - ksmbd_debug(AUTH, "krb5 authentication failure\n"); - retval = -EPERM; - goto out; - } - - if (*out_len <= resp->spnego_blob_len) { - ksmbd_debug(AUTH, "buf len %d, but blob len %d\n", - *out_len, resp->spnego_blob_len); - retval = -EINVAL; - goto out; - } - - if (resp->session_key_len > sizeof(sess->sess_key)) { - ksmbd_debug(AUTH, "session key is too long\n"); - retval = -EINVAL; - goto out; - } - - user = ksmbd_alloc_user(&resp->login_response); - if (!user) { - ksmbd_debug(AUTH, "login failure\n"); - retval = -ENOMEM; - goto out; - } - sess->user = user; - - memcpy(sess->sess_key, resp->payload, resp->session_key_len); - memcpy(out_blob, resp->payload + resp->session_key_len, - resp->spnego_blob_len); - *out_len = resp->spnego_blob_len; - retval = 0; -out: - kvfree(resp); - return retval; -} -#else -int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, - int in_len, char *out_blob, int *out_len) -{ - return -EOPNOTSUPP; -} -#endif - -/** - * ksmbd_sign_smb2_pdu() - function to generate packet signing - * @conn: connection - * @key: signing key - * @iov: buffer iov array - * @n_vec: number of iovecs - * @sig: signature value generated for client request packet - * - */ -int ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, - int n_vec, char *sig) -{ - struct ksmbd_crypto_ctx *ctx; - int rc, i; - - ctx = ksmbd_crypto_ctx_find_hmacsha256(); - if (!ctx) { - ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); - return -ENOMEM; - } - - rc = crypto_shash_setkey(CRYPTO_HMACSHA256_TFM(ctx), - key, - SMB2_NTLMV2_SESSKEY_SIZE); - if (rc) - goto out; - - rc = crypto_shash_init(CRYPTO_HMACSHA256(ctx)); - if (rc) { - ksmbd_debug(AUTH, "hmacsha256 init error %d\n", rc); - goto out; - } - - for (i = 0; i < n_vec; i++) { - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), - iov[i].iov_base, - iov[i].iov_len); - if (rc) { - ksmbd_debug(AUTH, "hmacsha256 update error %d\n", rc); - goto out; - } - } - - rc = crypto_shash_final(CRYPTO_HMACSHA256(ctx), sig); - if (rc) - ksmbd_debug(AUTH, "hmacsha256 generation error %d\n", rc); -out: - ksmbd_release_crypto_ctx(ctx); - return rc; -} - -/** - * ksmbd_sign_smb3_pdu() - function to generate packet signing - * @conn: connection - * @key: signing key - * @iov: buffer iov array - * @n_vec: number of iovecs - * @sig: signature value generated for client request packet - * - */ -int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, - int n_vec, char *sig) -{ - struct ksmbd_crypto_ctx *ctx; - int rc, i; - - ctx = ksmbd_crypto_ctx_find_cmacaes(); - if (!ctx) { - ksmbd_debug(AUTH, "could not crypto alloc cmac\n"); - return -ENOMEM; - } - - rc = crypto_shash_setkey(CRYPTO_CMACAES_TFM(ctx), - key, - SMB2_CMACAES_SIZE); - if (rc) - goto out; - - rc = crypto_shash_init(CRYPTO_CMACAES(ctx)); - if (rc) { - ksmbd_debug(AUTH, "cmaces init error %d\n", rc); - goto out; - } - - for (i = 0; i < n_vec; i++) { - rc = crypto_shash_update(CRYPTO_CMACAES(ctx), - iov[i].iov_base, - iov[i].iov_len); - if (rc) { - ksmbd_debug(AUTH, "cmaces update error %d\n", rc); - goto out; - } - } - - rc = crypto_shash_final(CRYPTO_CMACAES(ctx), sig); - if (rc) - ksmbd_debug(AUTH, "cmaces generation error %d\n", rc); -out: - ksmbd_release_crypto_ctx(ctx); - return rc; -} - -struct derivation { - struct kvec label; - struct kvec context; - bool binding; -}; - -static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess, - struct kvec label, struct kvec context, __u8 *key, - unsigned int key_size) -{ - unsigned char zero = 0x0; - __u8 i[4] = {0, 0, 0, 1}; - __u8 L128[4] = {0, 0, 0, 128}; - __u8 L256[4] = {0, 0, 1, 0}; - int rc; - unsigned char prfhash[SMB2_HMACSHA256_SIZE]; - unsigned char *hashptr = prfhash; - struct ksmbd_crypto_ctx *ctx; - - memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); - memset(key, 0x0, key_size); - - ctx = ksmbd_crypto_ctx_find_hmacsha256(); - if (!ctx) { - ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); - return -ENOMEM; - } - - rc = crypto_shash_setkey(CRYPTO_HMACSHA256_TFM(ctx), - sess->sess_key, - SMB2_NTLMV2_SESSKEY_SIZE); - if (rc) - goto smb3signkey_ret; - - rc = crypto_shash_init(CRYPTO_HMACSHA256(ctx)); - if (rc) { - ksmbd_debug(AUTH, "hmacsha256 init error %d\n", rc); - goto smb3signkey_ret; - } - - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), i, 4); - if (rc) { - ksmbd_debug(AUTH, "could not update with n\n"); - goto smb3signkey_ret; - } - - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), - label.iov_base, - label.iov_len); - if (rc) { - ksmbd_debug(AUTH, "could not update with label\n"); - goto smb3signkey_ret; - } - - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), &zero, 1); - if (rc) { - ksmbd_debug(AUTH, "could not update with zero\n"); - goto smb3signkey_ret; - } - - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), - context.iov_base, - context.iov_len); - if (rc) { - ksmbd_debug(AUTH, "could not update with context\n"); - goto smb3signkey_ret; - } - - if (key_size == SMB3_ENC_DEC_KEY_SIZE && - (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || - conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4); - else - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4); - if (rc) { - ksmbd_debug(AUTH, "could not update with L\n"); - goto smb3signkey_ret; - } - - rc = crypto_shash_final(CRYPTO_HMACSHA256(ctx), hashptr); - if (rc) { - ksmbd_debug(AUTH, "Could not generate hmacmd5 hash error %d\n", - rc); - goto smb3signkey_ret; - } - - memcpy(key, hashptr, key_size); - -smb3signkey_ret: - ksmbd_release_crypto_ctx(ctx); - return rc; -} - -static int generate_smb3signingkey(struct ksmbd_session *sess, - struct ksmbd_conn *conn, - const struct derivation *signing) -{ - int rc; - struct channel *chann; - char *key; - - chann = lookup_chann_list(sess, conn); - if (!chann) - return 0; - - if (conn->dialect >= SMB30_PROT_ID && signing->binding) - key = chann->smb3signingkey; - else - key = sess->smb3signingkey; - - rc = generate_key(conn, sess, signing->label, signing->context, key, - SMB3_SIGN_KEY_SIZE); - if (rc) - return rc; - - if (!(conn->dialect >= SMB30_PROT_ID && signing->binding)) - memcpy(chann->smb3signingkey, key, SMB3_SIGN_KEY_SIZE); - - ksmbd_debug(AUTH, "dumping generated AES signing keys\n"); - ksmbd_debug(AUTH, "Session Id %llu\n", sess->id); - ksmbd_debug(AUTH, "Session Key %*ph\n", - SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key); - ksmbd_debug(AUTH, "Signing Key %*ph\n", - SMB3_SIGN_KEY_SIZE, key); - return 0; -} - -int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess, - struct ksmbd_conn *conn) -{ - struct derivation d; - - d.label.iov_base = "SMB2AESCMAC"; - d.label.iov_len = 12; - d.context.iov_base = "SmbSign"; - d.context.iov_len = 8; - d.binding = conn->binding; - - return generate_smb3signingkey(sess, conn, &d); -} - -int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess, - struct ksmbd_conn *conn) -{ - struct derivation d; - - d.label.iov_base = "SMBSigningKey"; - d.label.iov_len = 14; - if (conn->binding) { - struct preauth_session *preauth_sess; - - preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id); - if (!preauth_sess) - return -ENOENT; - d.context.iov_base = preauth_sess->Preauth_HashValue; - } else { - d.context.iov_base = sess->Preauth_HashValue; - } - d.context.iov_len = 64; - d.binding = conn->binding; - - return generate_smb3signingkey(sess, conn, &d); -} - -struct derivation_twin { - struct derivation encryption; - struct derivation decryption; -}; - -static int generate_smb3encryptionkey(struct ksmbd_conn *conn, - struct ksmbd_session *sess, - const struct derivation_twin *ptwin) -{ - int rc; - - rc = generate_key(conn, sess, ptwin->encryption.label, - ptwin->encryption.context, sess->smb3encryptionkey, - SMB3_ENC_DEC_KEY_SIZE); - if (rc) - return rc; - - rc = generate_key(conn, sess, ptwin->decryption.label, - ptwin->decryption.context, - sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE); - if (rc) - return rc; - - ksmbd_debug(AUTH, "dumping generated AES encryption keys\n"); - ksmbd_debug(AUTH, "Cipher type %d\n", conn->cipher_type); - ksmbd_debug(AUTH, "Session Id %llu\n", sess->id); - ksmbd_debug(AUTH, "Session Key %*ph\n", - SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key); - if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || - conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) { - ksmbd_debug(AUTH, "ServerIn Key %*ph\n", - SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3encryptionkey); - ksmbd_debug(AUTH, "ServerOut Key %*ph\n", - SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3decryptionkey); - } else { - ksmbd_debug(AUTH, "ServerIn Key %*ph\n", - SMB3_GCM128_CRYPTKEY_SIZE, sess->smb3encryptionkey); - ksmbd_debug(AUTH, "ServerOut Key %*ph\n", - SMB3_GCM128_CRYPTKEY_SIZE, sess->smb3decryptionkey); - } - return 0; -} - -int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn, - struct ksmbd_session *sess) -{ - struct derivation_twin twin; - struct derivation *d; - - d = &twin.encryption; - d->label.iov_base = "SMB2AESCCM"; - d->label.iov_len = 11; - d->context.iov_base = "ServerOut"; - d->context.iov_len = 10; - - d = &twin.decryption; - d->label.iov_base = "SMB2AESCCM"; - d->label.iov_len = 11; - d->context.iov_base = "ServerIn "; - d->context.iov_len = 10; - - return generate_smb3encryptionkey(conn, sess, &twin); -} - -int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn, - struct ksmbd_session *sess) -{ - struct derivation_twin twin; - struct derivation *d; - - d = &twin.encryption; - d->label.iov_base = "SMBS2CCipherKey"; - d->label.iov_len = 16; - d->context.iov_base = sess->Preauth_HashValue; - d->context.iov_len = 64; - - d = &twin.decryption; - d->label.iov_base = "SMBC2SCipherKey"; - d->label.iov_len = 16; - d->context.iov_base = sess->Preauth_HashValue; - d->context.iov_len = 64; - - return generate_smb3encryptionkey(conn, sess, &twin); -} - -int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf, - __u8 *pi_hash) -{ - int rc; - struct smb2_hdr *rcv_hdr = smb2_get_msg(buf); - char *all_bytes_msg = (char *)&rcv_hdr->ProtocolId; - int msg_size = get_rfc1002_len(buf); - struct ksmbd_crypto_ctx *ctx = NULL; - - if (conn->preauth_info->Preauth_HashId != - SMB2_PREAUTH_INTEGRITY_SHA512) - return -EINVAL; - - ctx = ksmbd_crypto_ctx_find_sha512(); - if (!ctx) { - ksmbd_debug(AUTH, "could not alloc sha512\n"); - return -ENOMEM; - } - - rc = crypto_shash_init(CRYPTO_SHA512(ctx)); - if (rc) { - ksmbd_debug(AUTH, "could not init shashn"); - goto out; - } - - rc = crypto_shash_update(CRYPTO_SHA512(ctx), pi_hash, 64); - if (rc) { - ksmbd_debug(AUTH, "could not update with n\n"); - goto out; - } - - rc = crypto_shash_update(CRYPTO_SHA512(ctx), all_bytes_msg, msg_size); - if (rc) { - ksmbd_debug(AUTH, "could not update with n\n"); - goto out; - } - - rc = crypto_shash_final(CRYPTO_SHA512(ctx), pi_hash); - if (rc) { - ksmbd_debug(AUTH, "Could not generate hash err : %d\n", rc); - goto out; - } -out: - ksmbd_release_crypto_ctx(ctx); - return rc; -} - -int ksmbd_gen_sd_hash(struct ksmbd_conn *conn, char *sd_buf, int len, - __u8 *pi_hash) -{ - int rc; - struct ksmbd_crypto_ctx *ctx = NULL; - - ctx = ksmbd_crypto_ctx_find_sha256(); - if (!ctx) { - ksmbd_debug(AUTH, "could not alloc sha256\n"); - return -ENOMEM; - } - - rc = crypto_shash_init(CRYPTO_SHA256(ctx)); - if (rc) { - ksmbd_debug(AUTH, "could not init shashn"); - goto out; - } - - rc = crypto_shash_update(CRYPTO_SHA256(ctx), sd_buf, len); - if (rc) { - ksmbd_debug(AUTH, "could not update with n\n"); - goto out; - } - - rc = crypto_shash_final(CRYPTO_SHA256(ctx), pi_hash); - if (rc) { - ksmbd_debug(AUTH, "Could not generate hash err : %d\n", rc); - goto out; - } -out: - ksmbd_release_crypto_ctx(ctx); - return rc; -} - -static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id, - int enc, u8 *key) -{ - struct ksmbd_session *sess; - u8 *ses_enc_key; - - if (enc) - sess = work->sess; - else - sess = ksmbd_session_lookup_all(work->conn, ses_id); - if (!sess) - return -EINVAL; - - ses_enc_key = enc ? sess->smb3encryptionkey : - sess->smb3decryptionkey; - memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE); - - return 0; -} - -static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf, - unsigned int buflen) -{ - void *addr; - - if (is_vmalloc_addr(buf)) - addr = vmalloc_to_page(buf); - else - addr = virt_to_page(buf); - sg_set_page(sg, addr, buflen, offset_in_page(buf)); -} - -static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec, - u8 *sign) -{ - struct scatterlist *sg; - unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; - int i, nr_entries[3] = {0}, total_entries = 0, sg_idx = 0; - - if (!nvec) - return NULL; - - for (i = 0; i < nvec - 1; i++) { - unsigned long kaddr = (unsigned long)iov[i + 1].iov_base; - - if (is_vmalloc_addr(iov[i + 1].iov_base)) { - nr_entries[i] = ((kaddr + iov[i + 1].iov_len + - PAGE_SIZE - 1) >> PAGE_SHIFT) - - (kaddr >> PAGE_SHIFT); - } else { - nr_entries[i]++; - } - total_entries += nr_entries[i]; - } - - /* Add two entries for transform header and signature */ - total_entries += 2; - - sg = kmalloc_array(total_entries, sizeof(struct scatterlist), GFP_KERNEL); - if (!sg) - return NULL; - - sg_init_table(sg, total_entries); - smb2_sg_set_buf(&sg[sg_idx++], iov[0].iov_base + 24, assoc_data_len); - for (i = 0; i < nvec - 1; i++) { - void *data = iov[i + 1].iov_base; - int len = iov[i + 1].iov_len; - - if (is_vmalloc_addr(data)) { - int j, offset = offset_in_page(data); - - for (j = 0; j < nr_entries[i]; j++) { - unsigned int bytes = PAGE_SIZE - offset; - - if (!len) - break; - - if (bytes > len) - bytes = len; - - sg_set_page(&sg[sg_idx++], - vmalloc_to_page(data), bytes, - offset_in_page(data)); - - data += bytes; - len -= bytes; - offset = 0; - } - } else { - sg_set_page(&sg[sg_idx++], virt_to_page(data), len, - offset_in_page(data)); - } - } - smb2_sg_set_buf(&sg[sg_idx], sign, SMB2_SIGNATURE_SIZE); - return sg; -} - -int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, - unsigned int nvec, int enc) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base); - unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; - int rc; - struct scatterlist *sg; - u8 sign[SMB2_SIGNATURE_SIZE] = {}; - u8 key[SMB3_ENC_DEC_KEY_SIZE]; - struct aead_request *req; - char *iv; - unsigned int iv_len; - struct crypto_aead *tfm; - unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize); - struct ksmbd_crypto_ctx *ctx; - - rc = ksmbd_get_encryption_key(work, - le64_to_cpu(tr_hdr->SessionId), - enc, - key); - if (rc) { - pr_err("Could not get %scryption key\n", enc ? "en" : "de"); - return rc; - } - - if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM || - conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) - ctx = ksmbd_crypto_ctx_find_gcm(); - else - ctx = ksmbd_crypto_ctx_find_ccm(); - if (!ctx) { - pr_err("crypto alloc failed\n"); - return -ENOMEM; - } - - if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM || - conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) - tfm = CRYPTO_GCM(ctx); - else - tfm = CRYPTO_CCM(ctx); - - if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || - conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) - rc = crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE); - else - rc = crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE); - if (rc) { - pr_err("Failed to set aead key %d\n", rc); - goto free_ctx; - } - - rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE); - if (rc) { - pr_err("Failed to set authsize %d\n", rc); - goto free_ctx; - } - - req = aead_request_alloc(tfm, GFP_KERNEL); - if (!req) { - rc = -ENOMEM; - goto free_ctx; - } - - if (!enc) { - memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE); - crypt_len += SMB2_SIGNATURE_SIZE; - } - - sg = ksmbd_init_sg(iov, nvec, sign); - if (!sg) { - pr_err("Failed to init sg\n"); - rc = -ENOMEM; - goto free_req; - } - - iv_len = crypto_aead_ivsize(tfm); - iv = kzalloc(iv_len, GFP_KERNEL); - if (!iv) { - rc = -ENOMEM; - goto free_sg; - } - - if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM || - conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) { - memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE); - } else { - iv[0] = 3; - memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE); - } - - aead_request_set_crypt(req, sg, sg, crypt_len, iv); - aead_request_set_ad(req, assoc_data_len); - aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); - - if (enc) - rc = crypto_aead_encrypt(req); - else - rc = crypto_aead_decrypt(req); - if (rc) - goto free_iv; - - if (enc) - memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE); - -free_iv: - kfree(iv); -free_sg: - kfree(sg); -free_req: - kfree(req); -free_ctx: - ksmbd_release_crypto_ctx(ctx); - return rc; -} diff --git a/fs/ksmbd/auth.h b/fs/ksmbd/auth.h deleted file mode 100644 index 362b6159a6cf..000000000000 --- a/fs/ksmbd/auth.h +++ /dev/null @@ -1,71 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __AUTH_H__ -#define __AUTH_H__ - -#include "ntlmssp.h" - -#ifdef CONFIG_SMB_SERVER_KERBEROS5 -#define AUTH_GSS_LENGTH 96 -#define AUTH_GSS_PADDING 0 -#else -#define AUTH_GSS_LENGTH 74 -#define AUTH_GSS_PADDING 6 -#endif - -#define CIFS_HMAC_MD5_HASH_SIZE (16) -#define CIFS_NTHASH_SIZE (16) - -/* - * Size of the ntlm client response - */ -#define CIFS_AUTH_RESP_SIZE 24 -#define CIFS_SMB1_SIGNATURE_SIZE 8 -#define CIFS_SMB1_SESSKEY_SIZE 16 - -#define KSMBD_AUTH_NTLMSSP 0x0001 -#define KSMBD_AUTH_KRB5 0x0002 -#define KSMBD_AUTH_MSKRB5 0x0004 -#define KSMBD_AUTH_KRB5U2U 0x0008 - -struct ksmbd_session; -struct ksmbd_conn; -struct ksmbd_work; -struct kvec; - -int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, - unsigned int nvec, int enc); -void ksmbd_copy_gss_neg_header(void *buf); -int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, - struct ntlmv2_resp *ntlmv2, int blen, char *domain_name, - char *cryptkey); -int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob, - int blob_len, struct ksmbd_conn *conn, - struct ksmbd_session *sess); -int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob, - int blob_len, struct ksmbd_conn *conn); -unsigned int -ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob, - struct ksmbd_conn *conn); -int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, - int in_len, char *out_blob, int *out_len); -int ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, - int n_vec, char *sig); -int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, - int n_vec, char *sig); -int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess, - struct ksmbd_conn *conn); -int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess, - struct ksmbd_conn *conn); -int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn, - struct ksmbd_session *sess); -int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn, - struct ksmbd_session *sess); -int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf, - __u8 *pi_hash); -int ksmbd_gen_sd_hash(struct ksmbd_conn *conn, char *sd_buf, int len, - __u8 *pi_hash); -#endif diff --git a/fs/ksmbd/connection.c b/fs/ksmbd/connection.c deleted file mode 100644 index e1d2be19cddf..000000000000 --- a/fs/ksmbd/connection.c +++ /dev/null @@ -1,485 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Namjae Jeon <namjae.jeon@protocolfreedom.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/mutex.h> -#include <linux/freezer.h> -#include <linux/module.h> - -#include "server.h" -#include "smb_common.h" -#include "mgmt/ksmbd_ida.h" -#include "connection.h" -#include "transport_tcp.h" -#include "transport_rdma.h" - -static DEFINE_MUTEX(init_lock); - -static struct ksmbd_conn_ops default_conn_ops; - -LIST_HEAD(conn_list); -DECLARE_RWSEM(conn_list_lock); - -/** - * ksmbd_conn_free() - free resources of the connection instance - * - * @conn: connection instance to be cleand up - * - * During the thread termination, the corresponding conn instance - * resources(sock/memory) are released and finally the conn object is freed. - */ -void ksmbd_conn_free(struct ksmbd_conn *conn) -{ - down_write(&conn_list_lock); - list_del(&conn->conns_list); - up_write(&conn_list_lock); - - xa_destroy(&conn->sessions); - kvfree(conn->request_buf); - kfree(conn->preauth_info); - kfree(conn); -} - -/** - * ksmbd_conn_alloc() - initialize a new connection instance - * - * Return: ksmbd_conn struct on success, otherwise NULL - */ -struct ksmbd_conn *ksmbd_conn_alloc(void) -{ - struct ksmbd_conn *conn; - - conn = kzalloc(sizeof(struct ksmbd_conn), GFP_KERNEL); - if (!conn) - return NULL; - - conn->need_neg = true; - ksmbd_conn_set_new(conn); - conn->local_nls = load_nls("utf8"); - if (!conn->local_nls) - 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->r_count, 0); - conn->total_credits = 1; - conn->outstanding_credits = 0; - - init_waitqueue_head(&conn->req_running_q); - init_waitqueue_head(&conn->r_count_q); - INIT_LIST_HEAD(&conn->conns_list); - INIT_LIST_HEAD(&conn->requests); - INIT_LIST_HEAD(&conn->async_requests); - spin_lock_init(&conn->request_lock); - spin_lock_init(&conn->credits_lock); - ida_init(&conn->async_ida); - xa_init(&conn->sessions); - - spin_lock_init(&conn->llist_lock); - INIT_LIST_HEAD(&conn->lock_list); - - down_write(&conn_list_lock); - list_add(&conn->conns_list, &conn_list); - up_write(&conn_list_lock); - return conn; -} - -bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c) -{ - struct ksmbd_conn *t; - bool ret = false; - - down_read(&conn_list_lock); - list_for_each_entry(t, &conn_list, conns_list) { - if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE)) - continue; - - ret = true; - break; - } - up_read(&conn_list_lock); - return ret; -} - -void ksmbd_conn_enqueue_request(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct list_head *requests_queue = NULL; - - if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE) { - requests_queue = &conn->requests; - work->syncronous = true; - } - - if (requests_queue) { - atomic_inc(&conn->req_running); - spin_lock(&conn->request_lock); - list_add_tail(&work->request_entry, requests_queue); - spin_unlock(&conn->request_lock); - } -} - -int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - int ret = 1; - - if (list_empty(&work->request_entry) && - list_empty(&work->async_request_entry)) - return 0; - - if (!work->multiRsp) - atomic_dec(&conn->req_running); - spin_lock(&conn->request_lock); - if (!work->multiRsp) { - list_del_init(&work->request_entry); - if (work->syncronous == false) - list_del_init(&work->async_request_entry); - ret = 0; - } - spin_unlock(&conn->request_lock); - - wake_up_all(&conn->req_running_q); - return ret; -} - -void ksmbd_conn_lock(struct ksmbd_conn *conn) -{ - mutex_lock(&conn->srv_mutex); -} - -void ksmbd_conn_unlock(struct ksmbd_conn *conn) -{ - mutex_unlock(&conn->srv_mutex); -} - -void ksmbd_all_conn_set_status(u64 sess_id, u32 status) -{ - struct ksmbd_conn *conn; - - down_read(&conn_list_lock); - list_for_each_entry(conn, &conn_list, conns_list) { - if (conn->binding || xa_load(&conn->sessions, sess_id)) - WRITE_ONCE(conn->status, status); - } - up_read(&conn_list_lock); -} - -void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id) -{ - struct ksmbd_conn *bind_conn; - - wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2); - - down_read(&conn_list_lock); - list_for_each_entry(bind_conn, &conn_list, conns_list) { - if (bind_conn == conn) - continue; - - if ((bind_conn->binding || xa_load(&bind_conn->sessions, sess_id)) && - !ksmbd_conn_releasing(bind_conn) && - atomic_read(&bind_conn->req_running)) { - wait_event(bind_conn->req_running_q, - atomic_read(&bind_conn->req_running) == 0); - } - } - up_read(&conn_list_lock); -} - -int ksmbd_conn_write(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - size_t len = 0; - int sent; - struct kvec iov[3]; - int iov_idx = 0; - - if (!work->response_buf) { - pr_err("NULL response header\n"); - return -EINVAL; - } - - if (work->tr_buf) { - iov[iov_idx] = (struct kvec) { work->tr_buf, - sizeof(struct smb2_transform_hdr) + 4 }; - len += iov[iov_idx++].iov_len; - } - - if (work->aux_payload_sz) { - iov[iov_idx] = (struct kvec) { work->response_buf, work->resp_hdr_sz }; - len += iov[iov_idx++].iov_len; - iov[iov_idx] = (struct kvec) { work->aux_payload_buf, work->aux_payload_sz }; - len += iov[iov_idx++].iov_len; - } else { - if (work->tr_buf) - iov[iov_idx].iov_len = work->resp_hdr_sz; - else - iov[iov_idx].iov_len = get_rfc1002_len(work->response_buf) + 4; - iov[iov_idx].iov_base = work->response_buf; - len += iov[iov_idx++].iov_len; - } - - ksmbd_conn_lock(conn); - sent = conn->transport->ops->writev(conn->transport, &iov[0], - iov_idx, len, - work->need_invalidate_rkey, - work->remote_key); - ksmbd_conn_unlock(conn); - - if (sent < 0) { - pr_err("Failed to send message: %d\n", sent); - return sent; - } - - return 0; -} - -int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, - void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, - unsigned int desc_len) -{ - int ret = -EINVAL; - - if (conn->transport->ops->rdma_read) - ret = conn->transport->ops->rdma_read(conn->transport, - buf, buflen, - desc, desc_len); - return ret; -} - -int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, - void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, - unsigned int desc_len) -{ - int ret = -EINVAL; - - if (conn->transport->ops->rdma_write) - ret = conn->transport->ops->rdma_write(conn->transport, - buf, buflen, - desc, desc_len); - return ret; -} - -bool ksmbd_conn_alive(struct ksmbd_conn *conn) -{ - if (!ksmbd_server_running()) - return false; - - if (ksmbd_conn_exiting(conn)) - return false; - - if (kthread_should_stop()) - return false; - - if (atomic_read(&conn->stats.open_files_count) > 0) - return true; - - /* - * Stop current session if the time that get last request from client - * is bigger than deadtime user configured and opening file count is - * zero. - */ - if (server_conf.deadtime > 0 && - time_after(jiffies, conn->last_active + server_conf.deadtime)) { - ksmbd_debug(CONN, "No response from client in %lu minutes\n", - server_conf.deadtime / SMB_ECHO_INTERVAL); - return false; - } - return true; -} - -#define SMB1_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb_hdr)) -#define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4) - -/** - * ksmbd_conn_handler_loop() - session thread to listen on new smb requests - * @p: connection instance - * - * One thread each per connection - * - * Return: 0 on success - */ -int ksmbd_conn_handler_loop(void *p) -{ - struct ksmbd_conn *conn = (struct ksmbd_conn *)p; - struct ksmbd_transport *t = conn->transport; - unsigned int pdu_size, max_allowed_pdu_size; - char hdr_buf[4] = {0,}; - int size; - - mutex_init(&conn->srv_mutex); - __module_get(THIS_MODULE); - - if (t->ops->prepare && t->ops->prepare(t)) - goto out; - - conn->last_active = jiffies; - while (ksmbd_conn_alive(conn)) { - if (try_to_freeze()) - continue; - - kvfree(conn->request_buf); - conn->request_buf = NULL; - - size = t->ops->read(t, hdr_buf, sizeof(hdr_buf), -1); - if (size != sizeof(hdr_buf)) - break; - - pdu_size = get_rfc1002_len(hdr_buf); - ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size); - - if (ksmbd_conn_good(conn)) - max_allowed_pdu_size = - SMB3_MAX_MSGSIZE + conn->vals->max_write_size; - else - max_allowed_pdu_size = SMB3_MAX_MSGSIZE; - - if (pdu_size > max_allowed_pdu_size) { - pr_err_ratelimited("PDU length(%u) excceed maximum allowed pdu size(%u) on connection(%d)\n", - pdu_size, max_allowed_pdu_size, - READ_ONCE(conn->status)); - break; - } - - /* - * Check maximum pdu size(0x00FFFFFF). - */ - if (pdu_size > MAX_STREAM_PROT_LEN) - break; - - if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE) - break; - - /* 4 for rfc1002 length field */ - /* 1 for implied bcc[0] */ - size = pdu_size + 4 + 1; - conn->request_buf = kvmalloc(size, GFP_KERNEL); - if (!conn->request_buf) - break; - - memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf)); - - /* - * We already read 4 bytes to find out PDU size, now - * read in PDU - */ - size = t->ops->read(t, conn->request_buf + 4, pdu_size, 2); - if (size < 0) { - pr_err("sock_read failed: %d\n", size); - break; - } - - if (size != pdu_size) { - pr_err("PDU error. Read: %d, Expected: %d\n", - size, pdu_size); - continue; - } - - if (!ksmbd_smb_request(conn)) - break; - - if (((struct smb2_hdr *)smb2_get_msg(conn->request_buf))->ProtocolId == - SMB2_PROTO_NUMBER) { - if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE) - break; - } - - if (!default_conn_ops.process_fn) { - pr_err("No connection request callback\n"); - break; - } - - if (default_conn_ops.process_fn(conn)) { - pr_err("Cannot handle request\n"); - break; - } - } - -out: - ksmbd_conn_set_releasing(conn); - /* Wait till all reference dropped to the Server object*/ - 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); - if (default_conn_ops.terminate_fn) - default_conn_ops.terminate_fn(conn); - t->ops->disconnect(t); - module_put(THIS_MODULE); - return 0; -} - -void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops) -{ - default_conn_ops.process_fn = ops->process_fn; - default_conn_ops.terminate_fn = ops->terminate_fn; -} - -int ksmbd_conn_transport_init(void) -{ - int ret; - - mutex_lock(&init_lock); - ret = ksmbd_tcp_init(); - if (ret) { - pr_err("Failed to init TCP subsystem: %d\n", ret); - goto out; - } - - ret = ksmbd_rdma_init(); - if (ret) { - pr_err("Failed to init RDMA subsystem: %d\n", ret); - goto out; - } -out: - mutex_unlock(&init_lock); - return ret; -} - -static void stop_sessions(void) -{ - struct ksmbd_conn *conn; - struct ksmbd_transport *t; - -again: - down_read(&conn_list_lock); - list_for_each_entry(conn, &conn_list, conns_list) { - struct task_struct *task; - - t = conn->transport; - task = t->handler; - if (task) - ksmbd_debug(CONN, "Stop session handler %s/%d\n", - task->comm, task_pid_nr(task)); - ksmbd_conn_set_exiting(conn); - if (t->ops->shutdown) { - up_read(&conn_list_lock); - t->ops->shutdown(t); - down_read(&conn_list_lock); - } - } - up_read(&conn_list_lock); - - if (!list_empty(&conn_list)) { - schedule_timeout_interruptible(HZ / 10); /* 100ms */ - goto again; - } -} - -void ksmbd_conn_transport_destroy(void) -{ - mutex_lock(&init_lock); - ksmbd_tcp_destroy(); - ksmbd_rdma_destroy(); - stop_sessions(); - mutex_unlock(&init_lock); -} diff --git a/fs/ksmbd/connection.h b/fs/ksmbd/connection.h deleted file mode 100644 index ad8dfaa48ffb..000000000000 --- a/fs/ksmbd/connection.h +++ /dev/null @@ -1,231 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __KSMBD_CONNECTION_H__ -#define __KSMBD_CONNECTION_H__ - -#include <linux/list.h> -#include <linux/ip.h> -#include <net/sock.h> -#include <net/tcp.h> -#include <net/inet_connection_sock.h> -#include <net/request_sock.h> -#include <linux/kthread.h> -#include <linux/nls.h> -#include <linux/unicode.h> - -#include "smb_common.h" -#include "ksmbd_work.h" - -#define KSMBD_SOCKET_BACKLOG 16 - -enum { - KSMBD_SESS_NEW = 0, - KSMBD_SESS_GOOD, - KSMBD_SESS_EXITING, - KSMBD_SESS_NEED_RECONNECT, - KSMBD_SESS_NEED_NEGOTIATE, - KSMBD_SESS_RELEASING -}; - -struct ksmbd_stats { - atomic_t open_files_count; - atomic64_t request_served; -}; - -struct ksmbd_transport; - -struct ksmbd_conn { - struct smb_version_values *vals; - struct smb_version_ops *ops; - struct smb_version_cmds *cmds; - unsigned int max_cmds; - struct mutex srv_mutex; - int status; - unsigned int cli_cap; - char *request_buf; - struct ksmbd_transport *transport; - struct nls_table *local_nls; - struct unicode_map *um; - struct list_head conns_list; - /* smb session 1 per user */ - struct xarray sessions; - unsigned long last_active; - /* How many request are running currently */ - atomic_t req_running; - /* References which are made for this Server object*/ - atomic_t r_count; - unsigned int total_credits; - unsigned int outstanding_credits; - spinlock_t credits_lock; - wait_queue_head_t req_running_q; - wait_queue_head_t r_count_q; - /* Lock to protect requests list*/ - spinlock_t request_lock; - struct list_head requests; - struct list_head async_requests; - int connection_type; - struct ksmbd_stats stats; - char ClientGUID[SMB2_CLIENT_GUID_SIZE]; - struct ntlmssp_auth ntlmssp; - - spinlock_t llist_lock; - struct list_head lock_list; - - struct preauth_integrity_info *preauth_info; - - bool need_neg; - unsigned int auth_mechs; - unsigned int preferred_auth_mech; - bool sign; - bool use_spnego:1; - __u16 cli_sec_mode; - __u16 srv_sec_mode; - /* dialect index that server chose */ - __u16 dialect; - - char *mechToken; - - struct ksmbd_conn_ops *conn_ops; - - /* Preauth Session Table */ - struct list_head preauth_sess_table; - - struct sockaddr_storage peer_addr; - - /* Identifier for async message */ - struct ida async_ida; - - __le16 cipher_type; - __le16 compress_algorithm; - bool posix_ext_supported; - bool signing_negotiated; - __le16 signing_algorithm; - bool binding; -}; - -struct ksmbd_conn_ops { - int (*process_fn)(struct ksmbd_conn *conn); - int (*terminate_fn)(struct ksmbd_conn *conn); -}; - -struct ksmbd_transport_ops { - int (*prepare)(struct ksmbd_transport *t); - void (*disconnect)(struct ksmbd_transport *t); - void (*shutdown)(struct ksmbd_transport *t); - int (*read)(struct ksmbd_transport *t, char *buf, - unsigned int size, int max_retries); - int (*writev)(struct ksmbd_transport *t, struct kvec *iovs, int niov, - int size, bool need_invalidate_rkey, - unsigned int remote_key); - int (*rdma_read)(struct ksmbd_transport *t, - void *buf, unsigned int len, - struct smb2_buffer_desc_v1 *desc, - unsigned int desc_len); - int (*rdma_write)(struct ksmbd_transport *t, - void *buf, unsigned int len, - struct smb2_buffer_desc_v1 *desc, - unsigned int desc_len); -}; - -struct ksmbd_transport { - struct ksmbd_conn *conn; - struct ksmbd_transport_ops *ops; - struct task_struct *handler; -}; - -#define KSMBD_TCP_RECV_TIMEOUT (7 * HZ) -#define KSMBD_TCP_SEND_TIMEOUT (5 * HZ) -#define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr)) - -extern struct list_head conn_list; -extern struct rw_semaphore conn_list_lock; - -bool ksmbd_conn_alive(struct ksmbd_conn *conn); -void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id); -struct ksmbd_conn *ksmbd_conn_alloc(void); -void ksmbd_conn_free(struct ksmbd_conn *conn); -bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c); -int ksmbd_conn_write(struct ksmbd_work *work); -int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, - void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, - unsigned int desc_len); -int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, - void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, - unsigned int desc_len); -void ksmbd_conn_enqueue_request(struct ksmbd_work *work); -int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work); -void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops); -int ksmbd_conn_handler_loop(void *p); -int ksmbd_conn_transport_init(void); -void ksmbd_conn_transport_destroy(void); -void ksmbd_conn_lock(struct ksmbd_conn *conn); -void ksmbd_conn_unlock(struct ksmbd_conn *conn); - -/* - * WARNING - * - * This is a hack. We will move status to a proper place once we land - * a multi-sessions support. - */ -static inline bool ksmbd_conn_good(struct ksmbd_conn *conn) -{ - return READ_ONCE(conn->status) == KSMBD_SESS_GOOD; -} - -static inline bool ksmbd_conn_need_negotiate(struct ksmbd_conn *conn) -{ - return READ_ONCE(conn->status) == KSMBD_SESS_NEED_NEGOTIATE; -} - -static inline bool ksmbd_conn_need_reconnect(struct ksmbd_conn *conn) -{ - return READ_ONCE(conn->status) == KSMBD_SESS_NEED_RECONNECT; -} - -static inline bool ksmbd_conn_exiting(struct ksmbd_conn *conn) -{ - return READ_ONCE(conn->status) == KSMBD_SESS_EXITING; -} - -static inline bool ksmbd_conn_releasing(struct ksmbd_conn *conn) -{ - return READ_ONCE(conn->status) == KSMBD_SESS_RELEASING; -} - -static inline void ksmbd_conn_set_new(struct ksmbd_conn *conn) -{ - WRITE_ONCE(conn->status, KSMBD_SESS_NEW); -} - -static inline void ksmbd_conn_set_good(struct ksmbd_conn *conn) -{ - WRITE_ONCE(conn->status, KSMBD_SESS_GOOD); -} - -static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_conn *conn) -{ - WRITE_ONCE(conn->status, KSMBD_SESS_NEED_NEGOTIATE); -} - -static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_conn *conn) -{ - WRITE_ONCE(conn->status, KSMBD_SESS_NEED_RECONNECT); -} - -static inline void ksmbd_conn_set_exiting(struct ksmbd_conn *conn) -{ - WRITE_ONCE(conn->status, KSMBD_SESS_EXITING); -} - -static inline void ksmbd_conn_set_releasing(struct ksmbd_conn *conn) -{ - WRITE_ONCE(conn->status, KSMBD_SESS_RELEASING); -} - -void ksmbd_all_conn_set_status(u64 sess_id, u32 status); -#endif /* __CONNECTION_H__ */ diff --git a/fs/ksmbd/crypto_ctx.c b/fs/ksmbd/crypto_ctx.c deleted file mode 100644 index 81488d04199d..000000000000 --- a/fs/ksmbd/crypto_ctx.c +++ /dev/null @@ -1,266 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2019 Samsung Electronics Co., Ltd. - */ - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/err.h> -#include <linux/slab.h> -#include <linux/wait.h> -#include <linux/sched.h> - -#include "glob.h" -#include "crypto_ctx.h" - -struct crypto_ctx_list { - spinlock_t ctx_lock; - int avail_ctx; - struct list_head idle_ctx; - wait_queue_head_t ctx_wait; -}; - -static struct crypto_ctx_list ctx_list; - -static inline void free_aead(struct crypto_aead *aead) -{ - if (aead) - crypto_free_aead(aead); -} - -static void free_shash(struct shash_desc *shash) -{ - if (shash) { - crypto_free_shash(shash->tfm); - kfree(shash); - } -} - -static struct crypto_aead *alloc_aead(int id) -{ - struct crypto_aead *tfm = NULL; - - switch (id) { - case CRYPTO_AEAD_AES_GCM: - tfm = crypto_alloc_aead("gcm(aes)", 0, 0); - break; - case CRYPTO_AEAD_AES_CCM: - tfm = crypto_alloc_aead("ccm(aes)", 0, 0); - break; - default: - pr_err("Does not support encrypt ahead(id : %d)\n", id); - return NULL; - } - - if (IS_ERR(tfm)) { - pr_err("Failed to alloc encrypt aead : %ld\n", PTR_ERR(tfm)); - return NULL; - } - - return tfm; -} - -static struct shash_desc *alloc_shash_desc(int id) -{ - struct crypto_shash *tfm = NULL; - struct shash_desc *shash; - - switch (id) { - case CRYPTO_SHASH_HMACMD5: - tfm = crypto_alloc_shash("hmac(md5)", 0, 0); - break; - case CRYPTO_SHASH_HMACSHA256: - tfm = crypto_alloc_shash("hmac(sha256)", 0, 0); - break; - case CRYPTO_SHASH_CMACAES: - tfm = crypto_alloc_shash("cmac(aes)", 0, 0); - break; - case CRYPTO_SHASH_SHA256: - tfm = crypto_alloc_shash("sha256", 0, 0); - break; - case CRYPTO_SHASH_SHA512: - tfm = crypto_alloc_shash("sha512", 0, 0); - break; - default: - return NULL; - } - - if (IS_ERR(tfm)) - return NULL; - - shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm), - GFP_KERNEL); - if (!shash) - crypto_free_shash(tfm); - else - shash->tfm = tfm; - return shash; -} - -static void ctx_free(struct ksmbd_crypto_ctx *ctx) -{ - int i; - - for (i = 0; i < CRYPTO_SHASH_MAX; i++) - free_shash(ctx->desc[i]); - for (i = 0; i < CRYPTO_AEAD_MAX; i++) - free_aead(ctx->ccmaes[i]); - kfree(ctx); -} - -static struct ksmbd_crypto_ctx *ksmbd_find_crypto_ctx(void) -{ - struct ksmbd_crypto_ctx *ctx; - - while (1) { - spin_lock(&ctx_list.ctx_lock); - if (!list_empty(&ctx_list.idle_ctx)) { - ctx = list_entry(ctx_list.idle_ctx.next, - struct ksmbd_crypto_ctx, - list); - list_del(&ctx->list); - spin_unlock(&ctx_list.ctx_lock); - return ctx; - } - - if (ctx_list.avail_ctx > num_online_cpus()) { - spin_unlock(&ctx_list.ctx_lock); - wait_event(ctx_list.ctx_wait, - !list_empty(&ctx_list.idle_ctx)); - continue; - } - - ctx_list.avail_ctx++; - spin_unlock(&ctx_list.ctx_lock); - - ctx = kzalloc(sizeof(struct ksmbd_crypto_ctx), GFP_KERNEL); - if (!ctx) { - spin_lock(&ctx_list.ctx_lock); - ctx_list.avail_ctx--; - spin_unlock(&ctx_list.ctx_lock); - wait_event(ctx_list.ctx_wait, - !list_empty(&ctx_list.idle_ctx)); - continue; - } - break; - } - return ctx; -} - -void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx) -{ - if (!ctx) - return; - - spin_lock(&ctx_list.ctx_lock); - if (ctx_list.avail_ctx <= num_online_cpus()) { - list_add(&ctx->list, &ctx_list.idle_ctx); - spin_unlock(&ctx_list.ctx_lock); - wake_up(&ctx_list.ctx_wait); - return; - } - - ctx_list.avail_ctx--; - spin_unlock(&ctx_list.ctx_lock); - ctx_free(ctx); -} - -static struct ksmbd_crypto_ctx *____crypto_shash_ctx_find(int id) -{ - struct ksmbd_crypto_ctx *ctx; - - if (id >= CRYPTO_SHASH_MAX) - return NULL; - - ctx = ksmbd_find_crypto_ctx(); - if (ctx->desc[id]) - return ctx; - - ctx->desc[id] = alloc_shash_desc(id); - if (ctx->desc[id]) - return ctx; - ksmbd_release_crypto_ctx(ctx); - return NULL; -} - -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void) -{ - return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACMD5); -} - -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacsha256(void) -{ - return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACSHA256); -} - -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void) -{ - return ____crypto_shash_ctx_find(CRYPTO_SHASH_CMACAES); -} - -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha256(void) -{ - return ____crypto_shash_ctx_find(CRYPTO_SHASH_SHA256); -} - -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha512(void) -{ - return ____crypto_shash_ctx_find(CRYPTO_SHASH_SHA512); -} - -static struct ksmbd_crypto_ctx *____crypto_aead_ctx_find(int id) -{ - struct ksmbd_crypto_ctx *ctx; - - if (id >= CRYPTO_AEAD_MAX) - return NULL; - - ctx = ksmbd_find_crypto_ctx(); - if (ctx->ccmaes[id]) - return ctx; - - ctx->ccmaes[id] = alloc_aead(id); - if (ctx->ccmaes[id]) - return ctx; - ksmbd_release_crypto_ctx(ctx); - return NULL; -} - -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void) -{ - return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_GCM); -} - -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void) -{ - return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_CCM); -} - -void ksmbd_crypto_destroy(void) -{ - struct ksmbd_crypto_ctx *ctx; - - while (!list_empty(&ctx_list.idle_ctx)) { - ctx = list_entry(ctx_list.idle_ctx.next, - struct ksmbd_crypto_ctx, - list); - list_del(&ctx->list); - ctx_free(ctx); - } -} - -int ksmbd_crypto_create(void) -{ - struct ksmbd_crypto_ctx *ctx; - - spin_lock_init(&ctx_list.ctx_lock); - INIT_LIST_HEAD(&ctx_list.idle_ctx); - init_waitqueue_head(&ctx_list.ctx_wait); - ctx_list.avail_ctx = 1; - - ctx = kzalloc(sizeof(struct ksmbd_crypto_ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - list_add(&ctx->list, &ctx_list.idle_ctx); - return 0; -} diff --git a/fs/ksmbd/crypto_ctx.h b/fs/ksmbd/crypto_ctx.h deleted file mode 100644 index 4a367c62f653..000000000000 --- a/fs/ksmbd/crypto_ctx.h +++ /dev/null @@ -1,66 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2019 Samsung Electronics Co., Ltd. - */ - -#ifndef __CRYPTO_CTX_H__ -#define __CRYPTO_CTX_H__ - -#include <crypto/hash.h> -#include <crypto/aead.h> - -enum { - CRYPTO_SHASH_HMACMD5 = 0, - CRYPTO_SHASH_HMACSHA256, - CRYPTO_SHASH_CMACAES, - CRYPTO_SHASH_SHA256, - CRYPTO_SHASH_SHA512, - CRYPTO_SHASH_MAX, -}; - -enum { - CRYPTO_AEAD_AES_GCM = 16, - CRYPTO_AEAD_AES_CCM, - CRYPTO_AEAD_MAX, -}; - -enum { - CRYPTO_BLK_ECBDES = 32, - CRYPTO_BLK_MAX, -}; - -struct ksmbd_crypto_ctx { - struct list_head list; - - struct shash_desc *desc[CRYPTO_SHASH_MAX]; - struct crypto_aead *ccmaes[CRYPTO_AEAD_MAX]; -}; - -#define CRYPTO_HMACMD5(c) ((c)->desc[CRYPTO_SHASH_HMACMD5]) -#define CRYPTO_HMACSHA256(c) ((c)->desc[CRYPTO_SHASH_HMACSHA256]) -#define CRYPTO_CMACAES(c) ((c)->desc[CRYPTO_SHASH_CMACAES]) -#define CRYPTO_SHA256(c) ((c)->desc[CRYPTO_SHASH_SHA256]) -#define CRYPTO_SHA512(c) ((c)->desc[CRYPTO_SHASH_SHA512]) - -#define CRYPTO_HMACMD5_TFM(c) ((c)->desc[CRYPTO_SHASH_HMACMD5]->tfm) -#define CRYPTO_HMACSHA256_TFM(c)\ - ((c)->desc[CRYPTO_SHASH_HMACSHA256]->tfm) -#define CRYPTO_CMACAES_TFM(c) ((c)->desc[CRYPTO_SHASH_CMACAES]->tfm) -#define CRYPTO_SHA256_TFM(c) ((c)->desc[CRYPTO_SHASH_SHA256]->tfm) -#define CRYPTO_SHA512_TFM(c) ((c)->desc[CRYPTO_SHASH_SHA512]->tfm) - -#define CRYPTO_GCM(c) ((c)->ccmaes[CRYPTO_AEAD_AES_GCM]) -#define CRYPTO_CCM(c) ((c)->ccmaes[CRYPTO_AEAD_AES_CCM]) - -void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx); -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void); -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacsha256(void); -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void); -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha512(void); -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha256(void); -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void); -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void); -void ksmbd_crypto_destroy(void); -int ksmbd_crypto_create(void); - -#endif /* __CRYPTO_CTX_H__ */ diff --git a/fs/ksmbd/glob.h b/fs/ksmbd/glob.h deleted file mode 100644 index 5b8f3e0ebdb3..000000000000 --- a/fs/ksmbd/glob.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __KSMBD_GLOB_H -#define __KSMBD_GLOB_H - -#include <linux/ctype.h> - -#include "unicode.h" -#include "vfs_cache.h" - -#define KSMBD_VERSION "3.4.2" - -extern int ksmbd_debug_types; - -#define KSMBD_DEBUG_SMB BIT(0) -#define KSMBD_DEBUG_AUTH BIT(1) -#define KSMBD_DEBUG_VFS BIT(2) -#define KSMBD_DEBUG_OPLOCK BIT(3) -#define KSMBD_DEBUG_IPC BIT(4) -#define KSMBD_DEBUG_CONN BIT(5) -#define KSMBD_DEBUG_RDMA BIT(6) -#define KSMBD_DEBUG_ALL (KSMBD_DEBUG_SMB | KSMBD_DEBUG_AUTH | \ - KSMBD_DEBUG_VFS | KSMBD_DEBUG_OPLOCK | \ - KSMBD_DEBUG_IPC | KSMBD_DEBUG_CONN | \ - KSMBD_DEBUG_RDMA) - -#ifdef pr_fmt -#undef pr_fmt -#endif - -#ifdef SUBMOD_NAME -#define pr_fmt(fmt) "ksmbd: " SUBMOD_NAME ": " fmt -#else -#define pr_fmt(fmt) "ksmbd: " fmt -#endif - -#define ksmbd_debug(type, fmt, ...) \ - do { \ - if (ksmbd_debug_types & KSMBD_DEBUG_##type) \ - pr_info(fmt, ##__VA_ARGS__); \ - } while (0) - -#define UNICODE_LEN(x) ((x) * 2) - -#endif /* __KSMBD_GLOB_H */ diff --git a/fs/ksmbd/ksmbd_netlink.h b/fs/ksmbd/ksmbd_netlink.h deleted file mode 100644 index ce866ff159bf..000000000000 --- a/fs/ksmbd/ksmbd_netlink.h +++ /dev/null @@ -1,412 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - * - * linux-ksmbd-devel@lists.sourceforge.net - */ - -#ifndef _LINUX_KSMBD_SERVER_H -#define _LINUX_KSMBD_SERVER_H - -#include <linux/types.h> - -/* - * This is a userspace ABI to communicate data between ksmbd and user IPC - * daemon using netlink. This is added to track and cache user account DB - * and share configuration info from userspace. - * - * - KSMBD_EVENT_HEARTBEAT_REQUEST(ksmbd_heartbeat) - * This event is to check whether user IPC daemon is alive. If user IPC - * daemon is dead, ksmbd keep existing connection till disconnecting and - * new connection will be denied. - * - * - KSMBD_EVENT_STARTING_UP(ksmbd_startup_request) - * This event is to receive the information that initializes the ksmbd - * server from the user IPC daemon and to start the server. The global - * section parameters are given from smb.conf as initialization - * information. - * - * - KSMBD_EVENT_SHUTTING_DOWN(ksmbd_shutdown_request) - * This event is to shutdown ksmbd server. - * - * - KSMBD_EVENT_LOGIN_REQUEST/RESPONSE(ksmbd_login_request/response) - * This event is to get user account info to user IPC daemon. - * - * - KSMBD_EVENT_SHARE_CONFIG_REQUEST/RESPONSE(ksmbd_share_config_request/response) - * This event is to get net share configuration info. - * - * - KSMBD_EVENT_TREE_CONNECT_REQUEST/RESPONSE(ksmbd_tree_connect_request/response) - * This event is to get session and tree connect info. - * - * - KSMBD_EVENT_TREE_DISCONNECT_REQUEST(ksmbd_tree_disconnect_request) - * This event is to send tree disconnect info to user IPC daemon. - * - * - KSMBD_EVENT_LOGOUT_REQUEST(ksmbd_logout_request) - * This event is to send logout request to user IPC daemon. - * - * - KSMBD_EVENT_RPC_REQUEST/RESPONSE(ksmbd_rpc_command) - * This event is to make DCE/RPC request like srvsvc, wkssvc, lsarpc, - * samr to be processed in userspace. - * - * - KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST/RESPONSE(ksmbd_spnego_authen_request/response) - * This event is to make kerberos authentication to be processed in - * userspace. - */ - -#define KSMBD_GENL_NAME "SMBD_GENL" -#define KSMBD_GENL_VERSION 0x01 - -#define KSMBD_REQ_MAX_ACCOUNT_NAME_SZ 48 -#define KSMBD_REQ_MAX_HASH_SZ 18 -#define KSMBD_REQ_MAX_SHARE_NAME 64 - -/* - * IPC heartbeat frame to check whether user IPC daemon is alive. - */ -struct ksmbd_heartbeat { - __u32 handle; -}; - -/* - * Global config flags. - */ -#define KSMBD_GLOBAL_FLAG_INVALID (0) -#define KSMBD_GLOBAL_FLAG_SMB2_LEASES BIT(0) -#define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION BIT(1) -#define KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL BIT(2) - -/* - * IPC request for ksmbd server startup - */ -struct ksmbd_startup_request { - __u32 flags; /* Flags for global config */ - __s32 signing; /* Signing enabled */ - __s8 min_prot[16]; /* The minimum SMB protocol version */ - __s8 max_prot[16]; /* The maximum SMB protocol version */ - __s8 netbios_name[16]; - __s8 work_group[64]; /* Workgroup */ - __s8 server_string[64]; /* Server string */ - __u16 tcp_port; /* tcp port */ - __u16 ipc_timeout; /* - * specifies the number of seconds - * server will wait for the userspace to - * reply to heartbeat frames. - */ - __u32 deadtime; /* Number of minutes of inactivity */ - __u32 file_max; /* Limits the maximum number of open files */ - __u32 smb2_max_write; /* MAX write size */ - __u32 smb2_max_read; /* MAX read size */ - __u32 smb2_max_trans; /* MAX trans size */ - __u32 share_fake_fscaps; /* - * Support some special application that - * makes QFSINFO calls to check whether - * we set the SPARSE_FILES bit (0x40). - */ - __u32 sub_auth[3]; /* Subauth value for Security ID */ - __u32 smb2_max_credits; /* MAX credits */ - __u32 smbd_max_io_size; /* smbd read write size */ - __u32 max_connections; /* Number of maximum simultaneous connections */ - __u32 reserved[126]; /* Reserved room */ - __u32 ifc_list_sz; /* interfaces list size */ - __s8 ____payload[]; -}; - -#define KSMBD_STARTUP_CONFIG_INTERFACES(s) ((s)->____payload) - -/* - * IPC request to shutdown ksmbd server. - */ -struct ksmbd_shutdown_request { - __s32 reserved[16]; -}; - -/* - * IPC user login request. - */ -struct ksmbd_login_request { - __u32 handle; - __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; /* user account name */ - __u32 reserved[16]; /* Reserved room */ -}; - -/* - * IPC user login response. - */ -struct ksmbd_login_response { - __u32 handle; - __u32 gid; /* group id */ - __u32 uid; /* user id */ - __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; /* user account name */ - __u16 status; - __u16 hash_sz; /* hash size */ - __s8 hash[KSMBD_REQ_MAX_HASH_SZ]; /* password hash */ - __u32 reserved[16]; /* Reserved room */ -}; - -/* - * IPC request to fetch net share config. - */ -struct ksmbd_share_config_request { - __u32 handle; - __s8 share_name[KSMBD_REQ_MAX_SHARE_NAME]; /* share name */ - __u32 reserved[16]; /* Reserved room */ -}; - -/* - * IPC response to the net share config request. - */ -struct ksmbd_share_config_response { - __u32 handle; - __u32 flags; - __u16 create_mask; - __u16 directory_mask; - __u16 force_create_mode; - __u16 force_directory_mode; - __u16 force_uid; - __u16 force_gid; - __s8 share_name[KSMBD_REQ_MAX_SHARE_NAME]; - __u32 reserved[112]; /* Reserved room */ - __u32 veto_list_sz; - __s8 ____payload[]; -}; - -#define KSMBD_SHARE_CONFIG_VETO_LIST(s) ((s)->____payload) - -static inline char * -ksmbd_share_config_path(struct ksmbd_share_config_response *sc) -{ - char *p = sc->____payload; - - if (sc->veto_list_sz) - p += sc->veto_list_sz + 1; - - return p; -} - -/* - * IPC request for tree connection. This request include session and tree - * connect info from client. - */ -struct ksmbd_tree_connect_request { - __u32 handle; - __u16 account_flags; - __u16 flags; - __u64 session_id; - __u64 connect_id; - __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; - __s8 share[KSMBD_REQ_MAX_SHARE_NAME]; - __s8 peer_addr[64]; - __u32 reserved[16]; /* Reserved room */ -}; - -/* - * IPC Response structure for tree connection. - */ -struct ksmbd_tree_connect_response { - __u32 handle; - __u16 status; - __u16 connection_flags; - __u32 reserved[16]; /* Reserved room */ -}; - -/* - * IPC Request struture to disconnect tree connection. - */ -struct ksmbd_tree_disconnect_request { - __u64 session_id; /* session id */ - __u64 connect_id; /* tree connection id */ - __u32 reserved[16]; /* Reserved room */ -}; - -/* - * IPC Response structure to logout user account. - */ -struct ksmbd_logout_request { - __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; /* user account name */ - __u32 account_flags; - __u32 reserved[16]; /* Reserved room */ -}; - -/* - * RPC command structure to send rpc request like srvsvc or wkssvc to - * IPC user daemon. - */ -struct ksmbd_rpc_command { - __u32 handle; - __u32 flags; - __u32 payload_sz; - __u8 payload[]; -}; - -/* - * IPC Request Kerberos authentication - */ -struct ksmbd_spnego_authen_request { - __u32 handle; - __u16 spnego_blob_len; /* the length of spnego_blob */ - __u8 spnego_blob[]; /* - * the GSS token from SecurityBuffer of - * SMB2 SESSION SETUP request - */ -}; - -/* - * Response data which includes the GSS token and the session key generated by - * user daemon. - */ -struct ksmbd_spnego_authen_response { - __u32 handle; - struct ksmbd_login_response login_response; /* - * the login response with - * a user identified by the - * GSS token from a client - */ - __u16 session_key_len; /* the length of the session key */ - __u16 spnego_blob_len; /* - * the length of the GSS token which will be - * stored in SecurityBuffer of SMB2 SESSION - * SETUP response - */ - __u8 payload[]; /* session key + AP_REP */ -}; - -/* - * This also used as NETLINK attribute type value. - * - * NOTE: - * Response message type value should be equal to - * request message type value + 1. - */ -enum ksmbd_event { - KSMBD_EVENT_UNSPEC = 0, - KSMBD_EVENT_HEARTBEAT_REQUEST, - - KSMBD_EVENT_STARTING_UP, - KSMBD_EVENT_SHUTTING_DOWN, - - KSMBD_EVENT_LOGIN_REQUEST, - KSMBD_EVENT_LOGIN_RESPONSE = 5, - - KSMBD_EVENT_SHARE_CONFIG_REQUEST, - KSMBD_EVENT_SHARE_CONFIG_RESPONSE, - - KSMBD_EVENT_TREE_CONNECT_REQUEST, - KSMBD_EVENT_TREE_CONNECT_RESPONSE, - - KSMBD_EVENT_TREE_DISCONNECT_REQUEST = 10, - - KSMBD_EVENT_LOGOUT_REQUEST, - - KSMBD_EVENT_RPC_REQUEST, - KSMBD_EVENT_RPC_RESPONSE, - - KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST, - KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE = 15, - - KSMBD_EVENT_MAX -}; - -/* - * Enumeration for IPC tree connect status. - */ -enum KSMBD_TREE_CONN_STATUS { - KSMBD_TREE_CONN_STATUS_OK = 0, - KSMBD_TREE_CONN_STATUS_NOMEM, - KSMBD_TREE_CONN_STATUS_NO_SHARE, - KSMBD_TREE_CONN_STATUS_NO_USER, - KSMBD_TREE_CONN_STATUS_INVALID_USER, - KSMBD_TREE_CONN_STATUS_HOST_DENIED = 5, - KSMBD_TREE_CONN_STATUS_CONN_EXIST, - KSMBD_TREE_CONN_STATUS_TOO_MANY_CONNS, - KSMBD_TREE_CONN_STATUS_TOO_MANY_SESSIONS, - KSMBD_TREE_CONN_STATUS_ERROR, -}; - -/* - * User config flags. - */ -#define KSMBD_USER_FLAG_INVALID (0) -#define KSMBD_USER_FLAG_OK BIT(0) -#define KSMBD_USER_FLAG_BAD_PASSWORD BIT(1) -#define KSMBD_USER_FLAG_BAD_UID BIT(2) -#define KSMBD_USER_FLAG_BAD_USER BIT(3) -#define KSMBD_USER_FLAG_GUEST_ACCOUNT BIT(4) -#define KSMBD_USER_FLAG_DELAY_SESSION BIT(5) - -/* - * Share config flags. - */ -#define KSMBD_SHARE_FLAG_INVALID (0) -#define KSMBD_SHARE_FLAG_AVAILABLE BIT(0) -#define KSMBD_SHARE_FLAG_BROWSEABLE BIT(1) -#define KSMBD_SHARE_FLAG_WRITEABLE BIT(2) -#define KSMBD_SHARE_FLAG_READONLY BIT(3) -#define KSMBD_SHARE_FLAG_GUEST_OK BIT(4) -#define KSMBD_SHARE_FLAG_GUEST_ONLY BIT(5) -#define KSMBD_SHARE_FLAG_STORE_DOS_ATTRS BIT(6) -#define KSMBD_SHARE_FLAG_OPLOCKS BIT(7) -#define KSMBD_SHARE_FLAG_PIPE BIT(8) -#define KSMBD_SHARE_FLAG_HIDE_DOT_FILES BIT(9) -#define KSMBD_SHARE_FLAG_INHERIT_OWNER BIT(10) -#define KSMBD_SHARE_FLAG_STREAMS BIT(11) -#define KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS BIT(12) -#define KSMBD_SHARE_FLAG_ACL_XATTR BIT(13) -#define KSMBD_SHARE_FLAG_UPDATE BIT(14) - -/* - * Tree connect request flags. - */ -#define KSMBD_TREE_CONN_FLAG_REQUEST_SMB1 (0) -#define KSMBD_TREE_CONN_FLAG_REQUEST_IPV6 BIT(0) -#define KSMBD_TREE_CONN_FLAG_REQUEST_SMB2 BIT(1) - -/* - * Tree connect flags. - */ -#define KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT BIT(0) -#define KSMBD_TREE_CONN_FLAG_READ_ONLY BIT(1) -#define KSMBD_TREE_CONN_FLAG_WRITABLE BIT(2) -#define KSMBD_TREE_CONN_FLAG_ADMIN_ACCOUNT BIT(3) -#define KSMBD_TREE_CONN_FLAG_UPDATE BIT(4) - -/* - * RPC over IPC. - */ -#define KSMBD_RPC_METHOD_RETURN BIT(0) -#define KSMBD_RPC_SRVSVC_METHOD_INVOKE BIT(1) -#define KSMBD_RPC_SRVSVC_METHOD_RETURN (KSMBD_RPC_SRVSVC_METHOD_INVOKE | KSMBD_RPC_METHOD_RETURN) -#define KSMBD_RPC_WKSSVC_METHOD_INVOKE BIT(2) -#define KSMBD_RPC_WKSSVC_METHOD_RETURN (KSMBD_RPC_WKSSVC_METHOD_INVOKE | KSMBD_RPC_METHOD_RETURN) -#define KSMBD_RPC_IOCTL_METHOD (BIT(3) | KSMBD_RPC_METHOD_RETURN) -#define KSMBD_RPC_OPEN_METHOD BIT(4) -#define KSMBD_RPC_WRITE_METHOD BIT(5) -#define KSMBD_RPC_READ_METHOD (BIT(6) | KSMBD_RPC_METHOD_RETURN) -#define KSMBD_RPC_CLOSE_METHOD BIT(7) -#define KSMBD_RPC_RAP_METHOD (BIT(8) | KSMBD_RPC_METHOD_RETURN) -#define KSMBD_RPC_RESTRICTED_CONTEXT BIT(9) -#define KSMBD_RPC_SAMR_METHOD_INVOKE BIT(10) -#define KSMBD_RPC_SAMR_METHOD_RETURN (KSMBD_RPC_SAMR_METHOD_INVOKE | KSMBD_RPC_METHOD_RETURN) -#define KSMBD_RPC_LSARPC_METHOD_INVOKE BIT(11) -#define KSMBD_RPC_LSARPC_METHOD_RETURN (KSMBD_RPC_LSARPC_METHOD_INVOKE | KSMBD_RPC_METHOD_RETURN) - -/* - * RPC status definitions. - */ -#define KSMBD_RPC_OK 0 -#define KSMBD_RPC_EBAD_FUNC 0x00000001 -#define KSMBD_RPC_EACCESS_DENIED 0x00000005 -#define KSMBD_RPC_EBAD_FID 0x00000006 -#define KSMBD_RPC_ENOMEM 0x00000008 -#define KSMBD_RPC_EBAD_DATA 0x0000000D -#define KSMBD_RPC_ENOTIMPLEMENTED 0x00000040 -#define KSMBD_RPC_EINVALID_PARAMETER 0x00000057 -#define KSMBD_RPC_EMORE_DATA 0x000000EA -#define KSMBD_RPC_EINVALID_LEVEL 0x0000007C -#define KSMBD_RPC_SOME_NOT_MAPPED 0x00000107 - -#define KSMBD_CONFIG_OPT_DISABLED 0 -#define KSMBD_CONFIG_OPT_ENABLED 1 -#define KSMBD_CONFIG_OPT_AUTO 2 -#define KSMBD_CONFIG_OPT_MANDATORY 3 - -#endif /* _LINUX_KSMBD_SERVER_H */ diff --git a/fs/ksmbd/ksmbd_spnego_negtokeninit.asn1 b/fs/ksmbd/ksmbd_spnego_negtokeninit.asn1 deleted file mode 100644 index 0065f191b54b..000000000000 --- a/fs/ksmbd/ksmbd_spnego_negtokeninit.asn1 +++ /dev/null @@ -1,31 +0,0 @@ -GSSAPI ::= - [APPLICATION 0] IMPLICIT SEQUENCE { - thisMech - OBJECT IDENTIFIER ({ksmbd_gssapi_this_mech}), - negotiationToken - NegotiationToken - } - -MechType ::= OBJECT IDENTIFIER ({ksmbd_neg_token_init_mech_type}) - -MechTypeList ::= SEQUENCE OF MechType - -NegTokenInit ::= - SEQUENCE { - mechTypes - [0] MechTypeList, - reqFlags - [1] BIT STRING OPTIONAL, - mechToken - [2] OCTET STRING OPTIONAL ({ksmbd_neg_token_init_mech_token}), - mechListMIC - [3] OCTET STRING OPTIONAL - } - -NegotiationToken ::= - CHOICE { - negTokenInit - [0] NegTokenInit, - negTokenTarg - [1] ANY - } diff --git a/fs/ksmbd/ksmbd_spnego_negtokentarg.asn1 b/fs/ksmbd/ksmbd_spnego_negtokentarg.asn1 deleted file mode 100644 index 1151933e7b9c..000000000000 --- a/fs/ksmbd/ksmbd_spnego_negtokentarg.asn1 +++ /dev/null @@ -1,19 +0,0 @@ -GSSAPI ::= - CHOICE { - negTokenInit - [0] ANY, - negTokenTarg - [1] NegTokenTarg - } - -NegTokenTarg ::= - SEQUENCE { - negResult - [0] ENUMERATED OPTIONAL, - supportedMech - [1] OBJECT IDENTIFIER OPTIONAL, - responseToken - [2] OCTET STRING OPTIONAL ({ksmbd_neg_token_targ_resp_token}), - mechListMIC - [3] OCTET STRING OPTIONAL - } diff --git a/fs/ksmbd/ksmbd_work.c b/fs/ksmbd/ksmbd_work.c deleted file mode 100644 index 14b9caebf7a4..000000000000 --- a/fs/ksmbd/ksmbd_work.c +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2019 Samsung Electronics Co., Ltd. - */ - -#include <linux/list.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/workqueue.h> - -#include "server.h" -#include "connection.h" -#include "ksmbd_work.h" -#include "mgmt/ksmbd_ida.h" - -static struct kmem_cache *work_cache; -static struct workqueue_struct *ksmbd_wq; - -struct ksmbd_work *ksmbd_alloc_work_struct(void) -{ - struct ksmbd_work *work = kmem_cache_zalloc(work_cache, GFP_KERNEL); - - if (work) { - work->compound_fid = KSMBD_NO_FID; - work->compound_pfid = KSMBD_NO_FID; - INIT_LIST_HEAD(&work->request_entry); - INIT_LIST_HEAD(&work->async_request_entry); - INIT_LIST_HEAD(&work->fp_entry); - INIT_LIST_HEAD(&work->interim_entry); - } - return work; -} - -void ksmbd_free_work_struct(struct ksmbd_work *work) -{ - WARN_ON(work->saved_cred != NULL); - - kvfree(work->response_buf); - kvfree(work->aux_payload_buf); - kfree(work->tr_buf); - kvfree(work->request_buf); - if (work->async_id) - ksmbd_release_id(&work->conn->async_ida, work->async_id); - kmem_cache_free(work_cache, work); -} - -void ksmbd_work_pool_destroy(void) -{ - kmem_cache_destroy(work_cache); -} - -int ksmbd_work_pool_init(void) -{ - work_cache = kmem_cache_create("ksmbd_work_cache", - sizeof(struct ksmbd_work), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (!work_cache) - return -ENOMEM; - return 0; -} - -int ksmbd_workqueue_init(void) -{ - ksmbd_wq = alloc_workqueue("ksmbd-io", 0, 0); - if (!ksmbd_wq) - return -ENOMEM; - return 0; -} - -void ksmbd_workqueue_destroy(void) -{ - destroy_workqueue(ksmbd_wq); - ksmbd_wq = NULL; -} - -bool ksmbd_queue_work(struct ksmbd_work *work) -{ - return queue_work(ksmbd_wq, &work->work); -} diff --git a/fs/ksmbd/ksmbd_work.h b/fs/ksmbd/ksmbd_work.h deleted file mode 100644 index 5ece58e40c97..000000000000 --- a/fs/ksmbd/ksmbd_work.h +++ /dev/null @@ -1,117 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2019 Samsung Electronics Co., Ltd. - */ - -#ifndef __KSMBD_WORK_H__ -#define __KSMBD_WORK_H__ - -#include <linux/ctype.h> -#include <linux/workqueue.h> - -struct ksmbd_conn; -struct ksmbd_session; -struct ksmbd_tree_connect; - -enum { - KSMBD_WORK_ACTIVE = 0, - KSMBD_WORK_CANCELLED, - KSMBD_WORK_CLOSED, -}; - -/* one of these for every pending CIFS request at the connection */ -struct ksmbd_work { - /* Server corresponding to this mid */ - struct ksmbd_conn *conn; - struct ksmbd_session *sess; - struct ksmbd_tree_connect *tcon; - - /* Pointer to received SMB header */ - void *request_buf; - /* Response buffer */ - void *response_buf; - - /* Read data buffer */ - void *aux_payload_buf; - - /* Next cmd hdr in compound req buf*/ - int next_smb2_rcv_hdr_off; - /* Next cmd hdr in compound rsp buf*/ - int next_smb2_rsp_hdr_off; - - /* - * Current Local FID assigned compound response if SMB2 CREATE - * command is present in compound request - */ - u64 compound_fid; - u64 compound_pfid; - u64 compound_sid; - - const struct cred *saved_cred; - - /* Number of granted credits */ - unsigned int credits_granted; - - /* response smb header size */ - unsigned int resp_hdr_sz; - unsigned int response_sz; - /* Read data count */ - unsigned int aux_payload_sz; - - void *tr_buf; - - unsigned char state; - /* Multiple responses for one request e.g. SMB ECHO */ - bool multiRsp:1; - /* No response for cancelled request */ - bool send_no_response:1; - /* Request is encrypted */ - bool encrypted:1; - /* Is this SYNC or ASYNC ksmbd_work */ - bool syncronous:1; - bool need_invalidate_rkey:1; - - unsigned int remote_key; - /* cancel works */ - int async_id; - void **cancel_argv; - void (*cancel_fn)(void **argv); - - struct work_struct work; - /* List head at conn->requests */ - struct list_head request_entry; - /* List head at conn->async_requests */ - struct list_head async_request_entry; - struct list_head fp_entry; - struct list_head interim_entry; -}; - -/** - * ksmbd_resp_buf_next - Get next buffer on compound response. - * @work: smb work containing response buffer - */ -static inline void *ksmbd_resp_buf_next(struct ksmbd_work *work) -{ - return work->response_buf + work->next_smb2_rsp_hdr_off + 4; -} - -/** - * ksmbd_req_buf_next - Get next buffer on compound request. - * @work: smb work containing response buffer - */ -static inline void *ksmbd_req_buf_next(struct ksmbd_work *work) -{ - return work->request_buf + work->next_smb2_rcv_hdr_off + 4; -} - -struct ksmbd_work *ksmbd_alloc_work_struct(void); -void ksmbd_free_work_struct(struct ksmbd_work *work); - -void ksmbd_work_pool_destroy(void); -int ksmbd_work_pool_init(void); - -int ksmbd_workqueue_init(void); -void ksmbd_workqueue_destroy(void); -bool ksmbd_queue_work(struct ksmbd_work *work); - -#endif /* __KSMBD_WORK_H__ */ diff --git a/fs/ksmbd/mgmt/ksmbd_ida.c b/fs/ksmbd/mgmt/ksmbd_ida.c deleted file mode 100644 index 54194d959a5e..000000000000 --- a/fs/ksmbd/mgmt/ksmbd_ida.c +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include "ksmbd_ida.h" - -static inline int __acquire_id(struct ida *ida, int from, int to) -{ - return ida_simple_get(ida, from, to, GFP_KERNEL); -} - -int ksmbd_acquire_smb2_tid(struct ida *ida) -{ - int id; - - id = __acquire_id(ida, 1, 0xFFFFFFFF); - - return id; -} - -int ksmbd_acquire_smb2_uid(struct ida *ida) -{ - int id; - - id = __acquire_id(ida, 1, 0); - if (id == 0xFFFE) - id = __acquire_id(ida, 1, 0); - - return id; -} - -int ksmbd_acquire_async_msg_id(struct ida *ida) -{ - return __acquire_id(ida, 1, 0); -} - -int ksmbd_acquire_id(struct ida *ida) -{ - return __acquire_id(ida, 0, 0); -} - -void ksmbd_release_id(struct ida *ida, int id) -{ - ida_simple_remove(ida, id); -} diff --git a/fs/ksmbd/mgmt/ksmbd_ida.h b/fs/ksmbd/mgmt/ksmbd_ida.h deleted file mode 100644 index 2bc07b16cfde..000000000000 --- a/fs/ksmbd/mgmt/ksmbd_ida.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __KSMBD_IDA_MANAGEMENT_H__ -#define __KSMBD_IDA_MANAGEMENT_H__ - -#include <linux/slab.h> -#include <linux/idr.h> - -/* - * 2.2.1.6.7 TID Generation - * The value 0xFFFF MUST NOT be used as a valid TID. All other - * possible values for TID, including zero (0x0000), are valid. - * The value 0xFFFF is used to specify all TIDs or no TID, - * depending upon the context in which it is used. - */ -int ksmbd_acquire_smb2_tid(struct ida *ida); - -/* - * 2.2.1.6.8 UID Generation - * The value 0xFFFE was declared reserved in the LAN Manager 1.0 - * documentation, so a value of 0xFFFE SHOULD NOT be used as a - * valid UID.<21> All other possible values for a UID, excluding - * zero (0x0000), are valid. - */ -int ksmbd_acquire_smb2_uid(struct ida *ida); -int ksmbd_acquire_async_msg_id(struct ida *ida); - -int ksmbd_acquire_id(struct ida *ida); - -void ksmbd_release_id(struct ida *ida, int id); -#endif /* __KSMBD_IDA_MANAGEMENT_H__ */ diff --git a/fs/ksmbd/mgmt/share_config.c b/fs/ksmbd/mgmt/share_config.c deleted file mode 100644 index 328a412259dc..000000000000 --- a/fs/ksmbd/mgmt/share_config.c +++ /dev/null @@ -1,234 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/list.h> -#include <linux/jhash.h> -#include <linux/slab.h> -#include <linux/rwsem.h> -#include <linux/parser.h> -#include <linux/namei.h> -#include <linux/sched.h> -#include <linux/mm.h> - -#include "share_config.h" -#include "user_config.h" -#include "user_session.h" -#include "../transport_ipc.h" -#include "../misc.h" - -#define SHARE_HASH_BITS 3 -static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS); -static DECLARE_RWSEM(shares_table_lock); - -struct ksmbd_veto_pattern { - char *pattern; - struct list_head list; -}; - -static unsigned int share_name_hash(const char *name) -{ - return jhash(name, strlen(name), 0); -} - -static void kill_share(struct ksmbd_share_config *share) -{ - while (!list_empty(&share->veto_list)) { - struct ksmbd_veto_pattern *p; - - p = list_entry(share->veto_list.next, - struct ksmbd_veto_pattern, - list); - list_del(&p->list); - kfree(p->pattern); - kfree(p); - } - - if (share->path) - path_put(&share->vfs_path); - kfree(share->name); - kfree(share->path); - kfree(share); -} - -void ksmbd_share_config_del(struct ksmbd_share_config *share) -{ - down_write(&shares_table_lock); - hash_del(&share->hlist); - up_write(&shares_table_lock); -} - -void __ksmbd_share_config_put(struct ksmbd_share_config *share) -{ - ksmbd_share_config_del(share); - kill_share(share); -} - -static struct ksmbd_share_config * -__get_share_config(struct ksmbd_share_config *share) -{ - if (!atomic_inc_not_zero(&share->refcount)) - return NULL; - return share; -} - -static struct ksmbd_share_config *__share_lookup(const char *name) -{ - struct ksmbd_share_config *share; - unsigned int key = share_name_hash(name); - - hash_for_each_possible(shares_table, share, hlist, key) { - if (!strcmp(name, share->name)) - return share; - } - return NULL; -} - -static int parse_veto_list(struct ksmbd_share_config *share, - char *veto_list, - int veto_list_sz) -{ - int sz = 0; - - if (!veto_list_sz) - return 0; - - while (veto_list_sz > 0) { - struct ksmbd_veto_pattern *p; - - sz = strlen(veto_list); - if (!sz) - break; - - p = kzalloc(sizeof(struct ksmbd_veto_pattern), GFP_KERNEL); - if (!p) - return -ENOMEM; - - p->pattern = kstrdup(veto_list, GFP_KERNEL); - if (!p->pattern) { - kfree(p); - return -ENOMEM; - } - - list_add(&p->list, &share->veto_list); - - veto_list += sz + 1; - veto_list_sz -= (sz + 1); - } - - return 0; -} - -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 *share = NULL; - struct ksmbd_share_config *lookup; - int ret; - - resp = ksmbd_ipc_share_config_request(name); - if (!resp) - return NULL; - - if (resp->flags == KSMBD_SHARE_FLAG_INVALID) - 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); - if (!share) - goto out; - - share->flags = resp->flags; - atomic_set(&share->refcount, 1); - INIT_LIST_HEAD(&share->veto_list); - share->name = kstrdup(name, GFP_KERNEL); - - if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) { - share->path = kstrdup(ksmbd_share_config_path(resp), - GFP_KERNEL); - if (share->path) - share->path_sz = strlen(share->path); - share->create_mask = resp->create_mask; - share->directory_mask = resp->directory_mask; - share->force_create_mode = resp->force_create_mode; - share->force_directory_mode = resp->force_directory_mode; - share->force_uid = resp->force_uid; - share->force_gid = resp->force_gid; - ret = parse_veto_list(share, - KSMBD_SHARE_CONFIG_VETO_LIST(resp), - resp->veto_list_sz); - if (!ret && share->path) { - ret = kern_path(share->path, 0, &share->vfs_path); - if (ret) { - ksmbd_debug(SMB, "failed to access '%s'\n", - share->path); - /* Avoid put_path() */ - kfree(share->path); - share->path = NULL; - } - } - if (ret || !share->name) { - kill_share(share); - share = NULL; - goto out; - } - } - - down_write(&shares_table_lock); - lookup = __share_lookup(name); - if (lookup) - lookup = __get_share_config(lookup); - if (!lookup) { - hash_add(shares_table, &share->hlist, share_name_hash(name)); - } else { - kill_share(share); - share = lookup; - } - up_write(&shares_table_lock); - -out: - kvfree(resp); - return share; -} - -struct ksmbd_share_config *ksmbd_share_config_get(struct unicode_map *um, - const char *name) -{ - struct ksmbd_share_config *share; - - down_read(&shares_table_lock); - share = __share_lookup(name); - if (share) - share = __get_share_config(share); - up_read(&shares_table_lock); - - if (share) - return share; - return share_config_request(um, name); -} - -bool ksmbd_share_veto_filename(struct ksmbd_share_config *share, - const char *filename) -{ - struct ksmbd_veto_pattern *p; - - list_for_each_entry(p, &share->veto_list, list) { - if (match_wildcard(p->pattern, filename)) - return true; - } - return false; -} diff --git a/fs/ksmbd/mgmt/share_config.h b/fs/ksmbd/mgmt/share_config.h deleted file mode 100644 index 3fd338293942..000000000000 --- a/fs/ksmbd/mgmt/share_config.h +++ /dev/null @@ -1,82 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __SHARE_CONFIG_MANAGEMENT_H__ -#define __SHARE_CONFIG_MANAGEMENT_H__ - -#include <linux/workqueue.h> -#include <linux/hashtable.h> -#include <linux/path.h> -#include <linux/unicode.h> - -struct ksmbd_share_config { - char *name; - char *path; - - unsigned int path_sz; - unsigned int flags; - struct list_head veto_list; - - struct path vfs_path; - - atomic_t refcount; - struct hlist_node hlist; - unsigned short create_mask; - unsigned short directory_mask; - unsigned short force_create_mode; - unsigned short force_directory_mode; - unsigned short force_uid; - unsigned short force_gid; -}; - -#define KSMBD_SHARE_INVALID_UID ((__u16)-1) -#define KSMBD_SHARE_INVALID_GID ((__u16)-1) - -static inline int share_config_create_mode(struct ksmbd_share_config *share, - umode_t posix_mode) -{ - if (!share->force_create_mode) { - if (!posix_mode) - return share->create_mask; - else - return posix_mode & share->create_mask; - } - return share->force_create_mode & share->create_mask; -} - -static inline int share_config_directory_mode(struct ksmbd_share_config *share, - umode_t posix_mode) -{ - if (!share->force_directory_mode) { - if (!posix_mode) - return share->directory_mask; - else - return posix_mode & share->directory_mask; - } - - return share->force_directory_mode & share->directory_mask; -} - -static inline int test_share_config_flag(struct ksmbd_share_config *share, - int flag) -{ - return share->flags & flag; -} - -void ksmbd_share_config_del(struct ksmbd_share_config *share); -void __ksmbd_share_config_put(struct ksmbd_share_config *share); - -static inline void ksmbd_share_config_put(struct ksmbd_share_config *share) -{ - if (!atomic_dec_and_test(&share->refcount)) - return; - __ksmbd_share_config_put(share); -} - -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, - const char *filename); -#endif /* __SHARE_CONFIG_MANAGEMENT_H__ */ diff --git a/fs/ksmbd/mgmt/tree_connect.c b/fs/ksmbd/mgmt/tree_connect.c deleted file mode 100644 index f07a05f37651..000000000000 --- a/fs/ksmbd/mgmt/tree_connect.c +++ /dev/null @@ -1,147 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/list.h> -#include <linux/slab.h> -#include <linux/xarray.h> - -#include "../transport_ipc.h" -#include "../connection.h" - -#include "tree_connect.h" -#include "user_config.h" -#include "share_config.h" -#include "user_session.h" - -struct ksmbd_tree_conn_status -ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess, - const char *share_name) -{ - struct ksmbd_tree_conn_status status = {-ENOENT, NULL}; - struct ksmbd_tree_connect_response *resp = NULL; - struct ksmbd_share_config *sc; - struct ksmbd_tree_connect *tree_conn = NULL; - struct sockaddr *peer_addr; - int ret; - - sc = ksmbd_share_config_get(conn->um, share_name); - if (!sc) - return status; - - tree_conn = kzalloc(sizeof(struct ksmbd_tree_connect), GFP_KERNEL); - if (!tree_conn) { - status.ret = -ENOMEM; - goto out_error; - } - - tree_conn->id = ksmbd_acquire_tree_conn_id(sess); - if (tree_conn->id < 0) { - status.ret = -EINVAL; - goto out_error; - } - - peer_addr = KSMBD_TCP_PEER_SOCKADDR(conn); - resp = ksmbd_ipc_tree_connect_request(sess, - sc, - tree_conn, - peer_addr); - if (!resp) { - status.ret = -EINVAL; - goto out_error; - } - - status.ret = resp->status; - if (status.ret != KSMBD_TREE_CONN_STATUS_OK) - goto out_error; - - tree_conn->flags = resp->connection_flags; - if (test_tree_conn_flag(tree_conn, KSMBD_TREE_CONN_FLAG_UPDATE)) { - struct ksmbd_share_config *new_sc; - - ksmbd_share_config_del(sc); - new_sc = ksmbd_share_config_get(conn->um, share_name); - if (!new_sc) { - pr_err("Failed to update stale share config\n"); - status.ret = -ESTALE; - goto out_error; - } - ksmbd_share_config_put(sc); - sc = new_sc; - } - - tree_conn->user = sess->user; - tree_conn->share_conf = sc; - status.tree_conn = tree_conn; - - ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn, - GFP_KERNEL)); - if (ret) { - status.ret = -ENOMEM; - goto out_error; - } - kvfree(resp); - return status; - -out_error: - if (tree_conn) - ksmbd_release_tree_conn_id(sess, tree_conn->id); - ksmbd_share_config_put(sc); - kfree(tree_conn); - kvfree(resp); - return status; -} - -int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, - struct ksmbd_tree_connect *tree_conn) -{ - int ret; - - ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id); - ksmbd_release_tree_conn_id(sess, tree_conn->id); - xa_erase(&sess->tree_conns, tree_conn->id); - ksmbd_share_config_put(tree_conn->share_conf); - kfree(tree_conn); - return ret; -} - -struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess, - unsigned int id) -{ - struct ksmbd_tree_connect *tcon; - - tcon = xa_load(&sess->tree_conns, id); - if (tcon) { - if (test_bit(TREE_CONN_EXPIRE, &tcon->status)) - tcon = NULL; - } - - return tcon; -} - -struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess, - unsigned int id) -{ - struct ksmbd_tree_connect *tc; - - tc = ksmbd_tree_conn_lookup(sess, id); - if (tc) - return tc->share_conf; - return NULL; -} - -int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess) -{ - int ret = 0; - struct ksmbd_tree_connect *tc; - unsigned long id; - - if (!sess) - return -EINVAL; - - xa_for_each(&sess->tree_conns, id, tc) - ret |= ksmbd_tree_conn_disconnect(sess, tc); - xa_destroy(&sess->tree_conns); - return ret; -} diff --git a/fs/ksmbd/mgmt/tree_connect.h b/fs/ksmbd/mgmt/tree_connect.h deleted file mode 100644 index 700df36cf3e3..000000000000 --- a/fs/ksmbd/mgmt/tree_connect.h +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __TREE_CONNECT_MANAGEMENT_H__ -#define __TREE_CONNECT_MANAGEMENT_H__ - -#include <linux/hashtable.h> - -#include "../ksmbd_netlink.h" - -struct ksmbd_share_config; -struct ksmbd_user; -struct ksmbd_conn; - -#define TREE_CONN_EXPIRE 1 - -struct ksmbd_tree_connect { - int id; - - unsigned int flags; - struct ksmbd_share_config *share_conf; - struct ksmbd_user *user; - - struct list_head list; - - int maximal_access; - bool posix_extensions; - unsigned long status; -}; - -struct ksmbd_tree_conn_status { - unsigned int ret; - struct ksmbd_tree_connect *tree_conn; -}; - -static inline int test_tree_conn_flag(struct ksmbd_tree_connect *tree_conn, - int flag) -{ - return tree_conn->flags & flag; -} - -struct ksmbd_session; - -struct ksmbd_tree_conn_status -ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess, - const char *share_name); - -int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, - struct ksmbd_tree_connect *tree_conn); - -struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess, - unsigned int id); - -struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess, - unsigned int id); - -int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess); - -#endif /* __TREE_CONNECT_MANAGEMENT_H__ */ diff --git a/fs/ksmbd/mgmt/user_config.c b/fs/ksmbd/mgmt/user_config.c deleted file mode 100644 index 279d00feff21..000000000000 --- a/fs/ksmbd/mgmt/user_config.c +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/slab.h> -#include <linux/mm.h> - -#include "user_config.h" -#include "../transport_ipc.h" - -struct ksmbd_user *ksmbd_login_user(const char *account) -{ - struct ksmbd_login_response *resp; - struct ksmbd_user *user = NULL; - - resp = ksmbd_ipc_login_request(account); - if (!resp) - return NULL; - - if (!(resp->status & KSMBD_USER_FLAG_OK)) - goto out; - - user = ksmbd_alloc_user(resp); -out: - kvfree(resp); - return user; -} - -struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp) -{ - struct ksmbd_user *user = NULL; - - user = kmalloc(sizeof(struct ksmbd_user), GFP_KERNEL); - if (!user) - return NULL; - - user->name = kstrdup(resp->account, GFP_KERNEL); - user->flags = resp->status; - user->gid = resp->gid; - user->uid = resp->uid; - user->passkey_sz = resp->hash_sz; - user->passkey = kmalloc(resp->hash_sz, GFP_KERNEL); - if (user->passkey) - memcpy(user->passkey, resp->hash, resp->hash_sz); - - if (!user->name || !user->passkey) { - kfree(user->name); - kfree(user->passkey); - kfree(user); - user = NULL; - } - return user; -} - -void ksmbd_free_user(struct ksmbd_user *user) -{ - ksmbd_ipc_logout_request(user->name, user->flags); - kfree(user->name); - kfree(user->passkey); - kfree(user); -} - -int ksmbd_anonymous_user(struct ksmbd_user *user) -{ - if (user->name[0] == '\0') - return 1; - return 0; -} - -bool ksmbd_compare_user(struct ksmbd_user *u1, struct ksmbd_user *u2) -{ - if (strcmp(u1->name, u2->name)) - return false; - if (memcmp(u1->passkey, u2->passkey, u1->passkey_sz)) - return false; - - return true; -} diff --git a/fs/ksmbd/mgmt/user_config.h b/fs/ksmbd/mgmt/user_config.h deleted file mode 100644 index 6a44109617f1..000000000000 --- a/fs/ksmbd/mgmt/user_config.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __USER_CONFIG_MANAGEMENT_H__ -#define __USER_CONFIG_MANAGEMENT_H__ - -#include "../glob.h" - -struct ksmbd_user { - unsigned short flags; - - unsigned int uid; - unsigned int gid; - - char *name; - - size_t passkey_sz; - char *passkey; - unsigned int failed_login_count; -}; - -static inline bool user_guest(struct ksmbd_user *user) -{ - return user->flags & KSMBD_USER_FLAG_GUEST_ACCOUNT; -} - -static inline void set_user_flag(struct ksmbd_user *user, int flag) -{ - user->flags |= flag; -} - -static inline int test_user_flag(struct ksmbd_user *user, int flag) -{ - return user->flags & flag; -} - -static inline void set_user_guest(struct ksmbd_user *user) -{ -} - -static inline char *user_passkey(struct ksmbd_user *user) -{ - return user->passkey; -} - -static inline char *user_name(struct ksmbd_user *user) -{ - return user->name; -} - -static inline unsigned int user_uid(struct ksmbd_user *user) -{ - return user->uid; -} - -static inline unsigned int user_gid(struct ksmbd_user *user) -{ - return user->gid; -} - -struct ksmbd_user *ksmbd_login_user(const char *account); -struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp); -void ksmbd_free_user(struct ksmbd_user *user); -int ksmbd_anonymous_user(struct ksmbd_user *user); -bool ksmbd_compare_user(struct ksmbd_user *u1, struct ksmbd_user *u2); -#endif /* __USER_CONFIG_MANAGEMENT_H__ */ diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c deleted file mode 100644 index ea4b56d570fb..000000000000 --- a/fs/ksmbd/mgmt/user_session.c +++ /dev/null @@ -1,400 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/list.h> -#include <linux/slab.h> -#include <linux/rwsem.h> -#include <linux/xarray.h> - -#include "ksmbd_ida.h" -#include "user_session.h" -#include "user_config.h" -#include "tree_connect.h" -#include "../transport_ipc.h" -#include "../connection.h" -#include "../vfs_cache.h" - -static DEFINE_IDA(session_ida); - -#define SESSION_HASH_BITS 3 -static DEFINE_HASHTABLE(sessions_table, SESSION_HASH_BITS); -static DECLARE_RWSEM(sessions_table_lock); - -struct ksmbd_session_rpc { - int id; - unsigned int method; - struct list_head list; -}; - -static void free_channel_list(struct ksmbd_session *sess) -{ - struct channel *chann; - unsigned long index; - - xa_for_each(&sess->ksmbd_chann_list, index, chann) { - xa_erase(&sess->ksmbd_chann_list, index); - kfree(chann); - } - - xa_destroy(&sess->ksmbd_chann_list); -} - -static void __session_rpc_close(struct ksmbd_session *sess, - struct ksmbd_session_rpc *entry) -{ - struct ksmbd_rpc_command *resp; - - resp = ksmbd_rpc_close(sess, entry->id); - if (!resp) - pr_err("Unable to close RPC pipe %d\n", entry->id); - - kvfree(resp); - ksmbd_rpc_id_free(entry->id); - kfree(entry); -} - -static void ksmbd_session_rpc_clear_list(struct ksmbd_session *sess) -{ - struct ksmbd_session_rpc *entry; - - while (!list_empty(&sess->rpc_handle_list)) { - entry = list_entry(sess->rpc_handle_list.next, - struct ksmbd_session_rpc, - list); - - list_del(&entry->list); - __session_rpc_close(sess, entry); - } -} - -static int __rpc_method(char *rpc_name) -{ - if (!strcmp(rpc_name, "\\srvsvc") || !strcmp(rpc_name, "srvsvc")) - return KSMBD_RPC_SRVSVC_METHOD_INVOKE; - - if (!strcmp(rpc_name, "\\wkssvc") || !strcmp(rpc_name, "wkssvc")) - return KSMBD_RPC_WKSSVC_METHOD_INVOKE; - - if (!strcmp(rpc_name, "LANMAN") || !strcmp(rpc_name, "lanman")) - return KSMBD_RPC_RAP_METHOD; - - if (!strcmp(rpc_name, "\\samr") || !strcmp(rpc_name, "samr")) - return KSMBD_RPC_SAMR_METHOD_INVOKE; - - if (!strcmp(rpc_name, "\\lsarpc") || !strcmp(rpc_name, "lsarpc")) - return KSMBD_RPC_LSARPC_METHOD_INVOKE; - - pr_err("Unsupported RPC: %s\n", rpc_name); - return 0; -} - -int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name) -{ - struct ksmbd_session_rpc *entry; - struct ksmbd_rpc_command *resp; - int method; - - method = __rpc_method(rpc_name); - if (!method) - return -EINVAL; - - entry = kzalloc(sizeof(struct ksmbd_session_rpc), GFP_KERNEL); - if (!entry) - return -EINVAL; - - list_add(&entry->list, &sess->rpc_handle_list); - entry->method = method; - entry->id = ksmbd_ipc_id_alloc(); - if (entry->id < 0) - goto free_entry; - - resp = ksmbd_rpc_open(sess, entry->id); - if (!resp) - goto free_id; - - kvfree(resp); - return entry->id; -free_id: - ksmbd_rpc_id_free(entry->id); -free_entry: - list_del(&entry->list); - kfree(entry); - return -EINVAL; -} - -void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id) -{ - struct ksmbd_session_rpc *entry; - - list_for_each_entry(entry, &sess->rpc_handle_list, list) { - if (entry->id == id) { - list_del(&entry->list); - __session_rpc_close(sess, entry); - break; - } - } -} - -int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id) -{ - struct ksmbd_session_rpc *entry; - - list_for_each_entry(entry, &sess->rpc_handle_list, list) { - if (entry->id == id) - return entry->method; - } - return 0; -} - -void ksmbd_session_destroy(struct ksmbd_session *sess) -{ - if (!sess) - return; - - if (sess->user) - ksmbd_free_user(sess->user); - - ksmbd_tree_conn_session_logoff(sess); - ksmbd_destroy_file_table(&sess->file_table); - ksmbd_session_rpc_clear_list(sess); - free_channel_list(sess); - kfree(sess->Preauth_HashValue); - ksmbd_release_id(&session_ida, sess->id); - kfree(sess); -} - -static struct ksmbd_session *__session_lookup(unsigned long long id) -{ - struct ksmbd_session *sess; - - hash_for_each_possible(sessions_table, sess, hlist, id) { - if (id == sess->id) { - sess->last_active = jiffies; - return sess; - } - } - return NULL; -} - -static void ksmbd_expire_session(struct ksmbd_conn *conn) -{ - unsigned long id; - struct ksmbd_session *sess; - - down_write(&sessions_table_lock); - xa_for_each(&conn->sessions, id, sess) { - if (sess->state != SMB2_SESSION_VALID || - time_after(jiffies, - sess->last_active + SMB2_SESSION_TIMEOUT)) { - xa_erase(&conn->sessions, sess->id); - hash_del(&sess->hlist); - ksmbd_session_destroy(sess); - continue; - } - } - up_write(&sessions_table_lock); -} - -int ksmbd_session_register(struct ksmbd_conn *conn, - struct ksmbd_session *sess) -{ - sess->dialect = conn->dialect; - memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); - ksmbd_expire_session(conn); - return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL)); -} - -static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) -{ - struct channel *chann; - - chann = xa_erase(&sess->ksmbd_chann_list, (long)conn); - if (!chann) - return -ENOENT; - - kfree(chann); - return 0; -} - -void ksmbd_sessions_deregister(struct ksmbd_conn *conn) -{ - struct ksmbd_session *sess; - unsigned long id; - - down_write(&sessions_table_lock); - if (conn->binding) { - int bkt; - struct hlist_node *tmp; - - hash_for_each_safe(sessions_table, bkt, tmp, sess, hlist) { - if (!ksmbd_chann_del(conn, sess) && - xa_empty(&sess->ksmbd_chann_list)) { - hash_del(&sess->hlist); - ksmbd_session_destroy(sess); - } - } - } - - xa_for_each(&conn->sessions, id, sess) { - unsigned long chann_id; - struct channel *chann; - - xa_for_each(&sess->ksmbd_chann_list, chann_id, chann) { - if (chann->conn != conn) - ksmbd_conn_set_exiting(chann->conn); - } - - ksmbd_chann_del(conn, sess); - if (xa_empty(&sess->ksmbd_chann_list)) { - xa_erase(&conn->sessions, sess->id); - hash_del(&sess->hlist); - ksmbd_session_destroy(sess); - } - } - up_write(&sessions_table_lock); -} - -struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, - unsigned long long id) -{ - struct ksmbd_session *sess; - - sess = xa_load(&conn->sessions, id); - if (sess) - sess->last_active = jiffies; - return sess; -} - -struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) -{ - struct ksmbd_session *sess; - - down_read(&sessions_table_lock); - sess = __session_lookup(id); - if (sess) - sess->last_active = jiffies; - up_read(&sessions_table_lock); - - return sess; -} - -struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, - unsigned long long id) -{ - struct ksmbd_session *sess; - - sess = ksmbd_session_lookup(conn, id); - if (!sess && conn->binding) - sess = ksmbd_session_lookup_slowpath(id); - if (sess && sess->state != SMB2_SESSION_VALID) - sess = NULL; - return sess; -} - -struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn, - u64 sess_id) -{ - struct preauth_session *sess; - - sess = kmalloc(sizeof(struct preauth_session), GFP_KERNEL); - if (!sess) - return NULL; - - sess->id = sess_id; - memcpy(sess->Preauth_HashValue, conn->preauth_info->Preauth_HashValue, - PREAUTH_HASHVALUE_SIZE); - list_add(&sess->preauth_entry, &conn->preauth_sess_table); - - return sess; -} - -static bool ksmbd_preauth_session_id_match(struct preauth_session *sess, - unsigned long long id) -{ - return sess->id == id; -} - -struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn, - unsigned long long id) -{ - struct preauth_session *sess = NULL; - - list_for_each_entry(sess, &conn->preauth_sess_table, preauth_entry) { - if (ksmbd_preauth_session_id_match(sess, id)) - return sess; - } - return NULL; -} - -static int __init_smb2_session(struct ksmbd_session *sess) -{ - int id = ksmbd_acquire_smb2_uid(&session_ida); - - if (id < 0) - return -EINVAL; - sess->id = id; - return 0; -} - -static struct ksmbd_session *__session_create(int protocol) -{ - struct ksmbd_session *sess; - int ret; - - if (protocol != CIFDS_SESSION_FLAG_SMB2) - return NULL; - - sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL); - if (!sess) - return NULL; - - if (ksmbd_init_file_table(&sess->file_table)) - goto error; - - sess->last_active = jiffies; - sess->state = SMB2_SESSION_IN_PROGRESS; - set_session_flag(sess, protocol); - xa_init(&sess->tree_conns); - xa_init(&sess->ksmbd_chann_list); - INIT_LIST_HEAD(&sess->rpc_handle_list); - sess->sequence_number = 1; - - ret = __init_smb2_session(sess); - if (ret) - goto error; - - ida_init(&sess->tree_conn_ida); - - down_write(&sessions_table_lock); - hash_add(sessions_table, &sess->hlist, sess->id); - up_write(&sessions_table_lock); - - return sess; - -error: - ksmbd_session_destroy(sess); - return NULL; -} - -struct ksmbd_session *ksmbd_smb2_session_create(void) -{ - return __session_create(CIFDS_SESSION_FLAG_SMB2); -} - -int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess) -{ - int id = -EINVAL; - - if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2)) - id = ksmbd_acquire_smb2_tid(&sess->tree_conn_ida); - - return id; -} - -void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id) -{ - if (id >= 0) - ksmbd_release_id(&sess->tree_conn_ida, id); -} diff --git a/fs/ksmbd/mgmt/user_session.h b/fs/ksmbd/mgmt/user_session.h deleted file mode 100644 index 51f38e5b61ab..000000000000 --- a/fs/ksmbd/mgmt/user_session.h +++ /dev/null @@ -1,103 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __USER_SESSION_MANAGEMENT_H__ -#define __USER_SESSION_MANAGEMENT_H__ - -#include <linux/hashtable.h> -#include <linux/xarray.h> - -#include "../smb_common.h" -#include "../ntlmssp.h" - -#define CIFDS_SESSION_FLAG_SMB2 BIT(1) - -#define PREAUTH_HASHVALUE_SIZE 64 - -struct ksmbd_file_table; - -struct channel { - __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; - struct ksmbd_conn *conn; -}; - -struct preauth_session { - __u8 Preauth_HashValue[PREAUTH_HASHVALUE_SIZE]; - u64 id; - struct list_head preauth_entry; -}; - -struct ksmbd_session { - u64 id; - - __u16 dialect; - char ClientGUID[SMB2_CLIENT_GUID_SIZE]; - - struct ksmbd_user *user; - unsigned int sequence_number; - unsigned int flags; - - bool sign; - bool enc; - bool is_anonymous; - - int state; - __u8 *Preauth_HashValue; - - char sess_key[CIFS_KEY_SIZE]; - - struct hlist_node hlist; - struct xarray ksmbd_chann_list; - struct xarray tree_conns; - struct ida tree_conn_ida; - struct list_head rpc_handle_list; - - __u8 smb3encryptionkey[SMB3_ENC_DEC_KEY_SIZE]; - __u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE]; - __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; - - struct ksmbd_file_table file_table; - unsigned long last_active; -}; - -static inline int test_session_flag(struct ksmbd_session *sess, int bit) -{ - return sess->flags & bit; -} - -static inline void set_session_flag(struct ksmbd_session *sess, int bit) -{ - sess->flags |= bit; -} - -static inline void clear_session_flag(struct ksmbd_session *sess, int bit) -{ - sess->flags &= ~bit; -} - -struct ksmbd_session *ksmbd_smb2_session_create(void); - -void ksmbd_session_destroy(struct ksmbd_session *sess); - -struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id); -struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, - unsigned long long id); -int ksmbd_session_register(struct ksmbd_conn *conn, - struct ksmbd_session *sess); -void ksmbd_sessions_deregister(struct ksmbd_conn *conn); -struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, - unsigned long long id); -struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn, - u64 sess_id); -struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn, - unsigned long long id); - -int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess); -void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id); - -int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name); -void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id); -int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id); -#endif /* __USER_SESSION_MANAGEMENT_H__ */ diff --git a/fs/ksmbd/misc.c b/fs/ksmbd/misc.c deleted file mode 100644 index 9e8afaa686e3..000000000000 --- a/fs/ksmbd/misc.c +++ /dev/null @@ -1,381 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/kernel.h> -#include <linux/xattr.h> -#include <linux/fs.h> -#include <linux/unicode.h> - -#include "misc.h" -#include "smb_common.h" -#include "connection.h" -#include "vfs.h" - -#include "mgmt/share_config.h" - -/** - * match_pattern() - compare a string with a pattern which might include - * wildcard '*' and '?' - * TODO : implement consideration about DOS_DOT, DOS_QM and DOS_STAR - * - * @str: string to compare with a pattern - * @len: string length - * @pattern: pattern string which might include wildcard '*' and '?' - * - * Return: 0 if pattern matched with the string, otherwise non zero value - */ -int match_pattern(const char *str, size_t len, const char *pattern) -{ - const char *s = str; - const char *p = pattern; - bool star = false; - - while (*s && len) { - switch (*p) { - case '?': - s++; - len--; - p++; - break; - case '*': - star = true; - str = s; - if (!*++p) - return true; - pattern = p; - break; - default: - if (tolower(*s) == tolower(*p)) { - s++; - len--; - p++; - } else { - if (!star) - return false; - str++; - s = str; - p = pattern; - } - break; - } - } - - if (*p == '*') - ++p; - return !*p; -} - -/* - * is_char_allowed() - check for valid character - * @ch: input character to be checked - * - * Return: 1 if char is allowed, otherwise 0 - */ -static inline int is_char_allowed(char ch) -{ - /* check for control chars, wildcards etc. */ - if (!(ch & 0x80) && - (ch <= 0x1f || - ch == '?' || ch == '"' || ch == '<' || - ch == '>' || ch == '|' || ch == '*')) - return 0; - - return 1; -} - -int ksmbd_validate_filename(char *filename) -{ - while (*filename) { - char c = *filename; - - filename++; - if (!is_char_allowed(c)) { - ksmbd_debug(VFS, "File name validation failed: 0x%x\n", c); - return -ENOENT; - } - } - - return 0; -} - -static int ksmbd_validate_stream_name(char *stream_name) -{ - while (*stream_name) { - char c = *stream_name; - - stream_name++; - if (c == '/' || c == ':' || c == '\\') { - pr_err("Stream name validation failed: %c\n", c); - return -ENOENT; - } - } - - return 0; -} - -int parse_stream_name(char *filename, char **stream_name, int *s_type) -{ - char *stream_type; - char *s_name; - int rc = 0; - - s_name = filename; - filename = strsep(&s_name, ":"); - ksmbd_debug(SMB, "filename : %s, streams : %s\n", filename, s_name); - if (strchr(s_name, ':')) { - stream_type = s_name; - s_name = strsep(&stream_type, ":"); - - rc = ksmbd_validate_stream_name(s_name); - if (rc < 0) { - rc = -ENOENT; - goto out; - } - - ksmbd_debug(SMB, "stream name : %s, stream type : %s\n", s_name, - stream_type); - if (!strncasecmp("$data", stream_type, 5)) - *s_type = DATA_STREAM; - else if (!strncasecmp("$index_allocation", stream_type, 17)) - *s_type = DIR_STREAM; - else - rc = -ENOENT; - } - - *stream_name = s_name; -out: - return rc; -} - -/** - * convert_to_nt_pathname() - extract and return windows path string - * whose share directory prefix was removed from file path - * @share: ksmbd_share_config pointer - * @path: path to report - * - * Return : windows path string or error - */ - -char *convert_to_nt_pathname(struct ksmbd_share_config *share, - const struct path *path) -{ - char *pathname, *ab_pathname, *nt_pathname; - int share_path_len = share->path_sz; - - pathname = kmalloc(PATH_MAX, GFP_KERNEL); - if (!pathname) - return ERR_PTR(-EACCES); - - ab_pathname = d_path(path, pathname, PATH_MAX); - if (IS_ERR(ab_pathname)) { - nt_pathname = ERR_PTR(-EACCES); - goto free_pathname; - } - - if (strncmp(ab_pathname, share->path, share_path_len)) { - nt_pathname = ERR_PTR(-EACCES); - goto free_pathname; - } - - nt_pathname = kzalloc(strlen(&ab_pathname[share_path_len]) + 2, GFP_KERNEL); - if (!nt_pathname) { - nt_pathname = ERR_PTR(-ENOMEM); - goto free_pathname; - } - if (ab_pathname[share_path_len] == '\0') - strcpy(nt_pathname, "/"); - strcat(nt_pathname, &ab_pathname[share_path_len]); - - ksmbd_conv_path_to_windows(nt_pathname); - -free_pathname: - kfree(pathname); - return nt_pathname; -} - -int get_nlink(struct kstat *st) -{ - int nlink; - - nlink = st->nlink; - if (S_ISDIR(st->mode)) - nlink--; - - return nlink; -} - -void ksmbd_conv_path_to_unix(char *path) -{ - strreplace(path, '\\', '/'); -} - -void ksmbd_strip_last_slash(char *path) -{ - int len = strlen(path); - - while (len && path[len - 1] == '/') { - path[len - 1] = '\0'; - len--; - } -} - -void ksmbd_conv_path_to_windows(char *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 - * @treename: buffer containing tree name and share name - * - * Return: share name on success, otherwise error - */ -char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename) -{ - const char *name = treename, *pos = strrchr(name, '\\'); - - if (pos) - name = (pos + 1); - - /* caller has to free the memory */ - return ksmbd_casefold_sharename(um, name); -} - -/** - * convert_to_unix_name() - convert windows name to unix format - * @share: ksmbd_share_config pointer - * @name: file name that is relative to share - * - * Return: converted name on success, otherwise NULL - */ -char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name) -{ - int no_slash = 0, name_len, path_len; - char *new_name; - - if (name[0] == '/') - name++; - - path_len = share->path_sz; - name_len = strlen(name); - new_name = kmalloc(path_len + name_len + 2, GFP_KERNEL); - if (!new_name) - return new_name; - - memcpy(new_name, share->path, path_len); - if (new_name[path_len - 1] != '/') { - new_name[path_len] = '/'; - no_slash = 1; - } - - memcpy(new_name + path_len + no_slash, name, name_len); - path_len += name_len + no_slash; - new_name[path_len] = 0x00; - return new_name; -} - -char *ksmbd_convert_dir_info_name(struct ksmbd_dir_info *d_info, - const struct nls_table *local_nls, - int *conv_len) -{ - char *conv; - int sz = min(4 * d_info->name_len, PATH_MAX); - - if (!sz) - return NULL; - - conv = kmalloc(sz, GFP_KERNEL); - if (!conv) - return NULL; - - /* XXX */ - *conv_len = smbConvertToUTF16((__le16 *)conv, d_info->name, - d_info->name_len, local_nls, 0); - *conv_len *= 2; - - /* We allocate buffer twice bigger than needed. */ - conv[*conv_len] = 0x00; - conv[*conv_len + 1] = 0x00; - return conv; -} - -/* - * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units) - * into Unix UTC (based 1970-01-01, in seconds). - */ -struct timespec64 ksmbd_NTtimeToUnix(__le64 ntutc) -{ - struct timespec64 ts; - - /* Subtract the NTFS time offset, then convert to 1s intervals. */ - s64 t = le64_to_cpu(ntutc) - NTFS_TIME_OFFSET; - u64 abs_t; - - /* - * Unfortunately can not use normal 64 bit division on 32 bit arch, but - * the alternative, do_div, does not work with negative numbers so have - * to special case them - */ - if (t < 0) { - abs_t = -t; - ts.tv_nsec = do_div(abs_t, 10000000) * 100; - ts.tv_nsec = -ts.tv_nsec; - ts.tv_sec = -abs_t; - } else { - abs_t = t; - ts.tv_nsec = do_div(abs_t, 10000000) * 100; - ts.tv_sec = abs_t; - } - - return ts; -} - -/* Convert the Unix UTC into NT UTC. */ -inline u64 ksmbd_UnixTimeToNT(struct timespec64 t) -{ - /* Convert to 100ns intervals and then add the NTFS time offset. */ - return (u64)t.tv_sec * 10000000 + t.tv_nsec / 100 + NTFS_TIME_OFFSET; -} - -inline long long ksmbd_systime(void) -{ - struct timespec64 ts; - - ktime_get_real_ts64(&ts); - return ksmbd_UnixTimeToNT(ts); -} diff --git a/fs/ksmbd/misc.h b/fs/ksmbd/misc.h deleted file mode 100644 index 1facfcd21200..000000000000 --- a/fs/ksmbd/misc.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __KSMBD_MISC_H__ -#define __KSMBD_MISC_H__ - -struct ksmbd_share_config; -struct nls_table; -struct kstat; -struct ksmbd_file; - -int match_pattern(const char *str, size_t len, const char *pattern); -int ksmbd_validate_filename(char *filename); -int parse_stream_name(char *filename, char **stream_name, int *s_type); -char *convert_to_nt_pathname(struct ksmbd_share_config *share, - const struct path *path); -int get_nlink(struct kstat *st); -void ksmbd_conv_path_to_unix(char *path); -void ksmbd_strip_last_slash(char *path); -void ksmbd_conv_path_to_windows(char *path); -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); - -#define KSMBD_DIR_INFO_ALIGNMENT 8 -struct ksmbd_dir_info; -char *ksmbd_convert_dir_info_name(struct ksmbd_dir_info *d_info, - const struct nls_table *local_nls, - int *conv_len); - -#define NTFS_TIME_OFFSET ((u64)(369 * 365 + 89) * 24 * 3600 * 10000000) -struct timespec64 ksmbd_NTtimeToUnix(__le64 ntutc); -u64 ksmbd_UnixTimeToNT(struct timespec64 t); -long long ksmbd_systime(void); -#endif /* __KSMBD_MISC_H__ */ diff --git a/fs/ksmbd/ndr.c b/fs/ksmbd/ndr.c deleted file mode 100644 index 4d9e0b54e3db..000000000000 --- a/fs/ksmbd/ndr.c +++ /dev/null @@ -1,514 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2021 Samsung Electronics Co., Ltd. - * Author(s): Namjae Jeon <linkinjeon@kernel.org> - */ - -#include <linux/fs.h> - -#include "glob.h" -#include "ndr.h" - -static inline char *ndr_get_field(struct ndr *n) -{ - return n->data + n->offset; -} - -static int try_to_realloc_ndr_blob(struct ndr *n, size_t sz) -{ - char *data; - - data = krealloc(n->data, n->offset + sz + 1024, GFP_KERNEL); - if (!data) - return -ENOMEM; - - n->data = data; - n->length += 1024; - memset(n->data + n->offset, 0, 1024); - return 0; -} - -static int ndr_write_int16(struct ndr *n, __u16 value) -{ - if (n->length <= n->offset + sizeof(value)) { - int ret; - - ret = try_to_realloc_ndr_blob(n, sizeof(value)); - if (ret) - return ret; - } - - *(__le16 *)ndr_get_field(n) = cpu_to_le16(value); - n->offset += sizeof(value); - return 0; -} - -static int ndr_write_int32(struct ndr *n, __u32 value) -{ - if (n->length <= n->offset + sizeof(value)) { - int ret; - - ret = try_to_realloc_ndr_blob(n, sizeof(value)); - if (ret) - return ret; - } - - *(__le32 *)ndr_get_field(n) = cpu_to_le32(value); - n->offset += sizeof(value); - return 0; -} - -static int ndr_write_int64(struct ndr *n, __u64 value) -{ - if (n->length <= n->offset + sizeof(value)) { - int ret; - - ret = try_to_realloc_ndr_blob(n, sizeof(value)); - if (ret) - return ret; - } - - *(__le64 *)ndr_get_field(n) = cpu_to_le64(value); - n->offset += sizeof(value); - return 0; -} - -static int ndr_write_bytes(struct ndr *n, void *value, size_t sz) -{ - if (n->length <= n->offset + sz) { - int ret; - - ret = try_to_realloc_ndr_blob(n, sz); - if (ret) - return ret; - } - - memcpy(ndr_get_field(n), value, sz); - n->offset += sz; - return 0; -} - -static int ndr_write_string(struct ndr *n, char *value) -{ - size_t sz; - - sz = strlen(value) + 1; - if (n->length <= n->offset + sz) { - int ret; - - ret = try_to_realloc_ndr_blob(n, sz); - if (ret) - return ret; - } - - memcpy(ndr_get_field(n), value, sz); - n->offset += sz; - n->offset = ALIGN(n->offset, 2); - return 0; -} - -static int ndr_read_string(struct ndr *n, void *value, size_t sz) -{ - int len; - - if (n->offset + sz > n->length) - return -EINVAL; - - len = strnlen(ndr_get_field(n), sz); - if (value) - memcpy(value, ndr_get_field(n), len); - len++; - n->offset += len; - n->offset = ALIGN(n->offset, 2); - return 0; -} - -static int ndr_read_bytes(struct ndr *n, void *value, size_t sz) -{ - if (n->offset + sz > n->length) - return -EINVAL; - - if (value) - memcpy(value, ndr_get_field(n), sz); - n->offset += sz; - return 0; -} - -static int ndr_read_int16(struct ndr *n, __u16 *value) -{ - if (n->offset + sizeof(__u16) > n->length) - return -EINVAL; - - if (value) - *value = le16_to_cpu(*(__le16 *)ndr_get_field(n)); - n->offset += sizeof(__u16); - return 0; -} - -static int ndr_read_int32(struct ndr *n, __u32 *value) -{ - if (n->offset + sizeof(__u32) > n->length) - return -EINVAL; - - if (value) - *value = le32_to_cpu(*(__le32 *)ndr_get_field(n)); - n->offset += sizeof(__u32); - return 0; -} - -static int ndr_read_int64(struct ndr *n, __u64 *value) -{ - if (n->offset + sizeof(__u64) > n->length) - return -EINVAL; - - if (value) - *value = le64_to_cpu(*(__le64 *)ndr_get_field(n)); - n->offset += sizeof(__u64); - return 0; -} - -int ndr_encode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da) -{ - char hex_attr[12] = {0}; - int ret; - - n->offset = 0; - n->length = 1024; - n->data = kzalloc(n->length, GFP_KERNEL); - if (!n->data) - return -ENOMEM; - - if (da->version == 3) { - snprintf(hex_attr, 10, "0x%x", da->attr); - ret = ndr_write_string(n, hex_attr); - } else { - ret = ndr_write_string(n, ""); - } - if (ret) - return ret; - - ret = ndr_write_int16(n, da->version); - if (ret) - return ret; - - ret = ndr_write_int32(n, da->version); - if (ret) - return ret; - - ret = ndr_write_int32(n, da->flags); - if (ret) - return ret; - - ret = ndr_write_int32(n, da->attr); - if (ret) - return ret; - - if (da->version == 3) { - ret = ndr_write_int32(n, da->ea_size); - if (ret) - return ret; - ret = ndr_write_int64(n, da->size); - if (ret) - return ret; - ret = ndr_write_int64(n, da->alloc_size); - } else { - ret = ndr_write_int64(n, da->itime); - } - if (ret) - return ret; - - ret = ndr_write_int64(n, da->create_time); - if (ret) - return ret; - - if (da->version == 3) - ret = ndr_write_int64(n, da->change_time); - return ret; -} - -int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da) -{ - char hex_attr[12]; - unsigned int version2; - int ret; - - n->offset = 0; - ret = ndr_read_string(n, hex_attr, sizeof(hex_attr)); - if (ret) - return ret; - - ret = ndr_read_int16(n, &da->version); - if (ret) - return ret; - - if (da->version != 3 && da->version != 4) { - ksmbd_debug(VFS, "v%d version is not supported\n", da->version); - return -EINVAL; - } - - ret = ndr_read_int32(n, &version2); - if (ret) - return ret; - - if (da->version != version2) { - ksmbd_debug(VFS, "ndr version mismatched(version: %d, version2: %d)\n", - da->version, version2); - return -EINVAL; - } - - ret = ndr_read_int32(n, NULL); - if (ret) - return ret; - - ret = ndr_read_int32(n, &da->attr); - if (ret) - return ret; - - if (da->version == 4) { - ret = ndr_read_int64(n, &da->itime); - if (ret) - return ret; - - ret = ndr_read_int64(n, &da->create_time); - } else { - ret = ndr_read_int32(n, NULL); - if (ret) - return ret; - - ret = ndr_read_int64(n, NULL); - if (ret) - return ret; - - ret = ndr_read_int64(n, NULL); - if (ret) - return ret; - - ret = ndr_read_int64(n, &da->create_time); - if (ret) - return ret; - - ret = ndr_read_int64(n, NULL); - } - - return ret; -} - -static int ndr_encode_posix_acl_entry(struct ndr *n, struct xattr_smb_acl *acl) -{ - int i, ret; - - ret = ndr_write_int32(n, acl->count); - if (ret) - return ret; - - n->offset = ALIGN(n->offset, 8); - ret = ndr_write_int32(n, acl->count); - if (ret) - return ret; - - ret = ndr_write_int32(n, 0); - if (ret) - return ret; - - for (i = 0; i < acl->count; i++) { - n->offset = ALIGN(n->offset, 8); - ret = ndr_write_int16(n, acl->entries[i].type); - if (ret) - return ret; - - ret = ndr_write_int16(n, acl->entries[i].type); - if (ret) - return ret; - - if (acl->entries[i].type == SMB_ACL_USER) { - n->offset = ALIGN(n->offset, 8); - ret = ndr_write_int64(n, acl->entries[i].uid); - } else if (acl->entries[i].type == SMB_ACL_GROUP) { - n->offset = ALIGN(n->offset, 8); - ret = ndr_write_int64(n, acl->entries[i].gid); - } - if (ret) - return ret; - - /* push permission */ - ret = ndr_write_int32(n, acl->entries[i].perm); - } - - return ret; -} - -int ndr_encode_posix_acl(struct ndr *n, - struct user_namespace *user_ns, - struct inode *inode, - struct xattr_smb_acl *acl, - struct xattr_smb_acl *def_acl) -{ - unsigned int ref_id = 0x00020000; - int ret; - vfsuid_t vfsuid; - vfsgid_t vfsgid; - - n->offset = 0; - n->length = 1024; - n->data = kzalloc(n->length, GFP_KERNEL); - if (!n->data) - return -ENOMEM; - - if (acl) { - /* ACL ACCESS */ - ret = ndr_write_int32(n, ref_id); - ref_id += 4; - } else { - ret = ndr_write_int32(n, 0); - } - if (ret) - return ret; - - if (def_acl) { - /* DEFAULT ACL ACCESS */ - ret = ndr_write_int32(n, ref_id); - ref_id += 4; - } else { - ret = ndr_write_int32(n, 0); - } - if (ret) - return ret; - - vfsuid = i_uid_into_vfsuid(user_ns, inode); - ret = ndr_write_int64(n, from_kuid(&init_user_ns, vfsuid_into_kuid(vfsuid))); - if (ret) - return ret; - vfsgid = i_gid_into_vfsgid(user_ns, inode); - ret = ndr_write_int64(n, from_kgid(&init_user_ns, vfsgid_into_kgid(vfsgid))); - if (ret) - return ret; - ret = ndr_write_int32(n, inode->i_mode); - if (ret) - return ret; - - if (acl) { - ret = ndr_encode_posix_acl_entry(n, acl); - if (def_acl && !ret) - ret = ndr_encode_posix_acl_entry(n, def_acl); - } - return ret; -} - -int ndr_encode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl) -{ - unsigned int ref_id = 0x00020004; - int ret; - - n->offset = 0; - n->length = 2048; - n->data = kzalloc(n->length, GFP_KERNEL); - if (!n->data) - return -ENOMEM; - - ret = ndr_write_int16(n, acl->version); - if (ret) - return ret; - - ret = ndr_write_int32(n, acl->version); - if (ret) - return ret; - - ret = ndr_write_int16(n, 2); - if (ret) - return ret; - - ret = ndr_write_int32(n, ref_id); - if (ret) - return ret; - - /* push hash type and hash 64bytes */ - ret = ndr_write_int16(n, acl->hash_type); - if (ret) - return ret; - - ret = ndr_write_bytes(n, acl->hash, XATTR_SD_HASH_SIZE); - if (ret) - return ret; - - ret = ndr_write_bytes(n, acl->desc, acl->desc_len); - if (ret) - return ret; - - ret = ndr_write_int64(n, acl->current_time); - if (ret) - return ret; - - ret = ndr_write_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE); - if (ret) - return ret; - - /* push ndr for security descriptor */ - ret = ndr_write_bytes(n, acl->sd_buf, acl->sd_size); - return ret; -} - -int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl) -{ - unsigned int version2; - int ret; - - n->offset = 0; - ret = ndr_read_int16(n, &acl->version); - if (ret) - return ret; - if (acl->version != 4) { - ksmbd_debug(VFS, "v%d version is not supported\n", acl->version); - return -EINVAL; - } - - ret = ndr_read_int32(n, &version2); - if (ret) - return ret; - if (acl->version != version2) { - ksmbd_debug(VFS, "ndr version mismatched(version: %d, version2: %d)\n", - acl->version, version2); - return -EINVAL; - } - - /* Read Level */ - ret = ndr_read_int16(n, NULL); - if (ret) - return ret; - - /* Read Ref Id */ - ret = ndr_read_int32(n, NULL); - if (ret) - return ret; - - ret = ndr_read_int16(n, &acl->hash_type); - if (ret) - return ret; - - ret = ndr_read_bytes(n, acl->hash, XATTR_SD_HASH_SIZE); - if (ret) - return ret; - - ndr_read_bytes(n, acl->desc, 10); - if (strncmp(acl->desc, "posix_acl", 9)) { - pr_err("Invalid acl description : %s\n", acl->desc); - return -EINVAL; - } - - /* Read Time */ - ret = ndr_read_int64(n, NULL); - if (ret) - return ret; - - /* Read Posix ACL hash */ - ret = ndr_read_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE); - if (ret) - return ret; - - acl->sd_size = n->length - n->offset; - acl->sd_buf = kzalloc(acl->sd_size, GFP_KERNEL); - if (!acl->sd_buf) - return -ENOMEM; - - ret = ndr_read_bytes(n, acl->sd_buf, acl->sd_size); - return ret; -} diff --git a/fs/ksmbd/ndr.h b/fs/ksmbd/ndr.h deleted file mode 100644 index 60ca265d1bb0..000000000000 --- a/fs/ksmbd/ndr.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2020 Samsung Electronics Co., Ltd. - * Author(s): Namjae Jeon <linkinjeon@kernel.org> - */ - -struct ndr { - char *data; - int offset; - int length; -}; - -#define NDR_NTSD_OFFSETOF 0xA0 - -int ndr_encode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da); -int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da); -int ndr_encode_posix_acl(struct ndr *n, struct user_namespace *user_ns, - struct inode *inode, struct xattr_smb_acl *acl, - struct xattr_smb_acl *def_acl); -int ndr_encode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl); -int ndr_encode_v3_ntacl(struct ndr *n, struct xattr_ntacl *acl); -int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl); diff --git a/fs/ksmbd/nterr.h b/fs/ksmbd/nterr.h deleted file mode 100644 index 2f358f88a018..000000000000 --- a/fs/ksmbd/nterr.h +++ /dev/null @@ -1,543 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Unix SMB/Netbios implementation. - * Version 1.9. - * NT error code constants - * Copyright (C) Andrew Tridgell 1992-2000 - * Copyright (C) John H Terpstra 1996-2000 - * Copyright (C) Luke Kenneth Casson Leighton 1996-2000 - * Copyright (C) Paul Ashton 1998-2000 - */ - -#ifndef _NTERR_H -#define _NTERR_H - -/* Win32 Status codes. */ -#define NT_STATUS_MORE_ENTRIES 0x0105 -#define NT_ERROR_INVALID_PARAMETER 0x0057 -#define NT_ERROR_INSUFFICIENT_BUFFER 0x007a -#define NT_STATUS_1804 0x070c -#define NT_STATUS_NOTIFY_ENUM_DIR 0x010c -#define NT_STATUS_INVALID_LOCK_RANGE (0xC0000000 | 0x01a1) -/* - * Win32 Error codes extracted using a loop in smbclient then printing a netmon - * sniff to a file. - */ - -#define NT_STATUS_OK 0x0000 -#define NT_STATUS_SOME_UNMAPPED 0x0107 -#define NT_STATUS_BUFFER_OVERFLOW 0x80000005 -#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a -#define NT_STATUS_MEDIA_CHANGED 0x8000001c -#define NT_STATUS_END_OF_MEDIA 0x8000001e -#define NT_STATUS_MEDIA_CHECK 0x80000020 -#define NT_STATUS_NO_DATA_DETECTED 0x8000001c -#define NT_STATUS_STOPPED_ON_SYMLINK 0x8000002d -#define NT_STATUS_DEVICE_REQUIRES_CLEANING 0x80000288 -#define NT_STATUS_DEVICE_DOOR_OPEN 0x80000288 -#define NT_STATUS_UNSUCCESSFUL (0xC0000000 | 0x0001) -#define NT_STATUS_NOT_IMPLEMENTED (0xC0000000 | 0x0002) -#define NT_STATUS_INVALID_INFO_CLASS (0xC0000000 | 0x0003) -#define NT_STATUS_INFO_LENGTH_MISMATCH (0xC0000000 | 0x0004) -#define NT_STATUS_ACCESS_VIOLATION (0xC0000000 | 0x0005) -#define NT_STATUS_IN_PAGE_ERROR (0xC0000000 | 0x0006) -#define NT_STATUS_PAGEFILE_QUOTA (0xC0000000 | 0x0007) -#define NT_STATUS_INVALID_HANDLE (0xC0000000 | 0x0008) -#define NT_STATUS_BAD_INITIAL_STACK (0xC0000000 | 0x0009) -#define NT_STATUS_BAD_INITIAL_PC (0xC0000000 | 0x000a) -#define NT_STATUS_INVALID_CID (0xC0000000 | 0x000b) -#define NT_STATUS_TIMER_NOT_CANCELED (0xC0000000 | 0x000c) -#define NT_STATUS_INVALID_PARAMETER (0xC0000000 | 0x000d) -#define NT_STATUS_NO_SUCH_DEVICE (0xC0000000 | 0x000e) -#define NT_STATUS_NO_SUCH_FILE (0xC0000000 | 0x000f) -#define NT_STATUS_INVALID_DEVICE_REQUEST (0xC0000000 | 0x0010) -#define NT_STATUS_END_OF_FILE (0xC0000000 | 0x0011) -#define NT_STATUS_WRONG_VOLUME (0xC0000000 | 0x0012) -#define NT_STATUS_NO_MEDIA_IN_DEVICE (0xC0000000 | 0x0013) -#define NT_STATUS_UNRECOGNIZED_MEDIA (0xC0000000 | 0x0014) -#define NT_STATUS_NONEXISTENT_SECTOR (0xC0000000 | 0x0015) -#define NT_STATUS_MORE_PROCESSING_REQUIRED (0xC0000000 | 0x0016) -#define NT_STATUS_NO_MEMORY (0xC0000000 | 0x0017) -#define NT_STATUS_CONFLICTING_ADDRESSES (0xC0000000 | 0x0018) -#define NT_STATUS_NOT_MAPPED_VIEW (0xC0000000 | 0x0019) -#define NT_STATUS_UNABLE_TO_FREE_VM (0x80000000 | 0x001a) -#define NT_STATUS_UNABLE_TO_DELETE_SECTION (0xC0000000 | 0x001b) -#define NT_STATUS_INVALID_SYSTEM_SERVICE (0xC0000000 | 0x001c) -#define NT_STATUS_ILLEGAL_INSTRUCTION (0xC0000000 | 0x001d) -#define NT_STATUS_INVALID_LOCK_SEQUENCE (0xC0000000 | 0x001e) -#define NT_STATUS_INVALID_VIEW_SIZE (0xC0000000 | 0x001f) -#define NT_STATUS_INVALID_FILE_FOR_SECTION (0xC0000000 | 0x0020) -#define NT_STATUS_ALREADY_COMMITTED (0xC0000000 | 0x0021) -#define NT_STATUS_ACCESS_DENIED (0xC0000000 | 0x0022) -#define NT_STATUS_BUFFER_TOO_SMALL (0xC0000000 | 0x0023) -#define NT_STATUS_OBJECT_TYPE_MISMATCH (0xC0000000 | 0x0024) -#define NT_STATUS_NONCONTINUABLE_EXCEPTION (0xC0000000 | 0x0025) -#define NT_STATUS_INVALID_DISPOSITION (0xC0000000 | 0x0026) -#define NT_STATUS_UNWIND (0xC0000000 | 0x0027) -#define NT_STATUS_BAD_STACK (0xC0000000 | 0x0028) -#define NT_STATUS_INVALID_UNWIND_TARGET (0xC0000000 | 0x0029) -#define NT_STATUS_NOT_LOCKED (0xC0000000 | 0x002a) -#define NT_STATUS_PARITY_ERROR (0xC0000000 | 0x002b) -#define NT_STATUS_UNABLE_TO_DECOMMIT_VM (0xC0000000 | 0x002c) -#define NT_STATUS_NOT_COMMITTED (0xC0000000 | 0x002d) -#define NT_STATUS_INVALID_PORT_ATTRIBUTES (0xC0000000 | 0x002e) -#define NT_STATUS_PORT_MESSAGE_TOO_LONG (0xC0000000 | 0x002f) -#define NT_STATUS_INVALID_PARAMETER_MIX (0xC0000000 | 0x0030) -#define NT_STATUS_INVALID_QUOTA_LOWER (0xC0000000 | 0x0031) -#define NT_STATUS_DISK_CORRUPT_ERROR (0xC0000000 | 0x0032) -#define NT_STATUS_OBJECT_NAME_INVALID (0xC0000000 | 0x0033) -#define NT_STATUS_OBJECT_NAME_NOT_FOUND (0xC0000000 | 0x0034) -#define NT_STATUS_OBJECT_NAME_COLLISION (0xC0000000 | 0x0035) -#define NT_STATUS_HANDLE_NOT_WAITABLE (0xC0000000 | 0x0036) -#define NT_STATUS_PORT_DISCONNECTED (0xC0000000 | 0x0037) -#define NT_STATUS_DEVICE_ALREADY_ATTACHED (0xC0000000 | 0x0038) -#define NT_STATUS_OBJECT_PATH_INVALID (0xC0000000 | 0x0039) -#define NT_STATUS_OBJECT_PATH_NOT_FOUND (0xC0000000 | 0x003a) -#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD (0xC0000000 | 0x003b) -#define NT_STATUS_DATA_OVERRUN (0xC0000000 | 0x003c) -#define NT_STATUS_DATA_LATE_ERROR (0xC0000000 | 0x003d) -#define NT_STATUS_DATA_ERROR (0xC0000000 | 0x003e) -#define NT_STATUS_CRC_ERROR (0xC0000000 | 0x003f) -#define NT_STATUS_SECTION_TOO_BIG (0xC0000000 | 0x0040) -#define NT_STATUS_PORT_CONNECTION_REFUSED (0xC0000000 | 0x0041) -#define NT_STATUS_INVALID_PORT_HANDLE (0xC0000000 | 0x0042) -#define NT_STATUS_SHARING_VIOLATION (0xC0000000 | 0x0043) -#define NT_STATUS_QUOTA_EXCEEDED (0xC0000000 | 0x0044) -#define NT_STATUS_INVALID_PAGE_PROTECTION (0xC0000000 | 0x0045) -#define NT_STATUS_MUTANT_NOT_OWNED (0xC0000000 | 0x0046) -#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED (0xC0000000 | 0x0047) -#define NT_STATUS_PORT_ALREADY_SET (0xC0000000 | 0x0048) -#define NT_STATUS_SECTION_NOT_IMAGE (0xC0000000 | 0x0049) -#define NT_STATUS_SUSPEND_COUNT_EXCEEDED (0xC0000000 | 0x004a) -#define NT_STATUS_THREAD_IS_TERMINATING (0xC0000000 | 0x004b) -#define NT_STATUS_BAD_WORKING_SET_LIMIT (0xC0000000 | 0x004c) -#define NT_STATUS_INCOMPATIBLE_FILE_MAP (0xC0000000 | 0x004d) -#define NT_STATUS_SECTION_PROTECTION (0xC0000000 | 0x004e) -#define NT_STATUS_EAS_NOT_SUPPORTED (0xC0000000 | 0x004f) -#define NT_STATUS_EA_TOO_LARGE (0xC0000000 | 0x0050) -#define NT_STATUS_NONEXISTENT_EA_ENTRY (0xC0000000 | 0x0051) -#define NT_STATUS_NO_EAS_ON_FILE (0xC0000000 | 0x0052) -#define NT_STATUS_EA_CORRUPT_ERROR (0xC0000000 | 0x0053) -#define NT_STATUS_FILE_LOCK_CONFLICT (0xC0000000 | 0x0054) -#define NT_STATUS_LOCK_NOT_GRANTED (0xC0000000 | 0x0055) -#define NT_STATUS_DELETE_PENDING (0xC0000000 | 0x0056) -#define NT_STATUS_CTL_FILE_NOT_SUPPORTED (0xC0000000 | 0x0057) -#define NT_STATUS_UNKNOWN_REVISION (0xC0000000 | 0x0058) -#define NT_STATUS_REVISION_MISMATCH (0xC0000000 | 0x0059) -#define NT_STATUS_INVALID_OWNER (0xC0000000 | 0x005a) -#define NT_STATUS_INVALID_PRIMARY_GROUP (0xC0000000 | 0x005b) -#define NT_STATUS_NO_IMPERSONATION_TOKEN (0xC0000000 | 0x005c) -#define NT_STATUS_CANT_DISABLE_MANDATORY (0xC0000000 | 0x005d) -#define NT_STATUS_NO_LOGON_SERVERS (0xC0000000 | 0x005e) -#define NT_STATUS_NO_SUCH_LOGON_SESSION (0xC0000000 | 0x005f) -#define NT_STATUS_NO_SUCH_PRIVILEGE (0xC0000000 | 0x0060) -#define NT_STATUS_PRIVILEGE_NOT_HELD (0xC0000000 | 0x0061) -#define NT_STATUS_INVALID_ACCOUNT_NAME (0xC0000000 | 0x0062) -#define NT_STATUS_USER_EXISTS (0xC0000000 | 0x0063) -#define NT_STATUS_NO_SUCH_USER (0xC0000000 | 0x0064) -#define NT_STATUS_GROUP_EXISTS (0xC0000000 | 0x0065) -#define NT_STATUS_NO_SUCH_GROUP (0xC0000000 | 0x0066) -#define NT_STATUS_MEMBER_IN_GROUP (0xC0000000 | 0x0067) -#define NT_STATUS_MEMBER_NOT_IN_GROUP (0xC0000000 | 0x0068) -#define NT_STATUS_LAST_ADMIN (0xC0000000 | 0x0069) -#define NT_STATUS_WRONG_PASSWORD (0xC0000000 | 0x006a) -#define NT_STATUS_ILL_FORMED_PASSWORD (0xC0000000 | 0x006b) -#define NT_STATUS_PASSWORD_RESTRICTION (0xC0000000 | 0x006c) -#define NT_STATUS_LOGON_FAILURE (0xC0000000 | 0x006d) -#define NT_STATUS_ACCOUNT_RESTRICTION (0xC0000000 | 0x006e) -#define NT_STATUS_INVALID_LOGON_HOURS (0xC0000000 | 0x006f) -#define NT_STATUS_INVALID_WORKSTATION (0xC0000000 | 0x0070) -#define NT_STATUS_PASSWORD_EXPIRED (0xC0000000 | 0x0071) -#define NT_STATUS_ACCOUNT_DISABLED (0xC0000000 | 0x0072) -#define NT_STATUS_NONE_MAPPED (0xC0000000 | 0x0073) -#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED (0xC0000000 | 0x0074) -#define NT_STATUS_LUIDS_EXHAUSTED (0xC0000000 | 0x0075) -#define NT_STATUS_INVALID_SUB_AUTHORITY (0xC0000000 | 0x0076) -#define NT_STATUS_INVALID_ACL (0xC0000000 | 0x0077) -#define NT_STATUS_INVALID_SID (0xC0000000 | 0x0078) -#define NT_STATUS_INVALID_SECURITY_DESCR (0xC0000000 | 0x0079) -#define NT_STATUS_PROCEDURE_NOT_FOUND (0xC0000000 | 0x007a) -#define NT_STATUS_INVALID_IMAGE_FORMAT (0xC0000000 | 0x007b) -#define NT_STATUS_NO_TOKEN (0xC0000000 | 0x007c) -#define NT_STATUS_BAD_INHERITANCE_ACL (0xC0000000 | 0x007d) -#define NT_STATUS_RANGE_NOT_LOCKED (0xC0000000 | 0x007e) -#define NT_STATUS_DISK_FULL (0xC0000000 | 0x007f) -#define NT_STATUS_SERVER_DISABLED (0xC0000000 | 0x0080) -#define NT_STATUS_SERVER_NOT_DISABLED (0xC0000000 | 0x0081) -#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED (0xC0000000 | 0x0082) -#define NT_STATUS_GUIDS_EXHAUSTED (0xC0000000 | 0x0083) -#define NT_STATUS_INVALID_ID_AUTHORITY (0xC0000000 | 0x0084) -#define NT_STATUS_AGENTS_EXHAUSTED (0xC0000000 | 0x0085) -#define NT_STATUS_INVALID_VOLUME_LABEL (0xC0000000 | 0x0086) -#define NT_STATUS_SECTION_NOT_EXTENDED (0xC0000000 | 0x0087) -#define NT_STATUS_NOT_MAPPED_DATA (0xC0000000 | 0x0088) -#define NT_STATUS_RESOURCE_DATA_NOT_FOUND (0xC0000000 | 0x0089) -#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND (0xC0000000 | 0x008a) -#define NT_STATUS_RESOURCE_NAME_NOT_FOUND (0xC0000000 | 0x008b) -#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED (0xC0000000 | 0x008c) -#define NT_STATUS_FLOAT_DENORMAL_OPERAND (0xC0000000 | 0x008d) -#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO (0xC0000000 | 0x008e) -#define NT_STATUS_FLOAT_INEXACT_RESULT (0xC0000000 | 0x008f) -#define NT_STATUS_FLOAT_INVALID_OPERATION (0xC0000000 | 0x0090) -#define NT_STATUS_FLOAT_OVERFLOW (0xC0000000 | 0x0091) -#define NT_STATUS_FLOAT_STACK_CHECK (0xC0000000 | 0x0092) -#define NT_STATUS_FLOAT_UNDERFLOW (0xC0000000 | 0x0093) -#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO (0xC0000000 | 0x0094) -#define NT_STATUS_INTEGER_OVERFLOW (0xC0000000 | 0x0095) -#define NT_STATUS_PRIVILEGED_INSTRUCTION (0xC0000000 | 0x0096) -#define NT_STATUS_TOO_MANY_PAGING_FILES (0xC0000000 | 0x0097) -#define NT_STATUS_FILE_INVALID (0xC0000000 | 0x0098) -#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED (0xC0000000 | 0x0099) -#define NT_STATUS_INSUFFICIENT_RESOURCES (0xC0000000 | 0x009a) -#define NT_STATUS_DFS_EXIT_PATH_FOUND (0xC0000000 | 0x009b) -#define NT_STATUS_DEVICE_DATA_ERROR (0xC0000000 | 0x009c) -#define NT_STATUS_DEVICE_NOT_CONNECTED (0xC0000000 | 0x009d) -#define NT_STATUS_DEVICE_POWER_FAILURE (0xC0000000 | 0x009e) -#define NT_STATUS_FREE_VM_NOT_AT_BASE (0xC0000000 | 0x009f) -#define NT_STATUS_MEMORY_NOT_ALLOCATED (0xC0000000 | 0x00a0) -#define NT_STATUS_WORKING_SET_QUOTA (0xC0000000 | 0x00a1) -#define NT_STATUS_MEDIA_WRITE_PROTECTED (0xC0000000 | 0x00a2) -#define NT_STATUS_DEVICE_NOT_READY (0xC0000000 | 0x00a3) -#define NT_STATUS_INVALID_GROUP_ATTRIBUTES (0xC0000000 | 0x00a4) -#define NT_STATUS_BAD_IMPERSONATION_LEVEL (0xC0000000 | 0x00a5) -#define NT_STATUS_CANT_OPEN_ANONYMOUS (0xC0000000 | 0x00a6) -#define NT_STATUS_BAD_VALIDATION_CLASS (0xC0000000 | 0x00a7) -#define NT_STATUS_BAD_TOKEN_TYPE (0xC0000000 | 0x00a8) -#define NT_STATUS_BAD_MASTER_BOOT_RECORD (0xC0000000 | 0x00a9) -#define NT_STATUS_INSTRUCTION_MISALIGNMENT (0xC0000000 | 0x00aa) -#define NT_STATUS_INSTANCE_NOT_AVAILABLE (0xC0000000 | 0x00ab) -#define NT_STATUS_PIPE_NOT_AVAILABLE (0xC0000000 | 0x00ac) -#define NT_STATUS_INVALID_PIPE_STATE (0xC0000000 | 0x00ad) -#define NT_STATUS_PIPE_BUSY (0xC0000000 | 0x00ae) -#define NT_STATUS_ILLEGAL_FUNCTION (0xC0000000 | 0x00af) -#define NT_STATUS_PIPE_DISCONNECTED (0xC0000000 | 0x00b0) -#define NT_STATUS_PIPE_CLOSING (0xC0000000 | 0x00b1) -#define NT_STATUS_PIPE_CONNECTED (0xC0000000 | 0x00b2) -#define NT_STATUS_PIPE_LISTENING (0xC0000000 | 0x00b3) -#define NT_STATUS_INVALID_READ_MODE (0xC0000000 | 0x00b4) -#define NT_STATUS_IO_TIMEOUT (0xC0000000 | 0x00b5) -#define NT_STATUS_FILE_FORCED_CLOSED (0xC0000000 | 0x00b6) -#define NT_STATUS_PROFILING_NOT_STARTED (0xC0000000 | 0x00b7) -#define NT_STATUS_PROFILING_NOT_STOPPED (0xC0000000 | 0x00b8) -#define NT_STATUS_COULD_NOT_INTERPRET (0xC0000000 | 0x00b9) -#define NT_STATUS_FILE_IS_A_DIRECTORY (0xC0000000 | 0x00ba) -#define NT_STATUS_NOT_SUPPORTED (0xC0000000 | 0x00bb) -#define NT_STATUS_REMOTE_NOT_LISTENING (0xC0000000 | 0x00bc) -#define NT_STATUS_DUPLICATE_NAME (0xC0000000 | 0x00bd) -#define NT_STATUS_BAD_NETWORK_PATH (0xC0000000 | 0x00be) -#define NT_STATUS_NETWORK_BUSY (0xC0000000 | 0x00bf) -#define NT_STATUS_DEVICE_DOES_NOT_EXIST (0xC0000000 | 0x00c0) -#define NT_STATUS_TOO_MANY_COMMANDS (0xC0000000 | 0x00c1) -#define NT_STATUS_ADAPTER_HARDWARE_ERROR (0xC0000000 | 0x00c2) -#define NT_STATUS_INVALID_NETWORK_RESPONSE (0xC0000000 | 0x00c3) -#define NT_STATUS_UNEXPECTED_NETWORK_ERROR (0xC0000000 | 0x00c4) -#define NT_STATUS_BAD_REMOTE_ADAPTER (0xC0000000 | 0x00c5) -#define NT_STATUS_PRINT_QUEUE_FULL (0xC0000000 | 0x00c6) -#define NT_STATUS_NO_SPOOL_SPACE (0xC0000000 | 0x00c7) -#define NT_STATUS_PRINT_CANCELLED (0xC0000000 | 0x00c8) -#define NT_STATUS_NETWORK_NAME_DELETED (0xC0000000 | 0x00c9) -#define NT_STATUS_NETWORK_ACCESS_DENIED (0xC0000000 | 0x00ca) -#define NT_STATUS_BAD_DEVICE_TYPE (0xC0000000 | 0x00cb) -#define NT_STATUS_BAD_NETWORK_NAME (0xC0000000 | 0x00cc) -#define NT_STATUS_TOO_MANY_NAMES (0xC0000000 | 0x00cd) -#define NT_STATUS_TOO_MANY_SESSIONS (0xC0000000 | 0x00ce) -#define NT_STATUS_SHARING_PAUSED (0xC0000000 | 0x00cf) -#define NT_STATUS_REQUEST_NOT_ACCEPTED (0xC0000000 | 0x00d0) -#define NT_STATUS_REDIRECTOR_PAUSED (0xC0000000 | 0x00d1) -#define NT_STATUS_NET_WRITE_FAULT (0xC0000000 | 0x00d2) -#define NT_STATUS_PROFILING_AT_LIMIT (0xC0000000 | 0x00d3) -#define NT_STATUS_NOT_SAME_DEVICE (0xC0000000 | 0x00d4) -#define NT_STATUS_FILE_RENAMED (0xC0000000 | 0x00d5) -#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED (0xC0000000 | 0x00d6) -#define NT_STATUS_NO_SECURITY_ON_OBJECT (0xC0000000 | 0x00d7) -#define NT_STATUS_CANT_WAIT (0xC0000000 | 0x00d8) -#define NT_STATUS_PIPE_EMPTY (0xC0000000 | 0x00d9) -#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO (0xC0000000 | 0x00da) -#define NT_STATUS_CANT_TERMINATE_SELF (0xC0000000 | 0x00db) -#define NT_STATUS_INVALID_SERVER_STATE (0xC0000000 | 0x00dc) -#define NT_STATUS_INVALID_DOMAIN_STATE (0xC0000000 | 0x00dd) -#define NT_STATUS_INVALID_DOMAIN_ROLE (0xC0000000 | 0x00de) -#define NT_STATUS_NO_SUCH_DOMAIN (0xC0000000 | 0x00df) -#define NT_STATUS_DOMAIN_EXISTS (0xC0000000 | 0x00e0) -#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED (0xC0000000 | 0x00e1) -#define NT_STATUS_OPLOCK_NOT_GRANTED (0xC0000000 | 0x00e2) -#define NT_STATUS_INVALID_OPLOCK_PROTOCOL (0xC0000000 | 0x00e3) -#define NT_STATUS_INTERNAL_DB_CORRUPTION (0xC0000000 | 0x00e4) -#define NT_STATUS_INTERNAL_ERROR (0xC0000000 | 0x00e5) -#define NT_STATUS_GENERIC_NOT_MAPPED (0xC0000000 | 0x00e6) -#define NT_STATUS_BAD_DESCRIPTOR_FORMAT (0xC0000000 | 0x00e7) -#define NT_STATUS_INVALID_USER_BUFFER (0xC0000000 | 0x00e8) -#define NT_STATUS_UNEXPECTED_IO_ERROR (0xC0000000 | 0x00e9) -#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR (0xC0000000 | 0x00ea) -#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR (0xC0000000 | 0x00eb) -#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR (0xC0000000 | 0x00ec) -#define NT_STATUS_NOT_LOGON_PROCESS (0xC0000000 | 0x00ed) -#define NT_STATUS_LOGON_SESSION_EXISTS (0xC0000000 | 0x00ee) -#define NT_STATUS_INVALID_PARAMETER_1 (0xC0000000 | 0x00ef) -#define NT_STATUS_INVALID_PARAMETER_2 (0xC0000000 | 0x00f0) -#define NT_STATUS_INVALID_PARAMETER_3 (0xC0000000 | 0x00f1) -#define NT_STATUS_INVALID_PARAMETER_4 (0xC0000000 | 0x00f2) -#define NT_STATUS_INVALID_PARAMETER_5 (0xC0000000 | 0x00f3) -#define NT_STATUS_INVALID_PARAMETER_6 (0xC0000000 | 0x00f4) -#define NT_STATUS_INVALID_PARAMETER_7 (0xC0000000 | 0x00f5) -#define NT_STATUS_INVALID_PARAMETER_8 (0xC0000000 | 0x00f6) -#define NT_STATUS_INVALID_PARAMETER_9 (0xC0000000 | 0x00f7) -#define NT_STATUS_INVALID_PARAMETER_10 (0xC0000000 | 0x00f8) -#define NT_STATUS_INVALID_PARAMETER_11 (0xC0000000 | 0x00f9) -#define NT_STATUS_INVALID_PARAMETER_12 (0xC0000000 | 0x00fa) -#define NT_STATUS_REDIRECTOR_NOT_STARTED (0xC0000000 | 0x00fb) -#define NT_STATUS_REDIRECTOR_STARTED (0xC0000000 | 0x00fc) -#define NT_STATUS_STACK_OVERFLOW (0xC0000000 | 0x00fd) -#define NT_STATUS_NO_SUCH_PACKAGE (0xC0000000 | 0x00fe) -#define NT_STATUS_BAD_FUNCTION_TABLE (0xC0000000 | 0x00ff) -#define NT_STATUS_DIRECTORY_NOT_EMPTY (0xC0000000 | 0x0101) -#define NT_STATUS_FILE_CORRUPT_ERROR (0xC0000000 | 0x0102) -#define NT_STATUS_NOT_A_DIRECTORY (0xC0000000 | 0x0103) -#define NT_STATUS_BAD_LOGON_SESSION_STATE (0xC0000000 | 0x0104) -#define NT_STATUS_LOGON_SESSION_COLLISION (0xC0000000 | 0x0105) -#define NT_STATUS_NAME_TOO_LONG (0xC0000000 | 0x0106) -#define NT_STATUS_FILES_OPEN (0xC0000000 | 0x0107) -#define NT_STATUS_CONNECTION_IN_USE (0xC0000000 | 0x0108) -#define NT_STATUS_MESSAGE_NOT_FOUND (0xC0000000 | 0x0109) -#define NT_STATUS_PROCESS_IS_TERMINATING (0xC0000000 | 0x010a) -#define NT_STATUS_INVALID_LOGON_TYPE (0xC0000000 | 0x010b) -#define NT_STATUS_NO_GUID_TRANSLATION (0xC0000000 | 0x010c) -#define NT_STATUS_CANNOT_IMPERSONATE (0xC0000000 | 0x010d) -#define NT_STATUS_IMAGE_ALREADY_LOADED (0xC0000000 | 0x010e) -#define NT_STATUS_ABIOS_NOT_PRESENT (0xC0000000 | 0x010f) -#define NT_STATUS_ABIOS_LID_NOT_EXIST (0xC0000000 | 0x0110) -#define NT_STATUS_ABIOS_LID_ALREADY_OWNED (0xC0000000 | 0x0111) -#define NT_STATUS_ABIOS_NOT_LID_OWNER (0xC0000000 | 0x0112) -#define NT_STATUS_ABIOS_INVALID_COMMAND (0xC0000000 | 0x0113) -#define NT_STATUS_ABIOS_INVALID_LID (0xC0000000 | 0x0114) -#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE (0xC0000000 | 0x0115) -#define NT_STATUS_ABIOS_INVALID_SELECTOR (0xC0000000 | 0x0116) -#define NT_STATUS_NO_LDT (0xC0000000 | 0x0117) -#define NT_STATUS_INVALID_LDT_SIZE (0xC0000000 | 0x0118) -#define NT_STATUS_INVALID_LDT_OFFSET (0xC0000000 | 0x0119) -#define NT_STATUS_INVALID_LDT_DESCRIPTOR (0xC0000000 | 0x011a) -#define NT_STATUS_INVALID_IMAGE_NE_FORMAT (0xC0000000 | 0x011b) -#define NT_STATUS_RXACT_INVALID_STATE (0xC0000000 | 0x011c) -#define NT_STATUS_RXACT_COMMIT_FAILURE (0xC0000000 | 0x011d) -#define NT_STATUS_MAPPED_FILE_SIZE_ZERO (0xC0000000 | 0x011e) -#define NT_STATUS_TOO_MANY_OPENED_FILES (0xC0000000 | 0x011f) -#define NT_STATUS_CANCELLED (0xC0000000 | 0x0120) -#define NT_STATUS_CANNOT_DELETE (0xC0000000 | 0x0121) -#define NT_STATUS_INVALID_COMPUTER_NAME (0xC0000000 | 0x0122) -#define NT_STATUS_FILE_DELETED (0xC0000000 | 0x0123) -#define NT_STATUS_SPECIAL_ACCOUNT (0xC0000000 | 0x0124) -#define NT_STATUS_SPECIAL_GROUP (0xC0000000 | 0x0125) -#define NT_STATUS_SPECIAL_USER (0xC0000000 | 0x0126) -#define NT_STATUS_MEMBERS_PRIMARY_GROUP (0xC0000000 | 0x0127) -#define NT_STATUS_FILE_CLOSED (0xC0000000 | 0x0128) -#define NT_STATUS_TOO_MANY_THREADS (0xC0000000 | 0x0129) -#define NT_STATUS_THREAD_NOT_IN_PROCESS (0xC0000000 | 0x012a) -#define NT_STATUS_TOKEN_ALREADY_IN_USE (0xC0000000 | 0x012b) -#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED (0xC0000000 | 0x012c) -#define NT_STATUS_COMMITMENT_LIMIT (0xC0000000 | 0x012d) -#define NT_STATUS_INVALID_IMAGE_LE_FORMAT (0xC0000000 | 0x012e) -#define NT_STATUS_INVALID_IMAGE_NOT_MZ (0xC0000000 | 0x012f) -#define NT_STATUS_INVALID_IMAGE_PROTECT (0xC0000000 | 0x0130) -#define NT_STATUS_INVALID_IMAGE_WIN_16 (0xC0000000 | 0x0131) -#define NT_STATUS_LOGON_SERVER_CONFLICT (0xC0000000 | 0x0132) -#define NT_STATUS_TIME_DIFFERENCE_AT_DC (0xC0000000 | 0x0133) -#define NT_STATUS_SYNCHRONIZATION_REQUIRED (0xC0000000 | 0x0134) -#define NT_STATUS_DLL_NOT_FOUND (0xC0000000 | 0x0135) -#define NT_STATUS_OPEN_FAILED (0xC0000000 | 0x0136) -#define NT_STATUS_IO_PRIVILEGE_FAILED (0xC0000000 | 0x0137) -#define NT_STATUS_ORDINAL_NOT_FOUND (0xC0000000 | 0x0138) -#define NT_STATUS_ENTRYPOINT_NOT_FOUND (0xC0000000 | 0x0139) -#define NT_STATUS_CONTROL_C_EXIT (0xC0000000 | 0x013a) -#define NT_STATUS_LOCAL_DISCONNECT (0xC0000000 | 0x013b) -#define NT_STATUS_REMOTE_DISCONNECT (0xC0000000 | 0x013c) -#define NT_STATUS_REMOTE_RESOURCES (0xC0000000 | 0x013d) -#define NT_STATUS_LINK_FAILED (0xC0000000 | 0x013e) -#define NT_STATUS_LINK_TIMEOUT (0xC0000000 | 0x013f) -#define NT_STATUS_INVALID_CONNECTION (0xC0000000 | 0x0140) -#define NT_STATUS_INVALID_ADDRESS (0xC0000000 | 0x0141) -#define NT_STATUS_DLL_INIT_FAILED (0xC0000000 | 0x0142) -#define NT_STATUS_MISSING_SYSTEMFILE (0xC0000000 | 0x0143) -#define NT_STATUS_UNHANDLED_EXCEPTION (0xC0000000 | 0x0144) -#define NT_STATUS_APP_INIT_FAILURE (0xC0000000 | 0x0145) -#define NT_STATUS_PAGEFILE_CREATE_FAILED (0xC0000000 | 0x0146) -#define NT_STATUS_NO_PAGEFILE (0xC0000000 | 0x0147) -#define NT_STATUS_INVALID_LEVEL (0xC0000000 | 0x0148) -#define NT_STATUS_WRONG_PASSWORD_CORE (0xC0000000 | 0x0149) -#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT (0xC0000000 | 0x014a) -#define NT_STATUS_PIPE_BROKEN (0xC0000000 | 0x014b) -#define NT_STATUS_REGISTRY_CORRUPT (0xC0000000 | 0x014c) -#define NT_STATUS_REGISTRY_IO_FAILED (0xC0000000 | 0x014d) -#define NT_STATUS_NO_EVENT_PAIR (0xC0000000 | 0x014e) -#define NT_STATUS_UNRECOGNIZED_VOLUME (0xC0000000 | 0x014f) -#define NT_STATUS_SERIAL_NO_DEVICE_INITED (0xC0000000 | 0x0150) -#define NT_STATUS_NO_SUCH_ALIAS (0xC0000000 | 0x0151) -#define NT_STATUS_MEMBER_NOT_IN_ALIAS (0xC0000000 | 0x0152) -#define NT_STATUS_MEMBER_IN_ALIAS (0xC0000000 | 0x0153) -#define NT_STATUS_ALIAS_EXISTS (0xC0000000 | 0x0154) -#define NT_STATUS_LOGON_NOT_GRANTED (0xC0000000 | 0x0155) -#define NT_STATUS_TOO_MANY_SECRETS (0xC0000000 | 0x0156) -#define NT_STATUS_SECRET_TOO_LONG (0xC0000000 | 0x0157) -#define NT_STATUS_INTERNAL_DB_ERROR (0xC0000000 | 0x0158) -#define NT_STATUS_FULLSCREEN_MODE (0xC0000000 | 0x0159) -#define NT_STATUS_TOO_MANY_CONTEXT_IDS (0xC0000000 | 0x015a) -#define NT_STATUS_LOGON_TYPE_NOT_GRANTED (0xC0000000 | 0x015b) -#define NT_STATUS_NOT_REGISTRY_FILE (0xC0000000 | 0x015c) -#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED (0xC0000000 | 0x015d) -#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR (0xC0000000 | 0x015e) -#define NT_STATUS_FT_MISSING_MEMBER (0xC0000000 | 0x015f) -#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY (0xC0000000 | 0x0160) -#define NT_STATUS_ILLEGAL_CHARACTER (0xC0000000 | 0x0161) -#define NT_STATUS_UNMAPPABLE_CHARACTER (0xC0000000 | 0x0162) -#define NT_STATUS_UNDEFINED_CHARACTER (0xC0000000 | 0x0163) -#define NT_STATUS_FLOPPY_VOLUME (0xC0000000 | 0x0164) -#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND (0xC0000000 | 0x0165) -#define NT_STATUS_FLOPPY_WRONG_CYLINDER (0xC0000000 | 0x0166) -#define NT_STATUS_FLOPPY_UNKNOWN_ERROR (0xC0000000 | 0x0167) -#define NT_STATUS_FLOPPY_BAD_REGISTERS (0xC0000000 | 0x0168) -#define NT_STATUS_DISK_RECALIBRATE_FAILED (0xC0000000 | 0x0169) -#define NT_STATUS_DISK_OPERATION_FAILED (0xC0000000 | 0x016a) -#define NT_STATUS_DISK_RESET_FAILED (0xC0000000 | 0x016b) -#define NT_STATUS_SHARED_IRQ_BUSY (0xC0000000 | 0x016c) -#define NT_STATUS_FT_ORPHANING (0xC0000000 | 0x016d) -#define NT_STATUS_PARTITION_FAILURE (0xC0000000 | 0x0172) -#define NT_STATUS_INVALID_BLOCK_LENGTH (0xC0000000 | 0x0173) -#define NT_STATUS_DEVICE_NOT_PARTITIONED (0xC0000000 | 0x0174) -#define NT_STATUS_UNABLE_TO_LOCK_MEDIA (0xC0000000 | 0x0175) -#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA (0xC0000000 | 0x0176) -#define NT_STATUS_EOM_OVERFLOW (0xC0000000 | 0x0177) -#define NT_STATUS_NO_MEDIA (0xC0000000 | 0x0178) -#define NT_STATUS_NO_SUCH_MEMBER (0xC0000000 | 0x017a) -#define NT_STATUS_INVALID_MEMBER (0xC0000000 | 0x017b) -#define NT_STATUS_KEY_DELETED (0xC0000000 | 0x017c) -#define NT_STATUS_NO_LOG_SPACE (0xC0000000 | 0x017d) -#define NT_STATUS_TOO_MANY_SIDS (0xC0000000 | 0x017e) -#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED (0xC0000000 | 0x017f) -#define NT_STATUS_KEY_HAS_CHILDREN (0xC0000000 | 0x0180) -#define NT_STATUS_CHILD_MUST_BE_VOLATILE (0xC0000000 | 0x0181) -#define NT_STATUS_DEVICE_CONFIGURATION_ERROR (0xC0000000 | 0x0182) -#define NT_STATUS_DRIVER_INTERNAL_ERROR (0xC0000000 | 0x0183) -#define NT_STATUS_INVALID_DEVICE_STATE (0xC0000000 | 0x0184) -#define NT_STATUS_IO_DEVICE_ERROR (0xC0000000 | 0x0185) -#define NT_STATUS_DEVICE_PROTOCOL_ERROR (0xC0000000 | 0x0186) -#define NT_STATUS_BACKUP_CONTROLLER (0xC0000000 | 0x0187) -#define NT_STATUS_LOG_FILE_FULL (0xC0000000 | 0x0188) -#define NT_STATUS_TOO_LATE (0xC0000000 | 0x0189) -#define NT_STATUS_NO_TRUST_LSA_SECRET (0xC0000000 | 0x018a) -#define NT_STATUS_NO_TRUST_SAM_ACCOUNT (0xC0000000 | 0x018b) -#define NT_STATUS_TRUSTED_DOMAIN_FAILURE (0xC0000000 | 0x018c) -#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE (0xC0000000 | 0x018d) -#define NT_STATUS_EVENTLOG_FILE_CORRUPT (0xC0000000 | 0x018e) -#define NT_STATUS_EVENTLOG_CANT_START (0xC0000000 | 0x018f) -#define NT_STATUS_TRUST_FAILURE (0xC0000000 | 0x0190) -#define NT_STATUS_MUTANT_LIMIT_EXCEEDED (0xC0000000 | 0x0191) -#define NT_STATUS_NETLOGON_NOT_STARTED (0xC0000000 | 0x0192) -#define NT_STATUS_ACCOUNT_EXPIRED (0xC0000000 | 0x0193) -#define NT_STATUS_POSSIBLE_DEADLOCK (0xC0000000 | 0x0194) -#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT (0xC0000000 | 0x0195) -#define NT_STATUS_REMOTE_SESSION_LIMIT (0xC0000000 | 0x0196) -#define NT_STATUS_EVENTLOG_FILE_CHANGED (0xC0000000 | 0x0197) -#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT (0xC0000000 | 0x0198) -#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT (0xC0000000 | 0x0199) -#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT (0xC0000000 | 0x019a) -#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT (0xC0000000 | 0x019b) -#define NT_STATUS_FS_DRIVER_REQUIRED (0xC0000000 | 0x019c) -#define NT_STATUS_NO_USER_SESSION_KEY (0xC0000000 | 0x0202) -#define NT_STATUS_USER_SESSION_DELETED (0xC0000000 | 0x0203) -#define NT_STATUS_RESOURCE_LANG_NOT_FOUND (0xC0000000 | 0x0204) -#define NT_STATUS_INSUFF_SERVER_RESOURCES (0xC0000000 | 0x0205) -#define NT_STATUS_INVALID_BUFFER_SIZE (0xC0000000 | 0x0206) -#define NT_STATUS_INVALID_ADDRESS_COMPONENT (0xC0000000 | 0x0207) -#define NT_STATUS_INVALID_ADDRESS_WILDCARD (0xC0000000 | 0x0208) -#define NT_STATUS_TOO_MANY_ADDRESSES (0xC0000000 | 0x0209) -#define NT_STATUS_ADDRESS_ALREADY_EXISTS (0xC0000000 | 0x020a) -#define NT_STATUS_ADDRESS_CLOSED (0xC0000000 | 0x020b) -#define NT_STATUS_CONNECTION_DISCONNECTED (0xC0000000 | 0x020c) -#define NT_STATUS_CONNECTION_RESET (0xC0000000 | 0x020d) -#define NT_STATUS_TOO_MANY_NODES (0xC0000000 | 0x020e) -#define NT_STATUS_TRANSACTION_ABORTED (0xC0000000 | 0x020f) -#define NT_STATUS_TRANSACTION_TIMED_OUT (0xC0000000 | 0x0210) -#define NT_STATUS_TRANSACTION_NO_RELEASE (0xC0000000 | 0x0211) -#define NT_STATUS_TRANSACTION_NO_MATCH (0xC0000000 | 0x0212) -#define NT_STATUS_TRANSACTION_RESPONDED (0xC0000000 | 0x0213) -#define NT_STATUS_TRANSACTION_INVALID_ID (0xC0000000 | 0x0214) -#define NT_STATUS_TRANSACTION_INVALID_TYPE (0xC0000000 | 0x0215) -#define NT_STATUS_NOT_SERVER_SESSION (0xC0000000 | 0x0216) -#define NT_STATUS_NOT_CLIENT_SESSION (0xC0000000 | 0x0217) -#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE (0xC0000000 | 0x0218) -#define NT_STATUS_DEBUG_ATTACH_FAILED (0xC0000000 | 0x0219) -#define NT_STATUS_SYSTEM_PROCESS_TERMINATED (0xC0000000 | 0x021a) -#define NT_STATUS_DATA_NOT_ACCEPTED (0xC0000000 | 0x021b) -#define NT_STATUS_NO_BROWSER_SERVERS_FOUND (0xC0000000 | 0x021c) -#define NT_STATUS_VDM_HARD_ERROR (0xC0000000 | 0x021d) -#define NT_STATUS_DRIVER_CANCEL_TIMEOUT (0xC0000000 | 0x021e) -#define NT_STATUS_REPLY_MESSAGE_MISMATCH (0xC0000000 | 0x021f) -#define NT_STATUS_MAPPED_ALIGNMENT (0xC0000000 | 0x0220) -#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH (0xC0000000 | 0x0221) -#define NT_STATUS_LOST_WRITEBEHIND_DATA (0xC0000000 | 0x0222) -#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID (0xC0000000 | 0x0223) -#define NT_STATUS_PASSWORD_MUST_CHANGE (0xC0000000 | 0x0224) -#define NT_STATUS_NOT_FOUND (0xC0000000 | 0x0225) -#define NT_STATUS_NOT_TINY_STREAM (0xC0000000 | 0x0226) -#define NT_STATUS_RECOVERY_FAILURE (0xC0000000 | 0x0227) -#define NT_STATUS_STACK_OVERFLOW_READ (0xC0000000 | 0x0228) -#define NT_STATUS_FAIL_CHECK (0xC0000000 | 0x0229) -#define NT_STATUS_DUPLICATE_OBJECTID (0xC0000000 | 0x022a) -#define NT_STATUS_OBJECTID_EXISTS (0xC0000000 | 0x022b) -#define NT_STATUS_CONVERT_TO_LARGE (0xC0000000 | 0x022c) -#define NT_STATUS_RETRY (0xC0000000 | 0x022d) -#define NT_STATUS_FOUND_OUT_OF_SCOPE (0xC0000000 | 0x022e) -#define NT_STATUS_ALLOCATE_BUCKET (0xC0000000 | 0x022f) -#define NT_STATUS_PROPSET_NOT_FOUND (0xC0000000 | 0x0230) -#define NT_STATUS_MARSHALL_OVERFLOW (0xC0000000 | 0x0231) -#define NT_STATUS_INVALID_VARIANT (0xC0000000 | 0x0232) -#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND (0xC0000000 | 0x0233) -#define NT_STATUS_ACCOUNT_LOCKED_OUT (0xC0000000 | 0x0234) -#define NT_STATUS_HANDLE_NOT_CLOSABLE (0xC0000000 | 0x0235) -#define NT_STATUS_CONNECTION_REFUSED (0xC0000000 | 0x0236) -#define NT_STATUS_GRACEFUL_DISCONNECT (0xC0000000 | 0x0237) -#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED (0xC0000000 | 0x0238) -#define NT_STATUS_ADDRESS_NOT_ASSOCIATED (0xC0000000 | 0x0239) -#define NT_STATUS_CONNECTION_INVALID (0xC0000000 | 0x023a) -#define NT_STATUS_CONNECTION_ACTIVE (0xC0000000 | 0x023b) -#define NT_STATUS_NETWORK_UNREACHABLE (0xC0000000 | 0x023c) -#define NT_STATUS_HOST_UNREACHABLE (0xC0000000 | 0x023d) -#define NT_STATUS_PROTOCOL_UNREACHABLE (0xC0000000 | 0x023e) -#define NT_STATUS_PORT_UNREACHABLE (0xC0000000 | 0x023f) -#define NT_STATUS_REQUEST_ABORTED (0xC0000000 | 0x0240) -#define NT_STATUS_CONNECTION_ABORTED (0xC0000000 | 0x0241) -#define NT_STATUS_BAD_COMPRESSION_BUFFER (0xC0000000 | 0x0242) -#define NT_STATUS_USER_MAPPED_FILE (0xC0000000 | 0x0243) -#define NT_STATUS_AUDIT_FAILED (0xC0000000 | 0x0244) -#define NT_STATUS_TIMER_RESOLUTION_NOT_SET (0xC0000000 | 0x0245) -#define NT_STATUS_CONNECTION_COUNT_LIMIT (0xC0000000 | 0x0246) -#define NT_STATUS_LOGIN_TIME_RESTRICTION (0xC0000000 | 0x0247) -#define NT_STATUS_LOGIN_WKSTA_RESTRICTION (0xC0000000 | 0x0248) -#define NT_STATUS_IMAGE_MP_UP_MISMATCH (0xC0000000 | 0x0249) -#define NT_STATUS_INSUFFICIENT_LOGON_INFO (0xC0000000 | 0x0250) -#define NT_STATUS_BAD_DLL_ENTRYPOINT (0xC0000000 | 0x0251) -#define NT_STATUS_BAD_SERVICE_ENTRYPOINT (0xC0000000 | 0x0252) -#define NT_STATUS_LPC_REPLY_LOST (0xC0000000 | 0x0253) -#define NT_STATUS_IP_ADDRESS_CONFLICT1 (0xC0000000 | 0x0254) -#define NT_STATUS_IP_ADDRESS_CONFLICT2 (0xC0000000 | 0x0255) -#define NT_STATUS_REGISTRY_QUOTA_LIMIT (0xC0000000 | 0x0256) -#define NT_STATUS_PATH_NOT_COVERED (0xC0000000 | 0x0257) -#define NT_STATUS_NO_CALLBACK_ACTIVE (0xC0000000 | 0x0258) -#define NT_STATUS_LICENSE_QUOTA_EXCEEDED (0xC0000000 | 0x0259) -#define NT_STATUS_PWD_TOO_SHORT (0xC0000000 | 0x025a) -#define NT_STATUS_PWD_TOO_RECENT (0xC0000000 | 0x025b) -#define NT_STATUS_PWD_HISTORY_CONFLICT (0xC0000000 | 0x025c) -#define NT_STATUS_PLUGPLAY_NO_DEVICE (0xC0000000 | 0x025e) -#define NT_STATUS_UNSUPPORTED_COMPRESSION (0xC0000000 | 0x025f) -#define NT_STATUS_INVALID_HW_PROFILE (0xC0000000 | 0x0260) -#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH (0xC0000000 | 0x0261) -#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND (0xC0000000 | 0x0262) -#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND (0xC0000000 | 0x0263) -#define NT_STATUS_RESOURCE_NOT_OWNED (0xC0000000 | 0x0264) -#define NT_STATUS_TOO_MANY_LINKS (0xC0000000 | 0x0265) -#define NT_STATUS_QUOTA_LIST_INCONSISTENT (0xC0000000 | 0x0266) -#define NT_STATUS_FILE_IS_OFFLINE (0xC0000000 | 0x0267) -#define NT_STATUS_NETWORK_SESSION_EXPIRED (0xC0000000 | 0x035c) -#define NT_STATUS_NO_SUCH_JOB (0xC0000000 | 0xEDE) /* scheduler */ -#define NT_STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP (0xC0000000 | 0x5D0000) -#define NT_STATUS_PENDING 0x00000103 -#endif /* _NTERR_H */ diff --git a/fs/ksmbd/ntlmssp.h b/fs/ksmbd/ntlmssp.h deleted file mode 100644 index f13153c18b4e..000000000000 --- a/fs/ksmbd/ntlmssp.h +++ /dev/null @@ -1,169 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (c) International Business Machines Corp., 2002,2007 - * Author(s): Steve French (sfrench@us.ibm.com) - */ - -#ifndef __KSMBD_NTLMSSP_H -#define __KSMBD_NTLMSSP_H - -#define NTLMSSP_SIGNATURE "NTLMSSP" - -/* Security blob target info data */ -#define TGT_Name "KSMBD" - -/* - * Size of the crypto key returned on the negotiate SMB in bytes - */ -#define CIFS_CRYPTO_KEY_SIZE (8) -#define CIFS_KEY_SIZE (40) - -/* - * Size of encrypted user password in bytes - */ -#define CIFS_ENCPWD_SIZE (16) -#define CIFS_CPHTXT_SIZE (16) - -/* Message Types */ -#define NtLmNegotiate cpu_to_le32(1) -#define NtLmChallenge cpu_to_le32(2) -#define NtLmAuthenticate cpu_to_le32(3) -#define UnknownMessage cpu_to_le32(8) - -/* Negotiate Flags */ -#define NTLMSSP_NEGOTIATE_UNICODE 0x01 /* Text strings are unicode */ -#define NTLMSSP_NEGOTIATE_OEM 0x02 /* Text strings are in OEM */ -#define NTLMSSP_REQUEST_TARGET 0x04 /* Srv returns its auth realm */ -/* define reserved9 0x08 */ -#define NTLMSSP_NEGOTIATE_SIGN 0x0010 /* Request signing capability */ -#define NTLMSSP_NEGOTIATE_SEAL 0x0020 /* Request confidentiality */ -#define NTLMSSP_NEGOTIATE_DGRAM 0x0040 -#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 /* Use LM session key */ -/* defined reserved 8 0x0100 */ -#define NTLMSSP_NEGOTIATE_NTLM 0x0200 /* NTLM authentication */ -#define NTLMSSP_NEGOTIATE_NT_ONLY 0x0400 /* Lanman not allowed */ -#define NTLMSSP_ANONYMOUS 0x0800 -#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 /* reserved6 */ -#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 -#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 /* client/server same machine */ -#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 /* Sign. All security levels */ -#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 -#define NTLMSSP_TARGET_TYPE_SERVER 0x20000 -#define NTLMSSP_TARGET_TYPE_SHARE 0x40000 -#define NTLMSSP_NEGOTIATE_EXTENDED_SEC 0x80000 /* NB:not related to NTLMv2 pwd*/ -/* #define NTLMSSP_REQUEST_INIT_RESP 0x100000 */ -#define NTLMSSP_NEGOTIATE_IDENTIFY 0x100000 -#define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 /* reserved5 */ -#define NTLMSSP_REQUEST_NON_NT_KEY 0x400000 -#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 -/* #define reserved4 0x1000000 */ -#define NTLMSSP_NEGOTIATE_VERSION 0x2000000 /* we do not set */ -/* #define reserved3 0x4000000 */ -/* #define reserved2 0x8000000 */ -/* #define reserved1 0x10000000 */ -#define NTLMSSP_NEGOTIATE_128 0x20000000 -#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 -#define NTLMSSP_NEGOTIATE_56 0x80000000 - -/* Define AV Pair Field IDs */ -enum av_field_type { - NTLMSSP_AV_EOL = 0, - NTLMSSP_AV_NB_COMPUTER_NAME, - NTLMSSP_AV_NB_DOMAIN_NAME, - NTLMSSP_AV_DNS_COMPUTER_NAME, - NTLMSSP_AV_DNS_DOMAIN_NAME, - NTLMSSP_AV_DNS_TREE_NAME, - NTLMSSP_AV_FLAGS, - NTLMSSP_AV_TIMESTAMP, - NTLMSSP_AV_RESTRICTION, - NTLMSSP_AV_TARGET_NAME, - NTLMSSP_AV_CHANNEL_BINDINGS -}; - -/* Although typedefs are not commonly used for structure definitions */ -/* in the Linux kernel, in this particular case they are useful */ -/* to more closely match the standards document for NTLMSSP from */ -/* OpenGroup and to make the code more closely match the standard in */ -/* appearance */ - -struct security_buffer { - __le16 Length; - __le16 MaximumLength; - __le32 BufferOffset; /* offset to buffer */ -} __packed; - -struct target_info { - __le16 Type; - __le16 Length; - __u8 Content[]; -} __packed; - -struct negotiate_message { - __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; - __le32 MessageType; /* NtLmNegotiate = 1 */ - __le32 NegotiateFlags; - struct security_buffer DomainName; /* RFC 1001 style and ASCII */ - struct security_buffer WorkstationName; /* RFC 1001 and ASCII */ - /* - * struct security_buffer for version info not present since we - * do not set the version is present flag - */ - char DomainString[]; - /* followed by WorkstationString */ -} __packed; - -struct challenge_message { - __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; - __le32 MessageType; /* NtLmChallenge = 2 */ - struct security_buffer TargetName; - __le32 NegotiateFlags; - __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; - __u8 Reserved[8]; - struct security_buffer TargetInfoArray; - /* - * struct security_buffer for version info not present since we - * do not set the version is present flag - */ -} __packed; - -struct authenticate_message { - __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; - __le32 MessageType; /* NtLmsAuthenticate = 3 */ - struct security_buffer LmChallengeResponse; - struct security_buffer NtChallengeResponse; - struct security_buffer DomainName; - struct security_buffer UserName; - struct security_buffer WorkstationName; - struct security_buffer SessionKey; - __le32 NegotiateFlags; - /* - * struct security_buffer for version info not present since we - * do not set the version is present flag - */ - char UserString[]; -} __packed; - -struct ntlmv2_resp { - char ntlmv2_hash[CIFS_ENCPWD_SIZE]; - __le32 blob_signature; - __u32 reserved; - __le64 time; - __u64 client_chal; /* random */ - __u32 reserved2; - /* array of name entries could follow ending in minimum 4 byte struct */ -} __packed; - -/* per smb session structure/fields */ -struct ntlmssp_auth { - /* whether session key is per smb session */ - bool sesskey_per_smbsess; - /* sent by client in type 1 ntlmsssp exchange */ - __u32 client_flags; - /* sent by server in type 2 ntlmssp exchange */ - __u32 conn_flags; - /* sent to server */ - unsigned char ciphertext[CIFS_CPHTXT_SIZE]; - /* used by ntlmssp */ - char cryptkey[CIFS_CRYPTO_KEY_SIZE]; -}; -#endif /* __KSMBD_NTLMSSP_H */ diff --git a/fs/ksmbd/oplock.c b/fs/ksmbd/oplock.c deleted file mode 100644 index 4b210cdd7556..000000000000 --- a/fs/ksmbd/oplock.c +++ /dev/null @@ -1,1722 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/moduleparam.h> - -#include "glob.h" -#include "oplock.h" - -#include "smb_common.h" -#include "smbstatus.h" -#include "connection.h" -#include "mgmt/user_session.h" -#include "mgmt/share_config.h" -#include "mgmt/tree_connect.h" - -static LIST_HEAD(lease_table_list); -static DEFINE_RWLOCK(lease_list_lock); - -/** - * alloc_opinfo() - allocate a new opinfo object for oplock info - * @work: smb work - * @id: fid of open file - * @Tid: tree id of connection - * - * Return: allocated opinfo object on success, otherwise NULL - */ -static struct oplock_info *alloc_opinfo(struct ksmbd_work *work, - u64 id, __u16 Tid) -{ - struct ksmbd_conn *conn = work->conn; - struct ksmbd_session *sess = work->sess; - struct oplock_info *opinfo; - - opinfo = kzalloc(sizeof(struct oplock_info), GFP_KERNEL); - if (!opinfo) - return NULL; - - opinfo->sess = sess; - opinfo->conn = conn; - opinfo->level = SMB2_OPLOCK_LEVEL_NONE; - opinfo->op_state = OPLOCK_STATE_NONE; - opinfo->pending_break = 0; - opinfo->fid = id; - opinfo->Tid = Tid; - INIT_LIST_HEAD(&opinfo->op_entry); - INIT_LIST_HEAD(&opinfo->interim_list); - init_waitqueue_head(&opinfo->oplock_q); - init_waitqueue_head(&opinfo->oplock_brk); - atomic_set(&opinfo->refcount, 1); - atomic_set(&opinfo->breaking_cnt, 0); - - return opinfo; -} - -static void lease_add_list(struct oplock_info *opinfo) -{ - struct lease_table *lb = opinfo->o_lease->l_lb; - - spin_lock(&lb->lb_lock); - list_add_rcu(&opinfo->lease_entry, &lb->lease_list); - spin_unlock(&lb->lb_lock); -} - -static void lease_del_list(struct oplock_info *opinfo) -{ - struct lease_table *lb = opinfo->o_lease->l_lb; - - if (!lb) - return; - - spin_lock(&lb->lb_lock); - if (list_empty(&opinfo->lease_entry)) { - spin_unlock(&lb->lb_lock); - return; - } - - list_del_init(&opinfo->lease_entry); - opinfo->o_lease->l_lb = NULL; - spin_unlock(&lb->lb_lock); -} - -static void lb_add(struct lease_table *lb) -{ - write_lock(&lease_list_lock); - list_add(&lb->l_entry, &lease_table_list); - write_unlock(&lease_list_lock); -} - -static int alloc_lease(struct oplock_info *opinfo, struct lease_ctx_info *lctx) -{ - struct lease *lease; - - lease = kmalloc(sizeof(struct lease), GFP_KERNEL); - if (!lease) - return -ENOMEM; - - memcpy(lease->lease_key, lctx->lease_key, SMB2_LEASE_KEY_SIZE); - lease->state = lctx->req_state; - lease->new_state = 0; - lease->flags = lctx->flags; - lease->duration = lctx->duration; - memcpy(lease->parent_lease_key, lctx->parent_lease_key, SMB2_LEASE_KEY_SIZE); - lease->version = lctx->version; - lease->epoch = 0; - INIT_LIST_HEAD(&opinfo->lease_entry); - opinfo->o_lease = lease; - - return 0; -} - -static void free_lease(struct oplock_info *opinfo) -{ - struct lease *lease; - - lease = opinfo->o_lease; - kfree(lease); -} - -static void free_opinfo(struct oplock_info *opinfo) -{ - if (opinfo->is_lease) - free_lease(opinfo); - kfree(opinfo); -} - -static inline void opinfo_free_rcu(struct rcu_head *rcu_head) -{ - struct oplock_info *opinfo; - - opinfo = container_of(rcu_head, struct oplock_info, rcu_head); - free_opinfo(opinfo); -} - -struct oplock_info *opinfo_get(struct ksmbd_file *fp) -{ - struct oplock_info *opinfo; - - rcu_read_lock(); - opinfo = rcu_dereference(fp->f_opinfo); - if (opinfo && !atomic_inc_not_zero(&opinfo->refcount)) - opinfo = NULL; - rcu_read_unlock(); - - return opinfo; -} - -static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci) -{ - struct oplock_info *opinfo; - - if (list_empty(&ci->m_op_list)) - return NULL; - - rcu_read_lock(); - opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info, - op_entry); - if (opinfo) { - if (!atomic_inc_not_zero(&opinfo->refcount)) - opinfo = NULL; - else { - atomic_inc(&opinfo->conn->r_count); - if (ksmbd_conn_releasing(opinfo->conn)) { - atomic_dec(&opinfo->conn->r_count); - atomic_dec(&opinfo->refcount); - opinfo = NULL; - } - } - } - - rcu_read_unlock(); - - return opinfo; -} - -static void opinfo_conn_put(struct oplock_info *opinfo) -{ - struct ksmbd_conn *conn; - - if (!opinfo) - return; - - conn = opinfo->conn; - /* - * Checking waitqueue to dropping pending requests on - * disconnection. waitqueue_active is safe because it - * uses atomic operation for condition. - */ - if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) - wake_up(&conn->r_count_q); - opinfo_put(opinfo); -} - -void opinfo_put(struct oplock_info *opinfo) -{ - if (!atomic_dec_and_test(&opinfo->refcount)) - return; - - call_rcu(&opinfo->rcu_head, opinfo_free_rcu); -} - -static void opinfo_add(struct oplock_info *opinfo) -{ - struct ksmbd_inode *ci = opinfo->o_fp->f_ci; - - write_lock(&ci->m_lock); - list_add_rcu(&opinfo->op_entry, &ci->m_op_list); - write_unlock(&ci->m_lock); -} - -static void opinfo_del(struct oplock_info *opinfo) -{ - struct ksmbd_inode *ci = opinfo->o_fp->f_ci; - - if (opinfo->is_lease) { - write_lock(&lease_list_lock); - lease_del_list(opinfo); - write_unlock(&lease_list_lock); - } - write_lock(&ci->m_lock); - list_del_rcu(&opinfo->op_entry); - write_unlock(&ci->m_lock); -} - -static unsigned long opinfo_count(struct ksmbd_file *fp) -{ - if (ksmbd_stream_fd(fp)) - return atomic_read(&fp->f_ci->sop_count); - else - return atomic_read(&fp->f_ci->op_count); -} - -static void opinfo_count_inc(struct ksmbd_file *fp) -{ - if (ksmbd_stream_fd(fp)) - return atomic_inc(&fp->f_ci->sop_count); - else - return atomic_inc(&fp->f_ci->op_count); -} - -static void opinfo_count_dec(struct ksmbd_file *fp) -{ - if (ksmbd_stream_fd(fp)) - return atomic_dec(&fp->f_ci->sop_count); - else - return atomic_dec(&fp->f_ci->op_count); -} - -/** - * opinfo_write_to_read() - convert a write oplock to read oplock - * @opinfo: current oplock info - * - * Return: 0 on success, otherwise -EINVAL - */ -int opinfo_write_to_read(struct oplock_info *opinfo) -{ - struct lease *lease = opinfo->o_lease; - - if (!(opinfo->level == SMB2_OPLOCK_LEVEL_BATCH || - opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)) { - pr_err("bad oplock(0x%x)\n", opinfo->level); - if (opinfo->is_lease) - pr_err("lease state(0x%x)\n", lease->state); - return -EINVAL; - } - opinfo->level = SMB2_OPLOCK_LEVEL_II; - - if (opinfo->is_lease) - lease->state = lease->new_state; - return 0; -} - -/** - * opinfo_read_handle_to_read() - convert a read/handle oplock to read oplock - * @opinfo: current oplock info - * - * Return: 0 on success, otherwise -EINVAL - */ -int opinfo_read_handle_to_read(struct oplock_info *opinfo) -{ - struct lease *lease = opinfo->o_lease; - - lease->state = lease->new_state; - opinfo->level = SMB2_OPLOCK_LEVEL_II; - return 0; -} - -/** - * opinfo_write_to_none() - convert a write oplock to none - * @opinfo: current oplock info - * - * Return: 0 on success, otherwise -EINVAL - */ -int opinfo_write_to_none(struct oplock_info *opinfo) -{ - struct lease *lease = opinfo->o_lease; - - if (!(opinfo->level == SMB2_OPLOCK_LEVEL_BATCH || - opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)) { - pr_err("bad oplock(0x%x)\n", opinfo->level); - if (opinfo->is_lease) - pr_err("lease state(0x%x)\n", lease->state); - return -EINVAL; - } - opinfo->level = SMB2_OPLOCK_LEVEL_NONE; - if (opinfo->is_lease) - lease->state = lease->new_state; - return 0; -} - -/** - * opinfo_read_to_none() - convert a write read to none - * @opinfo: current oplock info - * - * Return: 0 on success, otherwise -EINVAL - */ -int opinfo_read_to_none(struct oplock_info *opinfo) -{ - struct lease *lease = opinfo->o_lease; - - if (opinfo->level != SMB2_OPLOCK_LEVEL_II) { - pr_err("bad oplock(0x%x)\n", opinfo->level); - if (opinfo->is_lease) - pr_err("lease state(0x%x)\n", lease->state); - return -EINVAL; - } - opinfo->level = SMB2_OPLOCK_LEVEL_NONE; - if (opinfo->is_lease) - lease->state = lease->new_state; - return 0; -} - -/** - * lease_read_to_write() - upgrade lease state from read to write - * @opinfo: current lease info - * - * Return: 0 on success, otherwise -EINVAL - */ -int lease_read_to_write(struct oplock_info *opinfo) -{ - struct lease *lease = opinfo->o_lease; - - if (!(lease->state & SMB2_LEASE_READ_CACHING_LE)) { - ksmbd_debug(OPLOCK, "bad lease state(0x%x)\n", lease->state); - return -EINVAL; - } - - lease->new_state = SMB2_LEASE_NONE_LE; - lease->state |= SMB2_LEASE_WRITE_CACHING_LE; - if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE) - opinfo->level = SMB2_OPLOCK_LEVEL_BATCH; - else - opinfo->level = SMB2_OPLOCK_LEVEL_EXCLUSIVE; - return 0; -} - -/** - * lease_none_upgrade() - upgrade lease state from none - * @opinfo: current lease info - * @new_state: new lease state - * - * Return: 0 on success, otherwise -EINVAL - */ -static int lease_none_upgrade(struct oplock_info *opinfo, __le32 new_state) -{ - struct lease *lease = opinfo->o_lease; - - if (!(lease->state == SMB2_LEASE_NONE_LE)) { - ksmbd_debug(OPLOCK, "bad lease state(0x%x)\n", lease->state); - return -EINVAL; - } - - lease->new_state = SMB2_LEASE_NONE_LE; - lease->state = new_state; - if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE) - if (lease->state & SMB2_LEASE_WRITE_CACHING_LE) - opinfo->level = SMB2_OPLOCK_LEVEL_BATCH; - else - opinfo->level = SMB2_OPLOCK_LEVEL_II; - else if (lease->state & SMB2_LEASE_WRITE_CACHING_LE) - opinfo->level = SMB2_OPLOCK_LEVEL_EXCLUSIVE; - else if (lease->state & SMB2_LEASE_READ_CACHING_LE) - opinfo->level = SMB2_OPLOCK_LEVEL_II; - - return 0; -} - -/** - * close_id_del_oplock() - release oplock object at file close time - * @fp: ksmbd file pointer - */ -void close_id_del_oplock(struct ksmbd_file *fp) -{ - struct oplock_info *opinfo; - - if (S_ISDIR(file_inode(fp->filp)->i_mode)) - return; - - opinfo = opinfo_get(fp); - if (!opinfo) - return; - - opinfo_del(opinfo); - - rcu_assign_pointer(fp->f_opinfo, NULL); - if (opinfo->op_state == OPLOCK_ACK_WAIT) { - opinfo->op_state = OPLOCK_CLOSING; - wake_up_interruptible_all(&opinfo->oplock_q); - if (opinfo->is_lease) { - atomic_set(&opinfo->breaking_cnt, 0); - wake_up_interruptible_all(&opinfo->oplock_brk); - } - } - - opinfo_count_dec(fp); - atomic_dec(&opinfo->refcount); - opinfo_put(opinfo); -} - -/** - * grant_write_oplock() - grant exclusive/batch oplock or write lease - * @opinfo_new: new oplock info object - * @req_oplock: request oplock - * @lctx: lease context information - * - * Return: 0 - */ -static void grant_write_oplock(struct oplock_info *opinfo_new, int req_oplock, - struct lease_ctx_info *lctx) -{ - struct lease *lease = opinfo_new->o_lease; - - if (req_oplock == SMB2_OPLOCK_LEVEL_BATCH) - opinfo_new->level = SMB2_OPLOCK_LEVEL_BATCH; - else - opinfo_new->level = SMB2_OPLOCK_LEVEL_EXCLUSIVE; - - if (lctx) { - lease->state = lctx->req_state; - memcpy(lease->lease_key, lctx->lease_key, SMB2_LEASE_KEY_SIZE); - } -} - -/** - * grant_read_oplock() - grant level2 oplock or read lease - * @opinfo_new: new oplock info object - * @lctx: lease context information - * - * Return: 0 - */ -static void grant_read_oplock(struct oplock_info *opinfo_new, - struct lease_ctx_info *lctx) -{ - struct lease *lease = opinfo_new->o_lease; - - opinfo_new->level = SMB2_OPLOCK_LEVEL_II; - - if (lctx) { - lease->state = SMB2_LEASE_READ_CACHING_LE; - if (lctx->req_state & SMB2_LEASE_HANDLE_CACHING_LE) - lease->state |= SMB2_LEASE_HANDLE_CACHING_LE; - memcpy(lease->lease_key, lctx->lease_key, SMB2_LEASE_KEY_SIZE); - } -} - -/** - * grant_none_oplock() - grant none oplock or none lease - * @opinfo_new: new oplock info object - * @lctx: lease context information - * - * Return: 0 - */ -static void grant_none_oplock(struct oplock_info *opinfo_new, - struct lease_ctx_info *lctx) -{ - struct lease *lease = opinfo_new->o_lease; - - opinfo_new->level = SMB2_OPLOCK_LEVEL_NONE; - - if (lctx) { - lease->state = 0; - memcpy(lease->lease_key, lctx->lease_key, SMB2_LEASE_KEY_SIZE); - } -} - -static inline int compare_guid_key(struct oplock_info *opinfo, - const char *guid1, const char *key1) -{ - const char *guid2, *key2; - - guid2 = opinfo->conn->ClientGUID; - key2 = opinfo->o_lease->lease_key; - if (!memcmp(guid1, guid2, SMB2_CLIENT_GUID_SIZE) && - !memcmp(key1, key2, SMB2_LEASE_KEY_SIZE)) - return 1; - - return 0; -} - -/** - * same_client_has_lease() - check whether current lease request is - * from lease owner of file - * @ci: master file pointer - * @client_guid: Client GUID - * @lctx: lease context information - * - * Return: oplock(lease) object on success, otherwise NULL - */ -static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci, - char *client_guid, - struct lease_ctx_info *lctx) -{ - int ret; - struct lease *lease; - struct oplock_info *opinfo; - struct oplock_info *m_opinfo = NULL; - - if (!lctx) - return NULL; - - /* - * Compare lease key and client_guid to know request from same owner - * of same client - */ - read_lock(&ci->m_lock); - list_for_each_entry(opinfo, &ci->m_op_list, op_entry) { - if (!opinfo->is_lease) - continue; - read_unlock(&ci->m_lock); - lease = opinfo->o_lease; - - ret = compare_guid_key(opinfo, client_guid, lctx->lease_key); - if (ret) { - m_opinfo = opinfo; - /* skip upgrading lease about breaking lease */ - if (atomic_read(&opinfo->breaking_cnt)) { - read_lock(&ci->m_lock); - continue; - } - - /* upgrading lease */ - if ((atomic_read(&ci->op_count) + - atomic_read(&ci->sop_count)) == 1) { - if (lease->state == - (lctx->req_state & lease->state)) { - lease->state |= lctx->req_state; - if (lctx->req_state & - SMB2_LEASE_WRITE_CACHING_LE) - lease_read_to_write(opinfo); - } - } else if ((atomic_read(&ci->op_count) + - atomic_read(&ci->sop_count)) > 1) { - if (lctx->req_state == - (SMB2_LEASE_READ_CACHING_LE | - SMB2_LEASE_HANDLE_CACHING_LE)) - lease->state = lctx->req_state; - } - - if (lctx->req_state && lease->state == - SMB2_LEASE_NONE_LE) - lease_none_upgrade(opinfo, lctx->req_state); - } - read_lock(&ci->m_lock); - } - read_unlock(&ci->m_lock); - - return m_opinfo; -} - -static void wait_for_break_ack(struct oplock_info *opinfo) -{ - int rc = 0; - - rc = wait_event_interruptible_timeout(opinfo->oplock_q, - opinfo->op_state == OPLOCK_STATE_NONE || - opinfo->op_state == OPLOCK_CLOSING, - OPLOCK_WAIT_TIME); - - /* is this a timeout ? */ - if (!rc) { - if (opinfo->is_lease) - opinfo->o_lease->state = SMB2_LEASE_NONE_LE; - opinfo->level = SMB2_OPLOCK_LEVEL_NONE; - opinfo->op_state = OPLOCK_STATE_NONE; - } -} - -static void wake_up_oplock_break(struct oplock_info *opinfo) -{ - clear_bit_unlock(0, &opinfo->pending_break); - /* memory barrier is needed for wake_up_bit() */ - smp_mb__after_atomic(); - wake_up_bit(&opinfo->pending_break, 0); -} - -static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level) -{ - while (test_and_set_bit(0, &opinfo->pending_break)) { - wait_on_bit(&opinfo->pending_break, 0, TASK_UNINTERRUPTIBLE); - - /* Not immediately break to none. */ - opinfo->open_trunc = 0; - - if (opinfo->op_state == OPLOCK_CLOSING) - return -ENOENT; - else if (!opinfo->is_lease && opinfo->level <= req_op_level) - return 1; - } - - if (!opinfo->is_lease && opinfo->level <= req_op_level) { - wake_up_oplock_break(opinfo); - return 1; - } - return 0; -} - -static inline int allocate_oplock_break_buf(struct ksmbd_work *work) -{ - work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL); - if (!work->response_buf) - return -ENOMEM; - work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE; - return 0; -} - -/** - * __smb2_oplock_break_noti() - send smb2 oplock break cmd from conn - * to client - * @wk: smb work object - * - * There are two ways this function can be called. 1- while file open we break - * from exclusive/batch lock to levelII oplock and 2- while file write/truncate - * we break from levelII oplock no oplock. - * work->request_buf contains oplock_info. - */ -static void __smb2_oplock_break_noti(struct work_struct *wk) -{ - struct smb2_oplock_break *rsp = NULL; - struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work); - struct ksmbd_conn *conn = work->conn; - struct oplock_break_info *br_info = work->request_buf; - struct smb2_hdr *rsp_hdr; - struct ksmbd_file *fp; - - fp = ksmbd_lookup_durable_fd(br_info->fid); - if (!fp) - goto out; - - if (allocate_oplock_break_buf(work)) { - pr_err("smb2_allocate_rsp_buf failed! "); - ksmbd_fd_put(work, fp); - goto out; - } - - rsp_hdr = smb2_get_msg(work->response_buf); - memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); - *(__be32 *)work->response_buf = - cpu_to_be32(conn->vals->header_size); - rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; - rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; - rsp_hdr->CreditRequest = cpu_to_le16(0); - rsp_hdr->Command = SMB2_OPLOCK_BREAK; - rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR); - rsp_hdr->NextCommand = 0; - rsp_hdr->MessageId = cpu_to_le64(-1); - rsp_hdr->Id.SyncId.ProcessId = 0; - rsp_hdr->Id.SyncId.TreeId = 0; - rsp_hdr->SessionId = 0; - memset(rsp_hdr->Signature, 0, 16); - - rsp = smb2_get_msg(work->response_buf); - - rsp->StructureSize = cpu_to_le16(24); - if (!br_info->open_trunc && - (br_info->level == SMB2_OPLOCK_LEVEL_BATCH || - br_info->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)) - rsp->OplockLevel = SMB2_OPLOCK_LEVEL_II; - else - rsp->OplockLevel = SMB2_OPLOCK_LEVEL_NONE; - rsp->Reserved = 0; - rsp->Reserved2 = 0; - rsp->PersistentFid = fp->persistent_id; - rsp->VolatileFid = fp->volatile_id; - - inc_rfc1001_len(work->response_buf, 24); - - ksmbd_debug(OPLOCK, - "sending oplock break v_id %llu p_id = %llu lock level = %d\n", - rsp->VolatileFid, rsp->PersistentFid, rsp->OplockLevel); - - ksmbd_fd_put(work, fp); - ksmbd_conn_write(work); - -out: - ksmbd_free_work_struct(work); -} - -/** - * smb2_oplock_break_noti() - send smb2 exclusive/batch to level2 oplock - * break command from server to client - * @opinfo: oplock info object - * - * Return: 0 on success, otherwise error - */ -static int smb2_oplock_break_noti(struct oplock_info *opinfo) -{ - struct ksmbd_conn *conn = opinfo->conn; - struct oplock_break_info *br_info; - int ret = 0; - struct ksmbd_work *work = ksmbd_alloc_work_struct(); - - if (!work) - return -ENOMEM; - - br_info = kmalloc(sizeof(struct oplock_break_info), GFP_KERNEL); - if (!br_info) { - ksmbd_free_work_struct(work); - return -ENOMEM; - } - - br_info->level = opinfo->level; - br_info->fid = opinfo->fid; - br_info->open_trunc = opinfo->open_trunc; - - work->request_buf = (char *)br_info; - work->conn = conn; - work->sess = opinfo->sess; - - if (opinfo->op_state == OPLOCK_ACK_WAIT) { - INIT_WORK(&work->work, __smb2_oplock_break_noti); - ksmbd_queue_work(work); - - wait_for_break_ack(opinfo); - } else { - __smb2_oplock_break_noti(&work->work); - if (opinfo->level == SMB2_OPLOCK_LEVEL_II) - opinfo->level = SMB2_OPLOCK_LEVEL_NONE; - } - return ret; -} - -/** - * __smb2_lease_break_noti() - send lease break command from server - * to client - * @wk: smb work object - */ -static void __smb2_lease_break_noti(struct work_struct *wk) -{ - struct smb2_lease_break *rsp = NULL; - struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work); - struct lease_break_info *br_info = work->request_buf; - struct ksmbd_conn *conn = work->conn; - struct smb2_hdr *rsp_hdr; - - if (allocate_oplock_break_buf(work)) { - ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! "); - goto out; - } - - rsp_hdr = smb2_get_msg(work->response_buf); - memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); - *(__be32 *)work->response_buf = - cpu_to_be32(conn->vals->header_size); - rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; - rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; - rsp_hdr->CreditRequest = cpu_to_le16(0); - rsp_hdr->Command = SMB2_OPLOCK_BREAK; - rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR); - rsp_hdr->NextCommand = 0; - rsp_hdr->MessageId = cpu_to_le64(-1); - rsp_hdr->Id.SyncId.ProcessId = 0; - rsp_hdr->Id.SyncId.TreeId = 0; - rsp_hdr->SessionId = 0; - memset(rsp_hdr->Signature, 0, 16); - - rsp = smb2_get_msg(work->response_buf); - rsp->StructureSize = cpu_to_le16(44); - rsp->Epoch = br_info->epoch; - rsp->Flags = 0; - - if (br_info->curr_state & (SMB2_LEASE_WRITE_CACHING_LE | - SMB2_LEASE_HANDLE_CACHING_LE)) - rsp->Flags = SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED; - - memcpy(rsp->LeaseKey, br_info->lease_key, SMB2_LEASE_KEY_SIZE); - rsp->CurrentLeaseState = br_info->curr_state; - rsp->NewLeaseState = br_info->new_state; - rsp->BreakReason = 0; - rsp->AccessMaskHint = 0; - rsp->ShareMaskHint = 0; - - inc_rfc1001_len(work->response_buf, 44); - - ksmbd_conn_write(work); - -out: - ksmbd_free_work_struct(work); -} - -/** - * smb2_lease_break_noti() - break lease when a new client request - * write lease - * @opinfo: conains lease state information - * - * Return: 0 on success, otherwise error - */ -static int smb2_lease_break_noti(struct oplock_info *opinfo) -{ - struct ksmbd_conn *conn = opinfo->conn; - struct list_head *tmp, *t; - struct ksmbd_work *work; - struct lease_break_info *br_info; - struct lease *lease = opinfo->o_lease; - - work = ksmbd_alloc_work_struct(); - if (!work) - return -ENOMEM; - - br_info = kmalloc(sizeof(struct lease_break_info), GFP_KERNEL); - if (!br_info) { - ksmbd_free_work_struct(work); - return -ENOMEM; - } - - br_info->curr_state = lease->state; - br_info->new_state = lease->new_state; - if (lease->version == 2) - br_info->epoch = cpu_to_le16(++lease->epoch); - else - br_info->epoch = 0; - memcpy(br_info->lease_key, lease->lease_key, SMB2_LEASE_KEY_SIZE); - - work->request_buf = (char *)br_info; - work->conn = conn; - work->sess = opinfo->sess; - - if (opinfo->op_state == OPLOCK_ACK_WAIT) { - list_for_each_safe(tmp, t, &opinfo->interim_list) { - struct ksmbd_work *in_work; - - in_work = list_entry(tmp, struct ksmbd_work, - interim_entry); - setup_async_work(in_work, NULL, NULL); - smb2_send_interim_resp(in_work, STATUS_PENDING); - list_del(&in_work->interim_entry); - } - INIT_WORK(&work->work, __smb2_lease_break_noti); - ksmbd_queue_work(work); - wait_for_break_ack(opinfo); - } else { - __smb2_lease_break_noti(&work->work); - if (opinfo->o_lease->new_state == SMB2_LEASE_NONE_LE) { - opinfo->level = SMB2_OPLOCK_LEVEL_NONE; - opinfo->o_lease->state = SMB2_LEASE_NONE_LE; - } - } - return 0; -} - -static void wait_lease_breaking(struct oplock_info *opinfo) -{ - if (!opinfo->is_lease) - return; - - wake_up_interruptible_all(&opinfo->oplock_brk); - if (atomic_read(&opinfo->breaking_cnt)) { - int ret = 0; - - ret = wait_event_interruptible_timeout(opinfo->oplock_brk, - atomic_read(&opinfo->breaking_cnt) == 0, - HZ); - if (!ret) - atomic_set(&opinfo->breaking_cnt, 0); - } -} - -static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level) -{ - int err = 0; - - /* Need to break exclusive/batch oplock, write lease or overwrite_if */ - ksmbd_debug(OPLOCK, - "request to send oplock(level : 0x%x) break notification\n", - brk_opinfo->level); - - if (brk_opinfo->is_lease) { - struct lease *lease = brk_opinfo->o_lease; - - atomic_inc(&brk_opinfo->breaking_cnt); - - err = oplock_break_pending(brk_opinfo, req_op_level); - if (err) - return err < 0 ? err : 0; - - if (brk_opinfo->open_trunc) { - /* - * Create overwrite break trigger the lease break to - * none. - */ - lease->new_state = SMB2_LEASE_NONE_LE; - } else { - if (lease->state & SMB2_LEASE_WRITE_CACHING_LE) { - if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE) - lease->new_state = - SMB2_LEASE_READ_CACHING_LE | - SMB2_LEASE_HANDLE_CACHING_LE; - else - lease->new_state = - SMB2_LEASE_READ_CACHING_LE; - } else { - if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE) - lease->new_state = - SMB2_LEASE_READ_CACHING_LE; - else - lease->new_state = SMB2_LEASE_NONE_LE; - } - } - - if (lease->state & (SMB2_LEASE_WRITE_CACHING_LE | - SMB2_LEASE_HANDLE_CACHING_LE)) - brk_opinfo->op_state = OPLOCK_ACK_WAIT; - else - atomic_dec(&brk_opinfo->breaking_cnt); - } else { - err = oplock_break_pending(brk_opinfo, req_op_level); - if (err) - return err < 0 ? err : 0; - - if (brk_opinfo->level == SMB2_OPLOCK_LEVEL_BATCH || - brk_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) - brk_opinfo->op_state = OPLOCK_ACK_WAIT; - } - - if (brk_opinfo->is_lease) - err = smb2_lease_break_noti(brk_opinfo); - else - err = smb2_oplock_break_noti(brk_opinfo); - - ksmbd_debug(OPLOCK, "oplock granted = %d\n", brk_opinfo->level); - if (brk_opinfo->op_state == OPLOCK_CLOSING) - err = -ENOENT; - wake_up_oplock_break(brk_opinfo); - - wait_lease_breaking(brk_opinfo); - - return err; -} - -void destroy_lease_table(struct ksmbd_conn *conn) -{ - struct lease_table *lb, *lbtmp; - struct oplock_info *opinfo; - - write_lock(&lease_list_lock); - if (list_empty(&lease_table_list)) { - write_unlock(&lease_list_lock); - return; - } - - list_for_each_entry_safe(lb, lbtmp, &lease_table_list, l_entry) { - if (conn && memcmp(lb->client_guid, conn->ClientGUID, - SMB2_CLIENT_GUID_SIZE)) - continue; -again: - rcu_read_lock(); - list_for_each_entry_rcu(opinfo, &lb->lease_list, - lease_entry) { - rcu_read_unlock(); - lease_del_list(opinfo); - goto again; - } - rcu_read_unlock(); - list_del(&lb->l_entry); - kfree(lb); - } - write_unlock(&lease_list_lock); -} - -int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci, - struct lease_ctx_info *lctx) -{ - struct oplock_info *opinfo; - int err = 0; - struct lease_table *lb; - - if (!lctx) - return err; - - read_lock(&lease_list_lock); - if (list_empty(&lease_table_list)) { - read_unlock(&lease_list_lock); - return 0; - } - - list_for_each_entry(lb, &lease_table_list, l_entry) { - if (!memcmp(lb->client_guid, sess->ClientGUID, - SMB2_CLIENT_GUID_SIZE)) - goto found; - } - read_unlock(&lease_list_lock); - - return 0; - -found: - rcu_read_lock(); - list_for_each_entry_rcu(opinfo, &lb->lease_list, lease_entry) { - if (!atomic_inc_not_zero(&opinfo->refcount)) - continue; - rcu_read_unlock(); - if (opinfo->o_fp->f_ci == ci) - goto op_next; - err = compare_guid_key(opinfo, sess->ClientGUID, - lctx->lease_key); - if (err) { - err = -EINVAL; - ksmbd_debug(OPLOCK, - "found same lease key is already used in other files\n"); - opinfo_put(opinfo); - goto out; - } -op_next: - opinfo_put(opinfo); - rcu_read_lock(); - } - rcu_read_unlock(); - -out: - read_unlock(&lease_list_lock); - return err; -} - -static void copy_lease(struct oplock_info *op1, struct oplock_info *op2) -{ - struct lease *lease1 = op1->o_lease; - struct lease *lease2 = op2->o_lease; - - op2->level = op1->level; - lease2->state = lease1->state; - memcpy(lease2->lease_key, lease1->lease_key, - SMB2_LEASE_KEY_SIZE); - lease2->duration = lease1->duration; - lease2->flags = lease1->flags; -} - -static int add_lease_global_list(struct oplock_info *opinfo) -{ - struct lease_table *lb; - - read_lock(&lease_list_lock); - list_for_each_entry(lb, &lease_table_list, l_entry) { - if (!memcmp(lb->client_guid, opinfo->conn->ClientGUID, - SMB2_CLIENT_GUID_SIZE)) { - opinfo->o_lease->l_lb = lb; - lease_add_list(opinfo); - read_unlock(&lease_list_lock); - return 0; - } - } - read_unlock(&lease_list_lock); - - lb = kmalloc(sizeof(struct lease_table), GFP_KERNEL); - if (!lb) - return -ENOMEM; - - memcpy(lb->client_guid, opinfo->conn->ClientGUID, - SMB2_CLIENT_GUID_SIZE); - INIT_LIST_HEAD(&lb->lease_list); - spin_lock_init(&lb->lb_lock); - opinfo->o_lease->l_lb = lb; - lease_add_list(opinfo); - lb_add(lb); - return 0; -} - -static void set_oplock_level(struct oplock_info *opinfo, int level, - struct lease_ctx_info *lctx) -{ - switch (level) { - case SMB2_OPLOCK_LEVEL_BATCH: - case SMB2_OPLOCK_LEVEL_EXCLUSIVE: - grant_write_oplock(opinfo, level, lctx); - break; - case SMB2_OPLOCK_LEVEL_II: - grant_read_oplock(opinfo, lctx); - break; - default: - grant_none_oplock(opinfo, lctx); - break; - } -} - -/** - * smb_grant_oplock() - handle oplock/lease request on file open - * @work: smb work - * @req_op_level: oplock level - * @pid: id of open file - * @fp: ksmbd file pointer - * @tid: Tree id of connection - * @lctx: lease context information on file open - * @share_ret: share mode - * - * Return: 0 on success, otherwise error - */ -int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid, - struct ksmbd_file *fp, __u16 tid, - struct lease_ctx_info *lctx, int share_ret) -{ - struct ksmbd_session *sess = work->sess; - int err = 0; - struct oplock_info *opinfo = NULL, *prev_opinfo = NULL; - struct ksmbd_inode *ci = fp->f_ci; - bool prev_op_has_lease; - __le32 prev_op_state = 0; - - /* not support directory lease */ - if (S_ISDIR(file_inode(fp->filp)->i_mode)) - return 0; - - opinfo = alloc_opinfo(work, pid, tid); - if (!opinfo) - return -ENOMEM; - - if (lctx) { - err = alloc_lease(opinfo, lctx); - if (err) - goto err_out; - opinfo->is_lease = 1; - } - - /* ci does not have any oplock */ - if (!opinfo_count(fp)) - goto set_lev; - - /* grant none-oplock if second open is trunc */ - if (fp->attrib_only && fp->cdoption != FILE_OVERWRITE_IF_LE && - fp->cdoption != FILE_OVERWRITE_LE && - fp->cdoption != FILE_SUPERSEDE_LE) { - req_op_level = SMB2_OPLOCK_LEVEL_NONE; - goto set_lev; - } - - if (lctx) { - struct oplock_info *m_opinfo; - - /* is lease already granted ? */ - m_opinfo = same_client_has_lease(ci, sess->ClientGUID, - lctx); - if (m_opinfo) { - copy_lease(m_opinfo, opinfo); - if (atomic_read(&m_opinfo->breaking_cnt)) - opinfo->o_lease->flags = - SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE; - goto out; - } - } - prev_opinfo = opinfo_get_list(ci); - if (!prev_opinfo || - (prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) { - opinfo_conn_put(prev_opinfo); - goto set_lev; - } - prev_op_has_lease = prev_opinfo->is_lease; - if (prev_op_has_lease) - prev_op_state = prev_opinfo->o_lease->state; - - if (share_ret < 0 && - prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) { - err = share_ret; - opinfo_conn_put(prev_opinfo); - goto err_out; - } - - if (prev_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH && - prev_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) { - opinfo_conn_put(prev_opinfo); - goto op_break_not_needed; - } - - list_add(&work->interim_entry, &prev_opinfo->interim_list); - err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II); - opinfo_conn_put(prev_opinfo); - if (err == -ENOENT) - goto set_lev; - /* Check all oplock was freed by close */ - else if (err < 0) - goto err_out; - -op_break_not_needed: - if (share_ret < 0) { - err = share_ret; - goto err_out; - } - - if (req_op_level != SMB2_OPLOCK_LEVEL_NONE) - req_op_level = SMB2_OPLOCK_LEVEL_II; - - /* grant fixed oplock on stacked locking between lease and oplock */ - if (prev_op_has_lease && !lctx) - if (prev_op_state & SMB2_LEASE_HANDLE_CACHING_LE) - req_op_level = SMB2_OPLOCK_LEVEL_NONE; - - if (!prev_op_has_lease && lctx) { - req_op_level = SMB2_OPLOCK_LEVEL_II; - lctx->req_state = SMB2_LEASE_READ_CACHING_LE; - } - -set_lev: - set_oplock_level(opinfo, req_op_level, lctx); - -out: - rcu_assign_pointer(fp->f_opinfo, opinfo); - opinfo->o_fp = fp; - - opinfo_count_inc(fp); - opinfo_add(opinfo); - if (opinfo->is_lease) { - err = add_lease_global_list(opinfo); - if (err) - goto err_out; - } - - return 0; -err_out: - free_opinfo(opinfo); - return err; -} - -/** - * smb_break_all_write_oplock() - break batch/exclusive oplock to level2 - * @work: smb work - * @fp: ksmbd file pointer - * @is_trunc: truncate on open - */ -static void smb_break_all_write_oplock(struct ksmbd_work *work, - struct ksmbd_file *fp, int is_trunc) -{ - struct oplock_info *brk_opinfo; - - brk_opinfo = opinfo_get_list(fp->f_ci); - if (!brk_opinfo) - return; - if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH && - brk_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) { - opinfo_conn_put(brk_opinfo); - return; - } - - brk_opinfo->open_trunc = is_trunc; - list_add(&work->interim_entry, &brk_opinfo->interim_list); - oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II); - opinfo_conn_put(brk_opinfo); -} - -/** - * smb_break_all_levII_oplock() - send level2 oplock or read lease break command - * from server to client - * @work: smb work - * @fp: ksmbd file pointer - * @is_trunc: truncate on open - */ -void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp, - int is_trunc) -{ - struct oplock_info *op, *brk_op; - struct ksmbd_inode *ci; - struct ksmbd_conn *conn = work->conn; - - if (!test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_OPLOCKS)) - return; - - ci = fp->f_ci; - op = opinfo_get(fp); - - rcu_read_lock(); - list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) { - if (!atomic_inc_not_zero(&brk_op->refcount)) - continue; - - atomic_inc(&brk_op->conn->r_count); - if (ksmbd_conn_releasing(brk_op->conn)) { - atomic_dec(&brk_op->conn->r_count); - continue; - } - - rcu_read_unlock(); - if (brk_op->is_lease && (brk_op->o_lease->state & - (~(SMB2_LEASE_READ_CACHING_LE | - SMB2_LEASE_HANDLE_CACHING_LE)))) { - ksmbd_debug(OPLOCK, "unexpected lease state(0x%x)\n", - brk_op->o_lease->state); - goto next; - } else if (brk_op->level != - SMB2_OPLOCK_LEVEL_II) { - ksmbd_debug(OPLOCK, "unexpected oplock(0x%x)\n", - brk_op->level); - goto next; - } - - /* Skip oplock being break to none */ - if (brk_op->is_lease && - brk_op->o_lease->new_state == SMB2_LEASE_NONE_LE && - atomic_read(&brk_op->breaking_cnt)) - goto next; - - if (op && op->is_lease && brk_op->is_lease && - !memcmp(conn->ClientGUID, brk_op->conn->ClientGUID, - SMB2_CLIENT_GUID_SIZE) && - !memcmp(op->o_lease->lease_key, brk_op->o_lease->lease_key, - SMB2_LEASE_KEY_SIZE)) - goto next; - brk_op->open_trunc = is_trunc; - oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE); -next: - opinfo_conn_put(brk_op); - rcu_read_lock(); - } - rcu_read_unlock(); - - if (op) - opinfo_put(op); -} - -/** - * smb_break_all_oplock() - break both batch/exclusive and level2 oplock - * @work: smb work - * @fp: ksmbd file pointer - */ -void smb_break_all_oplock(struct ksmbd_work *work, struct ksmbd_file *fp) -{ - if (!test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_OPLOCKS)) - return; - - smb_break_all_write_oplock(work, fp, 1); - smb_break_all_levII_oplock(work, fp, 1); -} - -/** - * smb2_map_lease_to_oplock() - map lease state to corresponding oplock type - * @lease_state: lease type - * - * Return: 0 if no mapping, otherwise corresponding oplock type - */ -__u8 smb2_map_lease_to_oplock(__le32 lease_state) -{ - if (lease_state == (SMB2_LEASE_HANDLE_CACHING_LE | - SMB2_LEASE_READ_CACHING_LE | - SMB2_LEASE_WRITE_CACHING_LE)) { - return SMB2_OPLOCK_LEVEL_BATCH; - } else if (lease_state != SMB2_LEASE_WRITE_CACHING_LE && - lease_state & SMB2_LEASE_WRITE_CACHING_LE) { - if (!(lease_state & SMB2_LEASE_HANDLE_CACHING_LE)) - return SMB2_OPLOCK_LEVEL_EXCLUSIVE; - } else if (lease_state & SMB2_LEASE_READ_CACHING_LE) { - return SMB2_OPLOCK_LEVEL_II; - } - return 0; -} - -/** - * create_lease_buf() - create lease context for open cmd response - * @rbuf: buffer to create lease context response - * @lease: buffer to stored parsed lease state information - */ -void create_lease_buf(u8 *rbuf, struct lease *lease) -{ - if (lease->version == 2) { - struct create_lease_v2 *buf = (struct create_lease_v2 *)rbuf; - - memset(buf, 0, sizeof(struct create_lease_v2)); - memcpy(buf->lcontext.LeaseKey, lease->lease_key, - SMB2_LEASE_KEY_SIZE); - buf->lcontext.LeaseFlags = lease->flags; - buf->lcontext.LeaseState = lease->state; - memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key, - SMB2_LEASE_KEY_SIZE); - buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_lease_v2, lcontext)); - buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context_v2)); - buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_lease_v2, Name)); - buf->ccontext.NameLength = cpu_to_le16(4); - buf->Name[0] = 'R'; - buf->Name[1] = 'q'; - buf->Name[2] = 'L'; - buf->Name[3] = 's'; - } else { - struct create_lease *buf = (struct create_lease *)rbuf; - - memset(buf, 0, sizeof(struct create_lease)); - memcpy(buf->lcontext.LeaseKey, lease->lease_key, SMB2_LEASE_KEY_SIZE); - buf->lcontext.LeaseFlags = lease->flags; - buf->lcontext.LeaseState = lease->state; - buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_lease, lcontext)); - buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context)); - buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_lease, Name)); - buf->ccontext.NameLength = cpu_to_le16(4); - buf->Name[0] = 'R'; - buf->Name[1] = 'q'; - buf->Name[2] = 'L'; - buf->Name[3] = 's'; - } -} - -/** - * parse_lease_state() - parse lease context containted in file open request - * @open_req: buffer containing smb2 file open(create) request - * - * Return: oplock state, -ENOENT if create lease context not found - */ -struct lease_ctx_info *parse_lease_state(void *open_req) -{ - struct create_context *cc; - struct smb2_create_req *req = (struct smb2_create_req *)open_req; - struct lease_ctx_info *lreq; - - cc = smb2_find_context_vals(req, SMB2_CREATE_REQUEST_LEASE, 4); - if (IS_ERR_OR_NULL(cc)) - return NULL; - - lreq = kzalloc(sizeof(struct lease_ctx_info), GFP_KERNEL); - if (!lreq) - return NULL; - - if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) { - struct create_lease_v2 *lc = (struct create_lease_v2 *)cc; - - memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); - lreq->req_state = lc->lcontext.LeaseState; - lreq->flags = lc->lcontext.LeaseFlags; - lreq->duration = lc->lcontext.LeaseDuration; - memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey, - SMB2_LEASE_KEY_SIZE); - lreq->version = 2; - } else { - struct create_lease *lc = (struct create_lease *)cc; - - memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); - lreq->req_state = lc->lcontext.LeaseState; - lreq->flags = lc->lcontext.LeaseFlags; - lreq->duration = lc->lcontext.LeaseDuration; - lreq->version = 1; - } - return lreq; -} - -/** - * smb2_find_context_vals() - find a particular context info in open request - * @open_req: buffer containing smb2 file open(create) request - * @tag: context name to search for - * @tag_len: the length of tag - * - * Return: pointer to requested context, NULL if @str context not found - * or error pointer if name length is invalid. - */ -struct create_context *smb2_find_context_vals(void *open_req, const char *tag, int tag_len) -{ - struct create_context *cc; - unsigned int next = 0; - char *name; - struct smb2_create_req *req = (struct smb2_create_req *)open_req; - unsigned int remain_len, name_off, name_len, value_off, value_len, - cc_len; - - /* - * CreateContextsOffset and CreateContextsLength are guaranteed to - * be valid because of ksmbd_smb2_check_message(). - */ - cc = (struct create_context *)((char *)req + - le32_to_cpu(req->CreateContextsOffset)); - remain_len = le32_to_cpu(req->CreateContextsLength); - do { - cc = (struct create_context *)((char *)cc + next); - if (remain_len < offsetof(struct create_context, Buffer)) - return ERR_PTR(-EINVAL); - - next = le32_to_cpu(cc->Next); - name_off = le16_to_cpu(cc->NameOffset); - name_len = le16_to_cpu(cc->NameLength); - value_off = le16_to_cpu(cc->DataOffset); - value_len = le32_to_cpu(cc->DataLength); - cc_len = next ? next : remain_len; - - if ((next & 0x7) != 0 || - next > remain_len || - name_off != offsetof(struct create_context, Buffer) || - name_len < 4 || - name_off + name_len > cc_len || - (value_off & 0x7) != 0 || - (value_off && (value_off < name_off + name_len)) || - ((u64)value_off + value_len > cc_len)) - return ERR_PTR(-EINVAL); - - name = (char *)cc + name_off; - if (name_len == tag_len && !memcmp(name, tag, name_len)) - return cc; - - remain_len -= next; - } while (next != 0); - - return NULL; -} - -/** - * create_durable_rsp_buf() - create durable handle context - * @cc: buffer to create durable context response - */ -void create_durable_rsp_buf(char *cc) -{ - struct create_durable_rsp *buf; - - buf = (struct create_durable_rsp *)cc; - memset(buf, 0, sizeof(struct create_durable_rsp)); - buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_durable_rsp, Data)); - buf->ccontext.DataLength = cpu_to_le32(8); - buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_durable_rsp, Name)); - buf->ccontext.NameLength = cpu_to_le16(4); - /* SMB2_CREATE_DURABLE_HANDLE_RESPONSE is "DHnQ" */ - buf->Name[0] = 'D'; - buf->Name[1] = 'H'; - buf->Name[2] = 'n'; - buf->Name[3] = 'Q'; -} - -/** - * create_durable_v2_rsp_buf() - create durable handle v2 context - * @cc: buffer to create durable context response - * @fp: ksmbd file pointer - */ -void create_durable_v2_rsp_buf(char *cc, struct ksmbd_file *fp) -{ - struct create_durable_v2_rsp *buf; - - buf = (struct create_durable_v2_rsp *)cc; - memset(buf, 0, sizeof(struct create_durable_rsp)); - buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_durable_rsp, Data)); - buf->ccontext.DataLength = cpu_to_le32(8); - buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_durable_rsp, Name)); - buf->ccontext.NameLength = cpu_to_le16(4); - /* SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2 is "DH2Q" */ - buf->Name[0] = 'D'; - buf->Name[1] = 'H'; - buf->Name[2] = '2'; - buf->Name[3] = 'Q'; - - buf->Timeout = cpu_to_le32(fp->durable_timeout); -} - -/** - * create_mxac_rsp_buf() - create query maximal access context - * @cc: buffer to create maximal access context response - * @maximal_access: maximal access - */ -void create_mxac_rsp_buf(char *cc, int maximal_access) -{ - struct create_mxac_rsp *buf; - - buf = (struct create_mxac_rsp *)cc; - memset(buf, 0, sizeof(struct create_mxac_rsp)); - buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_mxac_rsp, QueryStatus)); - buf->ccontext.DataLength = cpu_to_le32(8); - buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_mxac_rsp, Name)); - buf->ccontext.NameLength = cpu_to_le16(4); - /* SMB2_CREATE_QUERY_MAXIMAL_ACCESS_RESPONSE is "MxAc" */ - buf->Name[0] = 'M'; - buf->Name[1] = 'x'; - buf->Name[2] = 'A'; - buf->Name[3] = 'c'; - - buf->QueryStatus = STATUS_SUCCESS; - buf->MaximalAccess = cpu_to_le32(maximal_access); -} - -void create_disk_id_rsp_buf(char *cc, __u64 file_id, __u64 vol_id) -{ - struct create_disk_id_rsp *buf; - - buf = (struct create_disk_id_rsp *)cc; - memset(buf, 0, sizeof(struct create_disk_id_rsp)); - buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_disk_id_rsp, DiskFileId)); - buf->ccontext.DataLength = cpu_to_le32(32); - buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_mxac_rsp, Name)); - buf->ccontext.NameLength = cpu_to_le16(4); - /* SMB2_CREATE_QUERY_ON_DISK_ID_RESPONSE is "QFid" */ - buf->Name[0] = 'Q'; - buf->Name[1] = 'F'; - buf->Name[2] = 'i'; - buf->Name[3] = 'd'; - - buf->DiskFileId = cpu_to_le64(file_id); - buf->VolumeId = cpu_to_le64(vol_id); -} - -/** - * create_posix_rsp_buf() - create posix extension context - * @cc: buffer to create posix on posix response - * @fp: ksmbd file pointer - */ -void create_posix_rsp_buf(char *cc, struct ksmbd_file *fp) -{ - struct create_posix_rsp *buf; - 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); - - buf = (struct create_posix_rsp *)cc; - memset(buf, 0, sizeof(struct create_posix_rsp)); - buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_posix_rsp, nlink)); - /* - * 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 - (struct create_posix_rsp, Name)); - buf->ccontext.NameLength = cpu_to_le16(POSIX_CTXT_DATA_LEN); - /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */ - buf->Name[0] = 0x93; - buf->Name[1] = 0xAD; - buf->Name[2] = 0x25; - buf->Name[3] = 0x50; - buf->Name[4] = 0x9C; - buf->Name[5] = 0xB4; - buf->Name[6] = 0x11; - buf->Name[7] = 0xE7; - buf->Name[8] = 0xB4; - buf->Name[9] = 0x23; - buf->Name[10] = 0x83; - buf->Name[11] = 0xDE; - buf->Name[12] = 0x96; - buf->Name[13] = 0x8B; - buf->Name[14] = 0xCD; - buf->Name[15] = 0x7C; - - buf->nlink = cpu_to_le32(inode->i_nlink); - buf->reparse_tag = cpu_to_le32(fp->volatile_id); - buf->mode = cpu_to_le32(inode->i_mode & 0777); - /* - * SidBuffer(44) contain two sids(Domain sid(28), UNIX group sid(16)). - * Domain sid(28) = revision(1) + num_subauth(1) + authority(6) + - * sub_auth(4 * 4(num_subauth)) + RID(4). - * UNIX group id(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)), - 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]); -} - -/* - * Find lease object(opinfo) for given lease key/fid from lease - * break/file close path. - */ -/** - * lookup_lease_in_table() - find a matching lease info object - * @conn: connection instance - * @lease_key: lease key to be searched for - * - * Return: opinfo if found matching opinfo, otherwise NULL - */ -struct oplock_info *lookup_lease_in_table(struct ksmbd_conn *conn, - char *lease_key) -{ - struct oplock_info *opinfo = NULL, *ret_op = NULL; - struct lease_table *lt; - int ret; - - read_lock(&lease_list_lock); - list_for_each_entry(lt, &lease_table_list, l_entry) { - if (!memcmp(lt->client_guid, conn->ClientGUID, - SMB2_CLIENT_GUID_SIZE)) - goto found; - } - - read_unlock(&lease_list_lock); - return NULL; - -found: - rcu_read_lock(); - list_for_each_entry_rcu(opinfo, <->lease_list, lease_entry) { - if (!atomic_inc_not_zero(&opinfo->refcount)) - continue; - rcu_read_unlock(); - if (!opinfo->op_state || opinfo->op_state == OPLOCK_CLOSING) - goto op_next; - if (!(opinfo->o_lease->state & - (SMB2_LEASE_HANDLE_CACHING_LE | - SMB2_LEASE_WRITE_CACHING_LE))) - goto op_next; - ret = compare_guid_key(opinfo, conn->ClientGUID, - lease_key); - if (ret) { - ksmbd_debug(OPLOCK, "found opinfo\n"); - ret_op = opinfo; - goto out; - } -op_next: - opinfo_put(opinfo); - rcu_read_lock(); - } - rcu_read_unlock(); - -out: - read_unlock(&lease_list_lock); - return ret_op; -} diff --git a/fs/ksmbd/oplock.h b/fs/ksmbd/oplock.h deleted file mode 100644 index 4b0fe6da7694..000000000000 --- a/fs/ksmbd/oplock.h +++ /dev/null @@ -1,127 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __KSMBD_OPLOCK_H -#define __KSMBD_OPLOCK_H - -#include "smb_common.h" - -#define OPLOCK_WAIT_TIME (35 * HZ) - -/* SMB2 Oplock levels */ -#define SMB2_OPLOCK_LEVEL_NONE 0x00 -#define SMB2_OPLOCK_LEVEL_II 0x01 -#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08 -#define SMB2_OPLOCK_LEVEL_BATCH 0x09 -#define SMB2_OPLOCK_LEVEL_LEASE 0xFF - -/* Oplock states */ -#define OPLOCK_STATE_NONE 0x00 -#define OPLOCK_ACK_WAIT 0x01 -#define OPLOCK_CLOSING 0x02 - -#define OPLOCK_WRITE_TO_READ 0x01 -#define OPLOCK_READ_HANDLE_TO_READ 0x02 -#define OPLOCK_WRITE_TO_NONE 0x04 -#define OPLOCK_READ_TO_NONE 0x08 - -struct lease_ctx_info { - __u8 lease_key[SMB2_LEASE_KEY_SIZE]; - __le32 req_state; - __le32 flags; - __le64 duration; - __u8 parent_lease_key[SMB2_LEASE_KEY_SIZE]; - int version; -}; - -struct lease_table { - char client_guid[SMB2_CLIENT_GUID_SIZE]; - struct list_head lease_list; - struct list_head l_entry; - spinlock_t lb_lock; -}; - -struct lease { - __u8 lease_key[SMB2_LEASE_KEY_SIZE]; - __le32 state; - __le32 new_state; - __le32 flags; - __le64 duration; - __u8 parent_lease_key[SMB2_LEASE_KEY_SIZE]; - int version; - unsigned short epoch; - struct lease_table *l_lb; -}; - -struct oplock_info { - struct ksmbd_conn *conn; - struct ksmbd_session *sess; - struct ksmbd_work *work; - struct ksmbd_file *o_fp; - int level; - int op_state; - unsigned long pending_break; - u64 fid; - atomic_t breaking_cnt; - atomic_t refcount; - __u16 Tid; - bool is_lease; - bool open_trunc; /* truncate on open */ - struct lease *o_lease; - struct list_head interim_list; - struct list_head op_entry; - struct list_head lease_entry; - wait_queue_head_t oplock_q; /* Other server threads */ - wait_queue_head_t oplock_brk; /* oplock breaking wait */ - struct rcu_head rcu_head; -}; - -struct lease_break_info { - __le32 curr_state; - __le32 new_state; - __le16 epoch; - char lease_key[SMB2_LEASE_KEY_SIZE]; -}; - -struct oplock_break_info { - int level; - int open_trunc; - int fid; -}; - -int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, - u64 pid, struct ksmbd_file *fp, __u16 tid, - struct lease_ctx_info *lctx, int share_ret); -void smb_break_all_levII_oplock(struct ksmbd_work *work, - struct ksmbd_file *fp, int is_trunc); -int opinfo_write_to_read(struct oplock_info *opinfo); -int opinfo_read_handle_to_read(struct oplock_info *opinfo); -int opinfo_write_to_none(struct oplock_info *opinfo); -int opinfo_read_to_none(struct oplock_info *opinfo); -void close_id_del_oplock(struct ksmbd_file *fp); -void smb_break_all_oplock(struct ksmbd_work *work, struct ksmbd_file *fp); -struct oplock_info *opinfo_get(struct ksmbd_file *fp); -void opinfo_put(struct oplock_info *opinfo); - -/* Lease related functions */ -void create_lease_buf(u8 *rbuf, struct lease *lease); -struct lease_ctx_info *parse_lease_state(void *open_req); -__u8 smb2_map_lease_to_oplock(__le32 lease_state); -int lease_read_to_write(struct oplock_info *opinfo); - -/* Durable related functions */ -void create_durable_rsp_buf(char *cc); -void create_durable_v2_rsp_buf(char *cc, struct ksmbd_file *fp); -void create_mxac_rsp_buf(char *cc, int maximal_access); -void create_disk_id_rsp_buf(char *cc, __u64 file_id, __u64 vol_id); -void create_posix_rsp_buf(char *cc, struct ksmbd_file *fp); -struct create_context *smb2_find_context_vals(void *open_req, const char *tag, int tag_len); -struct oplock_info *lookup_lease_in_table(struct ksmbd_conn *conn, - char *lease_key); -int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci, - struct lease_ctx_info *lctx); -void destroy_lease_table(struct ksmbd_conn *conn); -#endif /* __KSMBD_OPLOCK_H */ diff --git a/fs/ksmbd/server.c b/fs/ksmbd/server.c deleted file mode 100644 index 847ee62afb8a..000000000000 --- a/fs/ksmbd/server.c +++ /dev/null @@ -1,646 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include "glob.h" -#include "oplock.h" -#include "misc.h" -#include <linux/sched/signal.h> -#include <linux/workqueue.h> -#include <linux/sysfs.h> -#include <linux/module.h> -#include <linux/moduleparam.h> - -#include "server.h" -#include "smb_common.h" -#include "smbstatus.h" -#include "connection.h" -#include "transport_ipc.h" -#include "mgmt/user_session.h" -#include "crypto_ctx.h" -#include "auth.h" - -int ksmbd_debug_types; - -struct ksmbd_server_config server_conf; - -enum SERVER_CTRL_TYPE { - SERVER_CTRL_TYPE_INIT, - SERVER_CTRL_TYPE_RESET, -}; - -struct server_ctrl_struct { - int type; - struct work_struct ctrl_work; -}; - -static DEFINE_MUTEX(ctrl_lock); - -static int ___server_conf_set(int idx, char *val) -{ - if (idx >= ARRAY_SIZE(server_conf.conf)) - return -EINVAL; - - if (!val || val[0] == 0x00) - return -EINVAL; - - kfree(server_conf.conf[idx]); - server_conf.conf[idx] = kstrdup(val, GFP_KERNEL); - if (!server_conf.conf[idx]) - return -ENOMEM; - return 0; -} - -int ksmbd_set_netbios_name(char *v) -{ - return ___server_conf_set(SERVER_CONF_NETBIOS_NAME, v); -} - -int ksmbd_set_server_string(char *v) -{ - return ___server_conf_set(SERVER_CONF_SERVER_STRING, v); -} - -int ksmbd_set_work_group(char *v) -{ - return ___server_conf_set(SERVER_CONF_WORK_GROUP, v); -} - -char *ksmbd_netbios_name(void) -{ - return server_conf.conf[SERVER_CONF_NETBIOS_NAME]; -} - -char *ksmbd_server_string(void) -{ - return server_conf.conf[SERVER_CONF_SERVER_STRING]; -} - -char *ksmbd_work_group(void) -{ - return server_conf.conf[SERVER_CONF_WORK_GROUP]; -} - -/** - * check_conn_state() - check state of server thread connection - * @work: smb work containing server thread information - * - * Return: 0 on valid connection, otherwise 1 to reconnect - */ -static inline int check_conn_state(struct ksmbd_work *work) -{ - struct smb_hdr *rsp_hdr; - - if (ksmbd_conn_exiting(work->conn) || - ksmbd_conn_need_reconnect(work->conn)) { - rsp_hdr = work->response_buf; - rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED; - return 1; - } - return 0; -} - -#define SERVER_HANDLER_CONTINUE 0 -#define SERVER_HANDLER_ABORT 1 - -static int __process_request(struct ksmbd_work *work, struct ksmbd_conn *conn, - u16 *cmd) -{ - struct smb_version_cmds *cmds; - u16 command; - int ret; - - if (check_conn_state(work)) - return SERVER_HANDLER_CONTINUE; - - if (ksmbd_verify_smb_message(work)) - return SERVER_HANDLER_ABORT; - - command = conn->ops->get_cmd_val(work); - *cmd = command; - -andx_again: - if (command >= conn->max_cmds) { - conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER); - return SERVER_HANDLER_CONTINUE; - } - - cmds = &conn->cmds[command]; - if (!cmds->proc) { - ksmbd_debug(SMB, "*** not implemented yet cmd = %x\n", command); - conn->ops->set_rsp_status(work, STATUS_NOT_IMPLEMENTED); - return SERVER_HANDLER_CONTINUE; - } - - if (work->sess && conn->ops->is_sign_req(work, command)) { - ret = conn->ops->check_sign_req(work); - if (!ret) { - conn->ops->set_rsp_status(work, STATUS_ACCESS_DENIED); - return SERVER_HANDLER_CONTINUE; - } - } - - ret = cmds->proc(work); - - if (ret < 0) - ksmbd_debug(CONN, "Failed to process %u [%d]\n", command, ret); - /* AndX commands - chained request can return positive values */ - else if (ret > 0) { - command = ret; - *cmd = command; - goto andx_again; - } - - if (work->send_no_response) - return SERVER_HANDLER_ABORT; - return SERVER_HANDLER_CONTINUE; -} - -static void __handle_ksmbd_work(struct ksmbd_work *work, - struct ksmbd_conn *conn) -{ - u16 command = 0; - int rc; - - if (conn->ops->allocate_rsp_buf(work)) - return; - - if (conn->ops->is_transform_hdr && - conn->ops->is_transform_hdr(work->request_buf)) { - rc = conn->ops->decrypt_req(work); - if (rc < 0) { - conn->ops->set_rsp_status(work, STATUS_DATA_ERROR); - goto send; - } - - work->encrypted = true; - } - - rc = conn->ops->init_rsp_hdr(work); - if (rc) { - /* either uid or tid is not correct */ - conn->ops->set_rsp_status(work, STATUS_INVALID_HANDLE); - goto send; - } - - do { - if (conn->ops->check_user_session) { - rc = conn->ops->check_user_session(work); - if (rc < 0) { - if (rc == -EINVAL) - conn->ops->set_rsp_status(work, - STATUS_INVALID_PARAMETER); - else - conn->ops->set_rsp_status(work, - STATUS_USER_SESSION_DELETED); - goto send; - } else if (rc > 0) { - rc = conn->ops->get_ksmbd_tcon(work); - if (rc < 0) { - if (rc == -EINVAL) - conn->ops->set_rsp_status(work, - STATUS_INVALID_PARAMETER); - else - conn->ops->set_rsp_status(work, - STATUS_NETWORK_NAME_DELETED); - goto send; - } - } - } - - rc = __process_request(work, conn, &command); - if (rc == SERVER_HANDLER_ABORT) - break; - - /* - * Call smb2_set_rsp_credits() function to set number of credits - * granted in hdr of smb2 response. - */ - if (conn->ops->set_rsp_credits) { - spin_lock(&conn->credits_lock); - rc = conn->ops->set_rsp_credits(work); - spin_unlock(&conn->credits_lock); - if (rc < 0) { - conn->ops->set_rsp_status(work, - STATUS_INVALID_PARAMETER); - goto send; - } - } - - if (work->sess && - (work->sess->sign || smb3_11_final_sess_setup_resp(work) || - conn->ops->is_sign_req(work, command))) - conn->ops->set_sign_rsp(work); - } while (is_chained_smb2_message(work)); - - if (work->send_no_response) - return; - -send: - smb3_preauth_hash_rsp(work); - if (work->sess && work->sess->enc && work->encrypted && - conn->ops->encrypt_resp) { - rc = conn->ops->encrypt_resp(work); - if (rc < 0) - conn->ops->set_rsp_status(work, STATUS_DATA_ERROR); - } - - ksmbd_conn_write(work); -} - -/** - * handle_ksmbd_work() - process pending smb work requests - * @wk: smb work containing request command buffer - * - * called by kworker threads to processing remaining smb work requests - */ -static void handle_ksmbd_work(struct work_struct *wk) -{ - struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work); - struct ksmbd_conn *conn = work->conn; - - atomic64_inc(&conn->stats.request_served); - - __handle_ksmbd_work(work, conn); - - ksmbd_conn_try_dequeue_request(work); - ksmbd_free_work_struct(work); - /* - * Checking waitqueue to dropping pending requests on - * disconnection. waitqueue_active is safe because it - * uses atomic operation for condition. - */ - if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) - wake_up(&conn->r_count_q); -} - -/** - * queue_ksmbd_work() - queue a smb request to worker thread queue - * for proccessing smb command and sending response - * @conn: connection instance - * - * read remaining data from socket create and submit work. - */ -static int queue_ksmbd_work(struct ksmbd_conn *conn) -{ - struct ksmbd_work *work; - - work = ksmbd_alloc_work_struct(); - if (!work) { - pr_err("allocation for work failed\n"); - return -ENOMEM; - } - - work->conn = conn; - work->request_buf = conn->request_buf; - conn->request_buf = NULL; - - ksmbd_init_smb_server(work); - - ksmbd_conn_enqueue_request(work); - atomic_inc(&conn->r_count); - /* update activity on connection */ - conn->last_active = jiffies; - INIT_WORK(&work->work, handle_ksmbd_work); - ksmbd_queue_work(work); - return 0; -} - -static int ksmbd_server_process_request(struct ksmbd_conn *conn) -{ - return queue_ksmbd_work(conn); -} - -static int ksmbd_server_terminate_conn(struct ksmbd_conn *conn) -{ - ksmbd_sessions_deregister(conn); - destroy_lease_table(conn); - return 0; -} - -static void ksmbd_server_tcp_callbacks_init(void) -{ - struct ksmbd_conn_ops ops; - - ops.process_fn = ksmbd_server_process_request; - ops.terminate_fn = ksmbd_server_terminate_conn; - - ksmbd_conn_init_server_callbacks(&ops); -} - -static void server_conf_free(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(server_conf.conf); i++) { - kfree(server_conf.conf[i]); - server_conf.conf[i] = NULL; - } -} - -static int server_conf_init(void) -{ - WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP); - server_conf.enforced_signing = 0; - server_conf.min_protocol = ksmbd_min_protocol(); - server_conf.max_protocol = ksmbd_max_protocol(); - server_conf.auth_mechs = KSMBD_AUTH_NTLMSSP; -#ifdef CONFIG_SMB_SERVER_KERBEROS5 - server_conf.auth_mechs |= KSMBD_AUTH_KRB5 | - KSMBD_AUTH_MSKRB5; -#endif - return 0; -} - -static void server_ctrl_handle_init(struct server_ctrl_struct *ctrl) -{ - int ret; - - ret = ksmbd_conn_transport_init(); - if (ret) { - server_queue_ctrl_reset_work(); - return; - } - - WRITE_ONCE(server_conf.state, SERVER_STATE_RUNNING); -} - -static void server_ctrl_handle_reset(struct server_ctrl_struct *ctrl) -{ - ksmbd_ipc_soft_reset(); - ksmbd_conn_transport_destroy(); - server_conf_free(); - server_conf_init(); - WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP); -} - -static void server_ctrl_handle_work(struct work_struct *work) -{ - struct server_ctrl_struct *ctrl; - - ctrl = container_of(work, struct server_ctrl_struct, ctrl_work); - - mutex_lock(&ctrl_lock); - switch (ctrl->type) { - case SERVER_CTRL_TYPE_INIT: - server_ctrl_handle_init(ctrl); - break; - case SERVER_CTRL_TYPE_RESET: - server_ctrl_handle_reset(ctrl); - break; - default: - pr_err("Unknown server work type: %d\n", ctrl->type); - } - mutex_unlock(&ctrl_lock); - kfree(ctrl); - module_put(THIS_MODULE); -} - -static int __queue_ctrl_work(int type) -{ - struct server_ctrl_struct *ctrl; - - ctrl = kmalloc(sizeof(struct server_ctrl_struct), GFP_KERNEL); - if (!ctrl) - return -ENOMEM; - - __module_get(THIS_MODULE); - ctrl->type = type; - INIT_WORK(&ctrl->ctrl_work, server_ctrl_handle_work); - queue_work(system_long_wq, &ctrl->ctrl_work); - return 0; -} - -int server_queue_ctrl_init_work(void) -{ - return __queue_ctrl_work(SERVER_CTRL_TYPE_INIT); -} - -int server_queue_ctrl_reset_work(void) -{ - return __queue_ctrl_work(SERVER_CTRL_TYPE_RESET); -} - -static ssize_t stats_show(struct class *class, struct class_attribute *attr, - char *buf) -{ - /* - * Inc this each time you change stats output format, - * so user space will know what to do. - */ - static int stats_version = 2; - static const char * const state[] = { - "startup", - "running", - "reset", - "shutdown" - }; - - ssize_t sz = scnprintf(buf, PAGE_SIZE, "%d %s %d %lu\n", stats_version, - state[server_conf.state], server_conf.tcp_port, - server_conf.ipc_last_active / HZ); - return sz; -} - -static ssize_t kill_server_store(struct class *class, - struct class_attribute *attr, const char *buf, - size_t len) -{ - if (!sysfs_streq(buf, "hard")) - return len; - - pr_info("kill command received\n"); - mutex_lock(&ctrl_lock); - WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING); - __module_get(THIS_MODULE); - server_ctrl_handle_reset(NULL); - module_put(THIS_MODULE); - mutex_unlock(&ctrl_lock); - return len; -} - -static const char * const debug_type_strings[] = {"smb", "auth", "vfs", - "oplock", "ipc", "conn", - "rdma"}; - -static ssize_t debug_show(struct class *class, struct class_attribute *attr, - char *buf) -{ - ssize_t sz = 0; - int i, pos = 0; - - for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) { - if ((ksmbd_debug_types >> i) & 1) { - pos = scnprintf(buf + sz, - PAGE_SIZE - sz, - "[%s] ", - debug_type_strings[i]); - } else { - pos = scnprintf(buf + sz, - PAGE_SIZE - sz, - "%s ", - debug_type_strings[i]); - } - sz += pos; - } - sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n"); - return sz; -} - -static ssize_t debug_store(struct class *class, struct class_attribute *attr, - const char *buf, size_t len) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) { - if (sysfs_streq(buf, "all")) { - if (ksmbd_debug_types == KSMBD_DEBUG_ALL) - ksmbd_debug_types = 0; - else - ksmbd_debug_types = KSMBD_DEBUG_ALL; - break; - } - - if (sysfs_streq(buf, debug_type_strings[i])) { - if (ksmbd_debug_types & (1 << i)) - ksmbd_debug_types &= ~(1 << i); - else - ksmbd_debug_types |= (1 << i); - break; - } - } - - return len; -} - -static CLASS_ATTR_RO(stats); -static CLASS_ATTR_WO(kill_server); -static CLASS_ATTR_RW(debug); - -static struct attribute *ksmbd_control_class_attrs[] = { - &class_attr_stats.attr, - &class_attr_kill_server.attr, - &class_attr_debug.attr, - NULL, -}; -ATTRIBUTE_GROUPS(ksmbd_control_class); - -static struct class ksmbd_control_class = { - .name = "ksmbd-control", - .owner = THIS_MODULE, - .class_groups = ksmbd_control_class_groups, -}; - -static int ksmbd_server_shutdown(void) -{ - WRITE_ONCE(server_conf.state, SERVER_STATE_SHUTTING_DOWN); - - class_unregister(&ksmbd_control_class); - ksmbd_workqueue_destroy(); - ksmbd_ipc_release(); - ksmbd_conn_transport_destroy(); - ksmbd_crypto_destroy(); - ksmbd_free_global_file_table(); - destroy_lease_table(NULL); - ksmbd_work_pool_destroy(); - ksmbd_exit_file_cache(); - server_conf_free(); - return 0; -} - -static int __init ksmbd_server_init(void) -{ - int ret; - - ret = class_register(&ksmbd_control_class); - if (ret) { - pr_err("Unable to register ksmbd-control class\n"); - return ret; - } - - ksmbd_server_tcp_callbacks_init(); - - ret = server_conf_init(); - if (ret) - goto err_unregister; - - ret = ksmbd_work_pool_init(); - if (ret) - goto err_unregister; - - ret = ksmbd_init_file_cache(); - if (ret) - goto err_destroy_work_pools; - - ret = ksmbd_ipc_init(); - if (ret) - goto err_exit_file_cache; - - ret = ksmbd_init_global_file_table(); - if (ret) - goto err_ipc_release; - - ret = ksmbd_inode_hash_init(); - if (ret) - goto err_destroy_file_table; - - ret = ksmbd_crypto_create(); - if (ret) - goto err_release_inode_hash; - - ret = ksmbd_workqueue_init(); - if (ret) - goto err_crypto_destroy; - - pr_warn_once("The ksmbd server is experimental\n"); - - return 0; - -err_crypto_destroy: - ksmbd_crypto_destroy(); -err_release_inode_hash: - ksmbd_release_inode_hash(); -err_destroy_file_table: - ksmbd_free_global_file_table(); -err_ipc_release: - ksmbd_ipc_release(); -err_exit_file_cache: - ksmbd_exit_file_cache(); -err_destroy_work_pools: - ksmbd_work_pool_destroy(); -err_unregister: - class_unregister(&ksmbd_control_class); - - return ret; -} - -/** - * ksmbd_server_exit() - shutdown forker thread and free memory at module exit - */ -static void __exit ksmbd_server_exit(void) -{ - ksmbd_server_shutdown(); - rcu_barrier(); - ksmbd_release_inode_hash(); -} - -MODULE_AUTHOR("Namjae Jeon <linkinjeon@kernel.org>"); -MODULE_VERSION(KSMBD_VERSION); -MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER"); -MODULE_LICENSE("GPL"); -MODULE_SOFTDEP("pre: ecb"); -MODULE_SOFTDEP("pre: hmac"); -MODULE_SOFTDEP("pre: md5"); -MODULE_SOFTDEP("pre: nls"); -MODULE_SOFTDEP("pre: aes"); -MODULE_SOFTDEP("pre: cmac"); -MODULE_SOFTDEP("pre: sha256"); -MODULE_SOFTDEP("pre: sha512"); -MODULE_SOFTDEP("pre: aead2"); -MODULE_SOFTDEP("pre: ccm"); -MODULE_SOFTDEP("pre: gcm"); -MODULE_SOFTDEP("pre: crc32"); -module_init(ksmbd_server_init) -module_exit(ksmbd_server_exit) diff --git a/fs/ksmbd/server.h b/fs/ksmbd/server.h deleted file mode 100644 index db7278181760..000000000000 --- a/fs/ksmbd/server.h +++ /dev/null @@ -1,71 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __SERVER_H__ -#define __SERVER_H__ - -#include "smbacl.h" - -/* - * Server state type - */ -enum { - SERVER_STATE_STARTING_UP, - SERVER_STATE_RUNNING, - SERVER_STATE_RESETTING, - SERVER_STATE_SHUTTING_DOWN, -}; - -/* - * Server global config string index - */ -enum { - SERVER_CONF_NETBIOS_NAME, - SERVER_CONF_SERVER_STRING, - SERVER_CONF_WORK_GROUP, -}; - -struct ksmbd_server_config { - unsigned int flags; - unsigned int state; - short signing; - short enforced_signing; - short min_protocol; - short max_protocol; - unsigned short tcp_port; - unsigned short ipc_timeout; - unsigned long ipc_last_active; - unsigned long deadtime; - unsigned int share_fake_fscaps; - struct smb_sid domain_sid; - unsigned int auth_mechs; - unsigned int max_connections; - - char *conf[SERVER_CONF_WORK_GROUP + 1]; -}; - -extern struct ksmbd_server_config server_conf; - -int ksmbd_set_netbios_name(char *v); -int ksmbd_set_server_string(char *v); -int ksmbd_set_work_group(char *v); - -char *ksmbd_netbios_name(void); -char *ksmbd_server_string(void); -char *ksmbd_work_group(void); - -static inline int ksmbd_server_running(void) -{ - return READ_ONCE(server_conf.state) == SERVER_STATE_RUNNING; -} - -static inline int ksmbd_server_configurable(void) -{ - return READ_ONCE(server_conf.state) < SERVER_STATE_RESETTING; -} - -int server_queue_ctrl_init_work(void); -int server_queue_ctrl_reset_work(void); -#endif /* __SERVER_H__ */ diff --git a/fs/ksmbd/smb2misc.c b/fs/ksmbd/smb2misc.c deleted file mode 100644 index 33b7e6c4ceff..000000000000 --- a/fs/ksmbd/smb2misc.c +++ /dev/null @@ -1,454 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include "glob.h" -#include "nterr.h" -#include "smb_common.h" -#include "smbstatus.h" -#include "mgmt/user_session.h" -#include "connection.h" - -static int check_smb2_hdr(struct smb2_hdr *hdr) -{ - /* - * Make sure that this really is an SMB, that it is a response. - */ - if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) - return 1; - return 0; -} - -/* - * The following table defines the expected "StructureSize" of SMB2 requests - * in order by SMB2 command. This is similar to "wct" in SMB/CIFS requests. - * - * Note that commands are defined in smb2pdu.h in le16 but the array below is - * indexed by command in host byte order - */ -static const __le16 smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { - /* SMB2_NEGOTIATE */ cpu_to_le16(36), - /* SMB2_SESSION_SETUP */ cpu_to_le16(25), - /* SMB2_LOGOFF */ cpu_to_le16(4), - /* SMB2_TREE_CONNECT */ cpu_to_le16(9), - /* SMB2_TREE_DISCONNECT */ cpu_to_le16(4), - /* SMB2_CREATE */ cpu_to_le16(57), - /* SMB2_CLOSE */ cpu_to_le16(24), - /* SMB2_FLUSH */ cpu_to_le16(24), - /* SMB2_READ */ cpu_to_le16(49), - /* SMB2_WRITE */ cpu_to_le16(49), - /* SMB2_LOCK */ cpu_to_le16(48), - /* SMB2_IOCTL */ cpu_to_le16(57), - /* SMB2_CANCEL */ cpu_to_le16(4), - /* SMB2_ECHO */ cpu_to_le16(4), - /* SMB2_QUERY_DIRECTORY */ cpu_to_le16(33), - /* SMB2_CHANGE_NOTIFY */ cpu_to_le16(32), - /* SMB2_QUERY_INFO */ cpu_to_le16(41), - /* SMB2_SET_INFO */ cpu_to_le16(33), - /* use 44 for lease break */ - /* SMB2_OPLOCK_BREAK */ cpu_to_le16(36) -}; - -/* - * The size of the variable area depends on the offset and length fields - * located in different fields for various SMB2 requests. SMB2 requests - * with no variable length info, show an offset of zero for the offset field. - */ -static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = { - /* SMB2_NEGOTIATE */ true, - /* SMB2_SESSION_SETUP */ true, - /* SMB2_LOGOFF */ false, - /* SMB2_TREE_CONNECT */ true, - /* SMB2_TREE_DISCONNECT */ false, - /* SMB2_CREATE */ true, - /* SMB2_CLOSE */ false, - /* SMB2_FLUSH */ false, - /* SMB2_READ */ true, - /* SMB2_WRITE */ true, - /* SMB2_LOCK */ true, - /* SMB2_IOCTL */ true, - /* SMB2_CANCEL */ false, /* BB CHECK this not listed in documentation */ - /* SMB2_ECHO */ false, - /* SMB2_QUERY_DIRECTORY */ true, - /* SMB2_CHANGE_NOTIFY */ false, - /* SMB2_QUERY_INFO */ true, - /* SMB2_SET_INFO */ true, - /* SMB2_OPLOCK_BREAK */ false -}; - -/* - * Set length of the data area and the offset to arguments. - * if they are invalid, return error. - */ -static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, - struct smb2_hdr *hdr) -{ - int ret = 0; - - *off = 0; - *len = 0; - - /* - * Following commands have data areas so we have to get the location - * of the data buffer offset and data buffer length for the particular - * command. - */ - switch (hdr->Command) { - case SMB2_SESSION_SETUP: - *off = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferOffset); - *len = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferLength); - break; - case SMB2_TREE_CONNECT: - *off = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset); - *len = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathLength); - break; - case SMB2_CREATE: - { - if (((struct smb2_create_req *)hdr)->CreateContextsLength) { - *off = le32_to_cpu(((struct smb2_create_req *) - hdr)->CreateContextsOffset); - *len = le32_to_cpu(((struct smb2_create_req *) - hdr)->CreateContextsLength); - break; - } - - *off = le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset); - *len = le16_to_cpu(((struct smb2_create_req *)hdr)->NameLength); - break; - } - case SMB2_QUERY_INFO: - *off = le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset); - *len = le32_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferLength); - break; - case SMB2_SET_INFO: - *off = le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset); - *len = le32_to_cpu(((struct smb2_set_info_req *)hdr)->BufferLength); - break; - case SMB2_READ: - *off = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoOffset); - *len = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoLength); - break; - case SMB2_WRITE: - if (((struct smb2_write_req *)hdr)->DataOffset || - ((struct smb2_write_req *)hdr)->Length) { - *off = max_t(unsigned int, - le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset), - offsetof(struct smb2_write_req, Buffer)); - *len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length); - break; - } - - *off = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoOffset); - *len = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoLength); - break; - case SMB2_QUERY_DIRECTORY: - *off = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset); - *len = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameLength); - break; - case SMB2_LOCK: - { - unsigned short lock_count; - - lock_count = le16_to_cpu(((struct smb2_lock_req *)hdr)->LockCount); - if (lock_count > 0) { - *off = offsetof(struct smb2_lock_req, locks); - *len = sizeof(struct smb2_lock_element) * lock_count; - } - break; - } - case SMB2_IOCTL: - *off = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset); - *len = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputCount); - break; - default: - ksmbd_debug(SMB, "no length check for command\n"); - break; - } - - if (*off > 4096) { - ksmbd_debug(SMB, "offset %d too large\n", *off); - ret = -EINVAL; - } else if ((u64)*off + *len > MAX_STREAM_PROT_LEN) { - ksmbd_debug(SMB, "Request is larger than maximum stream protocol length(%u): %llu\n", - MAX_STREAM_PROT_LEN, (u64)*off + *len); - ret = -EINVAL; - } - - return ret; -} - -/* - * Calculate the size of the SMB message based on the fixed header - * portion, the number of word parameters and the data portion of the message. - */ -static int smb2_calc_size(void *buf, unsigned int *len) -{ - struct smb2_pdu *pdu = (struct smb2_pdu *)buf; - struct smb2_hdr *hdr = &pdu->hdr; - unsigned int offset; /* the offset from the beginning of SMB to data area */ - unsigned int data_length; /* the length of the variable length data area */ - int ret; - - /* Structure Size has already been checked to make sure it is 64 */ - *len = le16_to_cpu(hdr->StructureSize); - - /* - * StructureSize2, ie length of fixed parameter area has already - * been checked to make sure it is the correct length. - */ - *len += le16_to_cpu(pdu->StructureSize2); - /* - * StructureSize2 of smb2_lock pdu is set to 48, indicating - * the size of smb2 lock request with single smb2_lock_element - * regardless of number of locks. Subtract single - * smb2_lock_element for correct buffer size check. - */ - if (hdr->Command == SMB2_LOCK) - *len -= sizeof(struct smb2_lock_element); - - if (has_smb2_data_area[le16_to_cpu(hdr->Command)] == false) - goto calc_size_exit; - - ret = smb2_get_data_area_len(&offset, &data_length, hdr); - if (ret) - return ret; - ksmbd_debug(SMB, "SMB2 data length %u offset %u\n", data_length, - offset); - - if (data_length > 0) { - /* - * Check to make sure that data area begins after fixed area, - * Note that last byte of the fixed area is part of data area - * for some commands, typically those with odd StructureSize, - * so we must add one to the calculation. - */ - if (offset + 1 < *len) { - ksmbd_debug(SMB, - "data area offset %d overlaps SMB2 header %u\n", - offset + 1, *len); - return -EINVAL; - } - - *len = offset + data_length; - } - -calc_size_exit: - ksmbd_debug(SMB, "SMB2 len %u\n", *len); - return 0; -} - -static inline int smb2_query_info_req_len(struct smb2_query_info_req *h) -{ - return le32_to_cpu(h->InputBufferLength) + - le32_to_cpu(h->OutputBufferLength); -} - -static inline int smb2_set_info_req_len(struct smb2_set_info_req *h) -{ - return le32_to_cpu(h->BufferLength); -} - -static inline int smb2_read_req_len(struct smb2_read_req *h) -{ - return le32_to_cpu(h->Length); -} - -static inline int smb2_write_req_len(struct smb2_write_req *h) -{ - return le32_to_cpu(h->Length); -} - -static inline int smb2_query_dir_req_len(struct smb2_query_directory_req *h) -{ - return le32_to_cpu(h->OutputBufferLength); -} - -static inline int smb2_ioctl_req_len(struct smb2_ioctl_req *h) -{ - return le32_to_cpu(h->InputCount) + - le32_to_cpu(h->OutputCount); -} - -static inline int smb2_ioctl_resp_len(struct smb2_ioctl_req *h) -{ - return le32_to_cpu(h->MaxInputResponse) + - le32_to_cpu(h->MaxOutputResponse); -} - -static int smb2_validate_credit_charge(struct ksmbd_conn *conn, - struct smb2_hdr *hdr) -{ - unsigned int req_len = 0, expect_resp_len = 0, calc_credit_num, max_len; - unsigned short credit_charge = le16_to_cpu(hdr->CreditCharge); - void *__hdr = hdr; - int ret = 0; - - switch (hdr->Command) { - case SMB2_QUERY_INFO: - req_len = smb2_query_info_req_len(__hdr); - break; - case SMB2_SET_INFO: - req_len = smb2_set_info_req_len(__hdr); - break; - case SMB2_READ: - req_len = smb2_read_req_len(__hdr); - break; - case SMB2_WRITE: - req_len = smb2_write_req_len(__hdr); - break; - case SMB2_QUERY_DIRECTORY: - req_len = smb2_query_dir_req_len(__hdr); - break; - case SMB2_IOCTL: - req_len = smb2_ioctl_req_len(__hdr); - expect_resp_len = smb2_ioctl_resp_len(__hdr); - break; - case SMB2_CANCEL: - return 0; - default: - req_len = 1; - break; - } - - credit_charge = max_t(unsigned short, credit_charge, 1); - max_len = max_t(unsigned int, req_len, expect_resp_len); - calc_credit_num = DIV_ROUND_UP(max_len, SMB2_MAX_BUFFER_SIZE); - - if (credit_charge < calc_credit_num) { - ksmbd_debug(SMB, "Insufficient credit charge, given: %d, needed: %d\n", - credit_charge, calc_credit_num); - return 1; - } else if (credit_charge > conn->vals->max_credits) { - ksmbd_debug(SMB, "Too large credit charge: %d\n", credit_charge); - return 1; - } - - spin_lock(&conn->credits_lock); - if (credit_charge > conn->total_credits) { - ksmbd_debug(SMB, "Insufficient credits granted, given: %u, granted: %u\n", - credit_charge, conn->total_credits); - ret = 1; - } - - if ((u64)conn->outstanding_credits + credit_charge > conn->total_credits) { - ksmbd_debug(SMB, "Limits exceeding the maximum allowable outstanding requests, given : %u, pending : %u\n", - credit_charge, conn->outstanding_credits); - ret = 1; - } else - conn->outstanding_credits += credit_charge; - - spin_unlock(&conn->credits_lock); - - return ret; -} - -int ksmbd_smb2_check_message(struct ksmbd_work *work) -{ - struct smb2_pdu *pdu = ksmbd_req_buf_next(work); - struct smb2_hdr *hdr = &pdu->hdr; - int command; - __u32 clc_len; /* calculated length */ - __u32 len = get_rfc1002_len(work->request_buf); - __u32 req_struct_size, next_cmd = le32_to_cpu(hdr->NextCommand); - - if ((u64)work->next_smb2_rcv_hdr_off + next_cmd > len) { - pr_err("next command(%u) offset exceeds smb msg size\n", - next_cmd); - return 1; - } - - if (next_cmd > 0) - len = next_cmd; - else if (work->next_smb2_rcv_hdr_off) - len -= work->next_smb2_rcv_hdr_off; - - if (check_smb2_hdr(hdr)) - return 1; - - if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) { - ksmbd_debug(SMB, "Illegal structure size %u\n", - le16_to_cpu(hdr->StructureSize)); - return 1; - } - - command = le16_to_cpu(hdr->Command); - if (command >= NUMBER_OF_SMB2_COMMANDS) { - ksmbd_debug(SMB, "Illegal SMB2 command %d\n", command); - return 1; - } - - if (smb2_req_struct_sizes[command] != pdu->StructureSize2) { - if (command == SMB2_OPLOCK_BREAK_HE && - le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_20 && - le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_21) { - /* special case for SMB2.1 lease break message */ - ksmbd_debug(SMB, - "Illegal request size %d for oplock break\n", - le16_to_cpu(pdu->StructureSize2)); - return 1; - } - } - - req_struct_size = le16_to_cpu(pdu->StructureSize2) + - __SMB2_HEADER_STRUCTURE_SIZE; - if (command == SMB2_LOCK_HE) - req_struct_size -= sizeof(struct smb2_lock_element); - - if (req_struct_size > len + 1) - return 1; - - if (smb2_calc_size(hdr, &clc_len)) - return 1; - - if (len != clc_len) { - /* client can return one byte more due to implied bcc[0] */ - if (clc_len == len + 1) - goto validate_credit; - - /* - * Some windows servers (win2016) will pad also the final - * PDU in a compound to 8 bytes. - */ - if (ALIGN(clc_len, 8) == len) - goto validate_credit; - - /* - * SMB2 NEGOTIATE request will be validated when message - * handling proceeds. - */ - if (command == SMB2_NEGOTIATE_HE) - goto validate_credit; - - /* - * Allow a message that padded to 8byte boundary. - * Linux 4.19.217 with smb 3.0.2 are sometimes - * sending messages where the cls_len is exactly - * 8 bytes less than len. - */ - if (clc_len < len && (len - clc_len) <= 8) - goto validate_credit; - - pr_err_ratelimited( - "cli req too short, len %d not %d. cmd:%d mid:%llu\n", - len, clc_len, command, - le64_to_cpu(hdr->MessageId)); - - return 1; - } - -validate_credit: - if ((work->conn->vals->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) && - smb2_validate_credit_charge(work->conn, hdr)) { - work->conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER); - return 1; - } - - return 0; -} - -int smb2_negotiate_request(struct ksmbd_work *work) -{ - return ksmbd_smb_negotiate_common(work, SMB2_NEGOTIATE_HE); -} diff --git a/fs/ksmbd/smb2ops.c b/fs/ksmbd/smb2ops.c deleted file mode 100644 index ab23da2120b9..000000000000 --- a/fs/ksmbd/smb2ops.c +++ /dev/null @@ -1,314 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/slab.h> -#include "glob.h" - -#include "auth.h" -#include "connection.h" -#include "smb_common.h" -#include "server.h" - -static struct smb_version_values smb21_server_values = { - .version_string = SMB21_VERSION_STRING, - .protocol_id = SMB21_PROT_ID, - .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, - .max_read_size = SMB21_DEFAULT_IOSIZE, - .max_write_size = SMB21_DEFAULT_IOSIZE, - .max_trans_size = SMB21_DEFAULT_IOSIZE, - .max_credits = SMB2_MAX_CREDITS, - .large_lock_type = 0, - .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE, - .shared_lock_type = SMB2_LOCKFLAG_SHARED, - .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), - .max_header_size = MAX_SMB2_HDR_SIZE, - .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, - .lock_cmd = SMB2_LOCK, - .cap_unix = 0, - .cap_nt_find = SMB2_NT_FIND, - .cap_large_files = SMB2_LARGE_FILES, - .create_lease_size = sizeof(struct create_lease), - .create_durable_size = sizeof(struct create_durable_rsp), - .create_mxac_size = sizeof(struct create_mxac_rsp), - .create_disk_id_size = sizeof(struct create_disk_id_rsp), - .create_posix_size = sizeof(struct create_posix_rsp), -}; - -static struct smb_version_values smb30_server_values = { - .version_string = SMB30_VERSION_STRING, - .protocol_id = SMB30_PROT_ID, - .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, - .max_read_size = SMB3_DEFAULT_IOSIZE, - .max_write_size = SMB3_DEFAULT_IOSIZE, - .max_trans_size = SMB3_DEFAULT_TRANS_SIZE, - .max_credits = SMB2_MAX_CREDITS, - .large_lock_type = 0, - .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE, - .shared_lock_type = SMB2_LOCKFLAG_SHARED, - .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), - .max_header_size = MAX_SMB2_HDR_SIZE, - .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, - .lock_cmd = SMB2_LOCK, - .cap_unix = 0, - .cap_nt_find = SMB2_NT_FIND, - .cap_large_files = SMB2_LARGE_FILES, - .create_lease_size = sizeof(struct create_lease_v2), - .create_durable_size = sizeof(struct create_durable_rsp), - .create_durable_v2_size = sizeof(struct create_durable_v2_rsp), - .create_mxac_size = sizeof(struct create_mxac_rsp), - .create_disk_id_size = sizeof(struct create_disk_id_rsp), - .create_posix_size = sizeof(struct create_posix_rsp), -}; - -static struct smb_version_values smb302_server_values = { - .version_string = SMB302_VERSION_STRING, - .protocol_id = SMB302_PROT_ID, - .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, - .max_read_size = SMB3_DEFAULT_IOSIZE, - .max_write_size = SMB3_DEFAULT_IOSIZE, - .max_trans_size = SMB3_DEFAULT_TRANS_SIZE, - .max_credits = SMB2_MAX_CREDITS, - .large_lock_type = 0, - .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE, - .shared_lock_type = SMB2_LOCKFLAG_SHARED, - .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), - .max_header_size = MAX_SMB2_HDR_SIZE, - .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, - .lock_cmd = SMB2_LOCK, - .cap_unix = 0, - .cap_nt_find = SMB2_NT_FIND, - .cap_large_files = SMB2_LARGE_FILES, - .create_lease_size = sizeof(struct create_lease_v2), - .create_durable_size = sizeof(struct create_durable_rsp), - .create_durable_v2_size = sizeof(struct create_durable_v2_rsp), - .create_mxac_size = sizeof(struct create_mxac_rsp), - .create_disk_id_size = sizeof(struct create_disk_id_rsp), - .create_posix_size = sizeof(struct create_posix_rsp), -}; - -static struct smb_version_values smb311_server_values = { - .version_string = SMB311_VERSION_STRING, - .protocol_id = SMB311_PROT_ID, - .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, - .max_read_size = SMB3_DEFAULT_IOSIZE, - .max_write_size = SMB3_DEFAULT_IOSIZE, - .max_trans_size = SMB3_DEFAULT_TRANS_SIZE, - .max_credits = SMB2_MAX_CREDITS, - .large_lock_type = 0, - .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE, - .shared_lock_type = SMB2_LOCKFLAG_SHARED, - .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), - .max_header_size = MAX_SMB2_HDR_SIZE, - .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, - .lock_cmd = SMB2_LOCK, - .cap_unix = 0, - .cap_nt_find = SMB2_NT_FIND, - .cap_large_files = SMB2_LARGE_FILES, - .create_lease_size = sizeof(struct create_lease_v2), - .create_durable_size = sizeof(struct create_durable_rsp), - .create_durable_v2_size = sizeof(struct create_durable_v2_rsp), - .create_mxac_size = sizeof(struct create_mxac_rsp), - .create_disk_id_size = sizeof(struct create_disk_id_rsp), - .create_posix_size = sizeof(struct create_posix_rsp), -}; - -static struct smb_version_ops smb2_0_server_ops = { - .get_cmd_val = get_smb2_cmd_val, - .init_rsp_hdr = init_smb2_rsp_hdr, - .set_rsp_status = set_smb2_rsp_status, - .allocate_rsp_buf = smb2_allocate_rsp_buf, - .set_rsp_credits = smb2_set_rsp_credits, - .check_user_session = smb2_check_user_session, - .get_ksmbd_tcon = smb2_get_ksmbd_tcon, - .is_sign_req = smb2_is_sign_req, - .check_sign_req = smb2_check_sign_req, - .set_sign_rsp = smb2_set_sign_rsp -}; - -static struct smb_version_ops smb3_0_server_ops = { - .get_cmd_val = get_smb2_cmd_val, - .init_rsp_hdr = init_smb2_rsp_hdr, - .set_rsp_status = set_smb2_rsp_status, - .allocate_rsp_buf = smb2_allocate_rsp_buf, - .set_rsp_credits = smb2_set_rsp_credits, - .check_user_session = smb2_check_user_session, - .get_ksmbd_tcon = smb2_get_ksmbd_tcon, - .is_sign_req = smb2_is_sign_req, - .check_sign_req = smb3_check_sign_req, - .set_sign_rsp = smb3_set_sign_rsp, - .generate_signingkey = ksmbd_gen_smb30_signingkey, - .generate_encryptionkey = ksmbd_gen_smb30_encryptionkey, - .is_transform_hdr = smb3_is_transform_hdr, - .decrypt_req = smb3_decrypt_req, - .encrypt_resp = smb3_encrypt_resp -}; - -static struct smb_version_ops smb3_11_server_ops = { - .get_cmd_val = get_smb2_cmd_val, - .init_rsp_hdr = init_smb2_rsp_hdr, - .set_rsp_status = set_smb2_rsp_status, - .allocate_rsp_buf = smb2_allocate_rsp_buf, - .set_rsp_credits = smb2_set_rsp_credits, - .check_user_session = smb2_check_user_session, - .get_ksmbd_tcon = smb2_get_ksmbd_tcon, - .is_sign_req = smb2_is_sign_req, - .check_sign_req = smb3_check_sign_req, - .set_sign_rsp = smb3_set_sign_rsp, - .generate_signingkey = ksmbd_gen_smb311_signingkey, - .generate_encryptionkey = ksmbd_gen_smb311_encryptionkey, - .is_transform_hdr = smb3_is_transform_hdr, - .decrypt_req = smb3_decrypt_req, - .encrypt_resp = smb3_encrypt_resp -}; - -static struct smb_version_cmds smb2_0_server_cmds[NUMBER_OF_SMB2_COMMANDS] = { - [SMB2_NEGOTIATE_HE] = { .proc = smb2_negotiate_request, }, - [SMB2_SESSION_SETUP_HE] = { .proc = smb2_sess_setup, }, - [SMB2_TREE_CONNECT_HE] = { .proc = smb2_tree_connect,}, - [SMB2_TREE_DISCONNECT_HE] = { .proc = smb2_tree_disconnect,}, - [SMB2_LOGOFF_HE] = { .proc = smb2_session_logoff,}, - [SMB2_CREATE_HE] = { .proc = smb2_open}, - [SMB2_QUERY_INFO_HE] = { .proc = smb2_query_info}, - [SMB2_QUERY_DIRECTORY_HE] = { .proc = smb2_query_dir}, - [SMB2_CLOSE_HE] = { .proc = smb2_close}, - [SMB2_ECHO_HE] = { .proc = smb2_echo}, - [SMB2_SET_INFO_HE] = { .proc = smb2_set_info}, - [SMB2_READ_HE] = { .proc = smb2_read}, - [SMB2_WRITE_HE] = { .proc = smb2_write}, - [SMB2_FLUSH_HE] = { .proc = smb2_flush}, - [SMB2_CANCEL_HE] = { .proc = smb2_cancel}, - [SMB2_LOCK_HE] = { .proc = smb2_lock}, - [SMB2_IOCTL_HE] = { .proc = smb2_ioctl}, - [SMB2_OPLOCK_BREAK_HE] = { .proc = smb2_oplock_break}, - [SMB2_CHANGE_NOTIFY_HE] = { .proc = smb2_notify}, -}; - -/** - * init_smb2_1_server() - initialize a smb server connection with smb2.1 - * command dispatcher - * @conn: connection instance - */ -void init_smb2_1_server(struct ksmbd_conn *conn) -{ - conn->vals = &smb21_server_values; - conn->ops = &smb2_0_server_ops; - conn->cmds = smb2_0_server_cmds; - conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds); - conn->signing_algorithm = SIGNING_ALG_HMAC_SHA256_LE; - - if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; -} - -/** - * init_smb3_0_server() - initialize a smb server connection with smb3.0 - * command dispatcher - * @conn: connection instance - */ -void init_smb3_0_server(struct ksmbd_conn *conn) -{ - conn->vals = &smb30_server_values; - conn->ops = &smb3_0_server_ops; - conn->cmds = smb2_0_server_cmds; - conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds); - conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; - - if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; - - if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION && - conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; - - if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; -} - -/** - * init_smb3_02_server() - initialize a smb server connection with smb3.02 - * command dispatcher - * @conn: connection instance - */ -void init_smb3_02_server(struct ksmbd_conn *conn) -{ - conn->vals = &smb302_server_values; - conn->ops = &smb3_0_server_ops; - conn->cmds = smb2_0_server_cmds; - conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds); - conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; - - if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; - - if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION && - conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; - - if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; -} - -/** - * init_smb3_11_server() - initialize a smb server connection with smb3.11 - * command dispatcher - * @conn: connection instance - */ -int init_smb3_11_server(struct ksmbd_conn *conn) -{ - conn->vals = &smb311_server_values; - conn->ops = &smb3_11_server_ops; - conn->cmds = smb2_0_server_cmds; - conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds); - conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; - - if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; - - if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; - - INIT_LIST_HEAD(&conn->preauth_sess_table); - return 0; -} - -void init_smb2_max_read_size(unsigned int sz) -{ - sz = clamp_val(sz, SMB3_MIN_IOSIZE, SMB3_MAX_IOSIZE); - smb21_server_values.max_read_size = sz; - smb30_server_values.max_read_size = sz; - smb302_server_values.max_read_size = sz; - smb311_server_values.max_read_size = sz; -} - -void init_smb2_max_write_size(unsigned int sz) -{ - sz = clamp_val(sz, SMB3_MIN_IOSIZE, SMB3_MAX_IOSIZE); - smb21_server_values.max_write_size = sz; - smb30_server_values.max_write_size = sz; - smb302_server_values.max_write_size = sz; - smb311_server_values.max_write_size = sz; -} - -void init_smb2_max_trans_size(unsigned int sz) -{ - sz = clamp_val(sz, SMB3_MIN_IOSIZE, SMB3_MAX_IOSIZE); - smb21_server_values.max_trans_size = sz; - smb30_server_values.max_trans_size = sz; - smb302_server_values.max_trans_size = sz; - smb311_server_values.max_trans_size = sz; -} - -void init_smb2_max_credits(unsigned int sz) -{ - smb21_server_values.max_credits = sz; - smb30_server_values.max_credits = sz; - smb302_server_values.max_credits = sz; - smb311_server_values.max_credits = sz; -} diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c deleted file mode 100644 index 2b7c0ba6a77d..000000000000 --- a/fs/ksmbd/smb2pdu.c +++ /dev/null @@ -1,8727 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/inetdevice.h> -#include <net/addrconf.h> -#include <linux/syscalls.h> -#include <linux/namei.h> -#include <linux/statfs.h> -#include <linux/ethtool.h> -#include <linux/falloc.h> -#include <linux/mount.h> - -#include "glob.h" -#include "smbfsctl.h" -#include "oplock.h" -#include "smbacl.h" - -#include "auth.h" -#include "asn1.h" -#include "connection.h" -#include "transport_ipc.h" -#include "transport_rdma.h" -#include "vfs.h" -#include "vfs_cache.h" -#include "misc.h" - -#include "server.h" -#include "smb_common.h" -#include "smbstatus.h" -#include "ksmbd_work.h" -#include "mgmt/user_config.h" -#include "mgmt/share_config.h" -#include "mgmt/tree_connect.h" -#include "mgmt/user_session.h" -#include "mgmt/ksmbd_ida.h" -#include "ndr.h" - -static void __wbuf(struct ksmbd_work *work, void **req, void **rsp) -{ - if (work->next_smb2_rcv_hdr_off) { - *req = ksmbd_req_buf_next(work); - *rsp = ksmbd_resp_buf_next(work); - } else { - *req = smb2_get_msg(work->request_buf); - *rsp = smb2_get_msg(work->response_buf); - } -} - -#define WORK_BUFFERS(w, rq, rs) __wbuf((w), (void **)&(rq), (void **)&(rs)) - -/** - * check_session_id() - check for valid session id in smb header - * @conn: connection instance - * @id: session id from smb header - * - * Return: 1 if valid session id, otherwise 0 - */ -static inline bool check_session_id(struct ksmbd_conn *conn, u64 id) -{ - struct ksmbd_session *sess; - - if (id == 0 || id == -1) - return false; - - sess = ksmbd_session_lookup_all(conn, id); - if (sess) - return true; - pr_err("Invalid user session id: %llu\n", id); - return false; -} - -struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn *conn) -{ - return xa_load(&sess->ksmbd_chann_list, (long)conn); -} - -/** - * smb2_get_ksmbd_tcon() - get tree connection information using a tree id. - * @work: smb work - * - * Return: 0 if there is a tree connection matched or these are - * skipable commands, otherwise error - */ -int smb2_get_ksmbd_tcon(struct ksmbd_work *work) -{ - struct smb2_hdr *req_hdr = smb2_get_msg(work->request_buf); - unsigned int cmd = le16_to_cpu(req_hdr->Command); - int tree_id; - - if (cmd == SMB2_TREE_CONNECT_HE || - cmd == SMB2_CANCEL_HE || - cmd == SMB2_LOGOFF_HE) { - ksmbd_debug(SMB, "skip to check tree connect request\n"); - return 0; - } - - if (xa_empty(&work->sess->tree_conns)) { - ksmbd_debug(SMB, "NO tree connected\n"); - return -ENOENT; - } - - tree_id = le32_to_cpu(req_hdr->Id.SyncId.TreeId); - - /* - * If request is not the first in Compound request, - * Just validate tree id in header with work->tcon->id. - */ - if (work->next_smb2_rcv_hdr_off) { - if (!work->tcon) { - pr_err("The first operation in the compound does not have tcon\n"); - return -EINVAL; - } - if (work->tcon->id != tree_id) { - pr_err("tree id(%u) is different with id(%u) in first operation\n", - tree_id, work->tcon->id); - return -EINVAL; - } - return 1; - } - - work->tcon = ksmbd_tree_conn_lookup(work->sess, tree_id); - if (!work->tcon) { - pr_err("Invalid tid %d\n", tree_id); - return -ENOENT; - } - - return 1; -} - -/** - * smb2_set_err_rsp() - set error response code on smb response - * @work: smb work containing response buffer - */ -void smb2_set_err_rsp(struct ksmbd_work *work) -{ - struct smb2_err_rsp *err_rsp; - - if (work->next_smb2_rcv_hdr_off) - err_rsp = ksmbd_resp_buf_next(work); - else - err_rsp = smb2_get_msg(work->response_buf); - - if (err_rsp->hdr.Status != STATUS_STOPPED_ON_SYMLINK) { - err_rsp->StructureSize = SMB2_ERROR_STRUCTURE_SIZE2_LE; - err_rsp->ErrorContextCount = 0; - err_rsp->Reserved = 0; - err_rsp->ByteCount = 0; - err_rsp->ErrorData[0] = 0; - inc_rfc1001_len(work->response_buf, SMB2_ERROR_STRUCTURE_SIZE2); - } -} - -/** - * is_smb2_neg_cmd() - is it smb2 negotiation command - * @work: smb work containing smb header - * - * Return: true if smb2 negotiation command, otherwise false - */ -bool is_smb2_neg_cmd(struct ksmbd_work *work) -{ - struct smb2_hdr *hdr = smb2_get_msg(work->request_buf); - - /* is it SMB2 header ? */ - if (hdr->ProtocolId != SMB2_PROTO_NUMBER) - return false; - - /* make sure it is request not response message */ - if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) - return false; - - if (hdr->Command != SMB2_NEGOTIATE) - return false; - - return true; -} - -/** - * is_smb2_rsp() - is it smb2 response - * @work: smb work containing smb response buffer - * - * Return: true if smb2 response, otherwise false - */ -bool is_smb2_rsp(struct ksmbd_work *work) -{ - struct smb2_hdr *hdr = smb2_get_msg(work->response_buf); - - /* is it SMB2 header ? */ - if (hdr->ProtocolId != SMB2_PROTO_NUMBER) - return false; - - /* make sure it is response not request message */ - if (!(hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)) - return false; - - return true; -} - -/** - * get_smb2_cmd_val() - get smb command code from smb header - * @work: smb work containing smb request buffer - * - * Return: smb2 request command value - */ -u16 get_smb2_cmd_val(struct ksmbd_work *work) -{ - struct smb2_hdr *rcv_hdr; - - if (work->next_smb2_rcv_hdr_off) - rcv_hdr = ksmbd_req_buf_next(work); - else - rcv_hdr = smb2_get_msg(work->request_buf); - return le16_to_cpu(rcv_hdr->Command); -} - -/** - * set_smb2_rsp_status() - set error response code on smb2 header - * @work: smb work containing response buffer - * @err: error response code - */ -void set_smb2_rsp_status(struct ksmbd_work *work, __le32 err) -{ - struct smb2_hdr *rsp_hdr; - - if (work->next_smb2_rcv_hdr_off) - rsp_hdr = ksmbd_resp_buf_next(work); - else - rsp_hdr = smb2_get_msg(work->response_buf); - rsp_hdr->Status = err; - smb2_set_err_rsp(work); -} - -/** - * init_smb2_neg_rsp() - initialize smb2 response for negotiate command - * @work: smb work containing smb request buffer - * - * smb2 negotiate response is sent in reply of smb1 negotiate command for - * dialect auto-negotiation. - */ -int init_smb2_neg_rsp(struct ksmbd_work *work) -{ - struct smb2_hdr *rsp_hdr; - struct smb2_negotiate_rsp *rsp; - struct ksmbd_conn *conn = work->conn; - - *(__be32 *)work->response_buf = - cpu_to_be32(conn->vals->header_size); - - rsp_hdr = smb2_get_msg(work->response_buf); - memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); - rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; - rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; - rsp_hdr->CreditRequest = cpu_to_le16(2); - rsp_hdr->Command = SMB2_NEGOTIATE; - rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR); - rsp_hdr->NextCommand = 0; - rsp_hdr->MessageId = 0; - rsp_hdr->Id.SyncId.ProcessId = 0; - rsp_hdr->Id.SyncId.TreeId = 0; - rsp_hdr->SessionId = 0; - memset(rsp_hdr->Signature, 0, 16); - - rsp = smb2_get_msg(work->response_buf); - - WARN_ON(ksmbd_conn_good(conn)); - - rsp->StructureSize = cpu_to_le16(65); - ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect); - rsp->DialectRevision = cpu_to_le16(conn->dialect); - /* Not setting conn guid rsp->ServerGUID, as it - * not used by client for identifying connection - */ - rsp->Capabilities = cpu_to_le32(conn->vals->capabilities); - /* Default Max Message Size till SMB2.0, 64K*/ - rsp->MaxTransactSize = cpu_to_le32(conn->vals->max_trans_size); - rsp->MaxReadSize = cpu_to_le32(conn->vals->max_read_size); - rsp->MaxWriteSize = cpu_to_le32(conn->vals->max_write_size); - - rsp->SystemTime = cpu_to_le64(ksmbd_systime()); - rsp->ServerStartTime = 0; - - rsp->SecurityBufferOffset = cpu_to_le16(128); - rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH); - ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) + - le16_to_cpu(rsp->SecurityBufferOffset)); - inc_rfc1001_len(work->response_buf, - sizeof(struct smb2_negotiate_rsp) - - sizeof(struct smb2_hdr) - sizeof(rsp->Buffer) + - AUTH_GSS_LENGTH); - rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE; - if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY) - rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE; - conn->use_spnego = true; - - ksmbd_conn_set_need_negotiate(conn); - return 0; -} - -/** - * smb2_set_rsp_credits() - set number of credits in response buffer - * @work: smb work containing smb response buffer - */ -int smb2_set_rsp_credits(struct ksmbd_work *work) -{ - struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work); - struct smb2_hdr *hdr = ksmbd_resp_buf_next(work); - struct ksmbd_conn *conn = work->conn; - unsigned short credits_requested, aux_max; - unsigned short credit_charge, credits_granted = 0; - - if (work->send_no_response) - return 0; - - hdr->CreditCharge = req_hdr->CreditCharge; - - if (conn->total_credits > conn->vals->max_credits) { - hdr->CreditRequest = 0; - pr_err("Total credits overflow: %d\n", conn->total_credits); - return -EINVAL; - } - - credit_charge = max_t(unsigned short, - le16_to_cpu(req_hdr->CreditCharge), 1); - if (credit_charge > conn->total_credits) { - ksmbd_debug(SMB, "Insufficient credits granted, given: %u, granted: %u\n", - credit_charge, conn->total_credits); - return -EINVAL; - } - - conn->total_credits -= credit_charge; - conn->outstanding_credits -= credit_charge; - credits_requested = max_t(unsigned short, - le16_to_cpu(req_hdr->CreditRequest), 1); - - /* according to smb2.credits smbtorture, Windows server - * 2016 or later grant up to 8192 credits at once. - * - * TODO: Need to adjuct CreditRequest value according to - * current cpu load - */ - if (hdr->Command == SMB2_NEGOTIATE) - aux_max = 1; - else - aux_max = conn->vals->max_credits - conn->total_credits; - credits_granted = min_t(unsigned short, credits_requested, aux_max); - - conn->total_credits += credits_granted; - work->credits_granted += credits_granted; - - if (!req_hdr->NextCommand) { - /* Update CreditRequest in last request */ - hdr->CreditRequest = cpu_to_le16(work->credits_granted); - } - ksmbd_debug(SMB, - "credits: requested[%d] granted[%d] total_granted[%d]\n", - credits_requested, credits_granted, - conn->total_credits); - return 0; -} - -/** - * init_chained_smb2_rsp() - initialize smb2 chained response - * @work: smb work containing smb response buffer - */ -static void init_chained_smb2_rsp(struct ksmbd_work *work) -{ - struct smb2_hdr *req = ksmbd_req_buf_next(work); - struct smb2_hdr *rsp = ksmbd_resp_buf_next(work); - struct smb2_hdr *rsp_hdr; - struct smb2_hdr *rcv_hdr; - int next_hdr_offset = 0; - int len, new_len; - - /* Len of this response = updated RFC len - offset of previous cmd - * in the compound rsp - */ - - /* Storing the current local FID which may be needed by subsequent - * command in the compound request - */ - if (req->Command == SMB2_CREATE && rsp->Status == STATUS_SUCCESS) { - work->compound_fid = ((struct smb2_create_rsp *)rsp)->VolatileFileId; - work->compound_pfid = ((struct smb2_create_rsp *)rsp)->PersistentFileId; - work->compound_sid = le64_to_cpu(rsp->SessionId); - } - - len = get_rfc1002_len(work->response_buf) - work->next_smb2_rsp_hdr_off; - next_hdr_offset = le32_to_cpu(req->NextCommand); - - new_len = ALIGN(len, 8); - inc_rfc1001_len(work->response_buf, - sizeof(struct smb2_hdr) + new_len - len); - rsp->NextCommand = cpu_to_le32(new_len); - - work->next_smb2_rcv_hdr_off += next_hdr_offset; - work->next_smb2_rsp_hdr_off += new_len; - ksmbd_debug(SMB, - "Compound req new_len = %d rcv off = %d rsp off = %d\n", - new_len, work->next_smb2_rcv_hdr_off, - work->next_smb2_rsp_hdr_off); - - rsp_hdr = ksmbd_resp_buf_next(work); - rcv_hdr = ksmbd_req_buf_next(work); - - if (!(rcv_hdr->Flags & SMB2_FLAGS_RELATED_OPERATIONS)) { - ksmbd_debug(SMB, "related flag should be set\n"); - work->compound_fid = KSMBD_NO_FID; - work->compound_pfid = KSMBD_NO_FID; - } - memset((char *)rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); - rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; - rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; - rsp_hdr->Command = rcv_hdr->Command; - - /* - * Message is response. We don't grant oplock yet. - */ - rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR | - SMB2_FLAGS_RELATED_OPERATIONS); - rsp_hdr->NextCommand = 0; - rsp_hdr->MessageId = rcv_hdr->MessageId; - rsp_hdr->Id.SyncId.ProcessId = rcv_hdr->Id.SyncId.ProcessId; - rsp_hdr->Id.SyncId.TreeId = rcv_hdr->Id.SyncId.TreeId; - rsp_hdr->SessionId = rcv_hdr->SessionId; - memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16); -} - -/** - * is_chained_smb2_message() - check for chained command - * @work: smb work containing smb request buffer - * - * Return: true if chained request, otherwise false - */ -bool is_chained_smb2_message(struct ksmbd_work *work) -{ - struct smb2_hdr *hdr = smb2_get_msg(work->request_buf); - unsigned int len, next_cmd; - - if (hdr->ProtocolId != SMB2_PROTO_NUMBER) - return false; - - hdr = ksmbd_req_buf_next(work); - next_cmd = le32_to_cpu(hdr->NextCommand); - if (next_cmd > 0) { - if ((u64)work->next_smb2_rcv_hdr_off + next_cmd + - __SMB2_HEADER_STRUCTURE_SIZE > - get_rfc1002_len(work->request_buf)) { - pr_err("next command(%u) offset exceeds smb msg size\n", - next_cmd); - return false; - } - - if ((u64)get_rfc1002_len(work->response_buf) + MAX_CIFS_SMALL_BUFFER_SIZE > - work->response_sz) { - pr_err("next response offset exceeds response buffer size\n"); - return false; - } - - ksmbd_debug(SMB, "got SMB2 chained command\n"); - init_chained_smb2_rsp(work); - return true; - } else if (work->next_smb2_rcv_hdr_off) { - /* - * This is last request in chained command, - * align response to 8 byte - */ - len = ALIGN(get_rfc1002_len(work->response_buf), 8); - len = len - get_rfc1002_len(work->response_buf); - if (len) { - ksmbd_debug(SMB, "padding len %u\n", len); - inc_rfc1001_len(work->response_buf, len); - if (work->aux_payload_sz) - work->aux_payload_sz += len; - } - } - return false; -} - -/** - * init_smb2_rsp_hdr() - initialize smb2 response - * @work: smb work containing smb request buffer - * - * Return: 0 - */ -int init_smb2_rsp_hdr(struct ksmbd_work *work) -{ - struct smb2_hdr *rsp_hdr = smb2_get_msg(work->response_buf); - struct smb2_hdr *rcv_hdr = smb2_get_msg(work->request_buf); - struct ksmbd_conn *conn = work->conn; - - memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); - *(__be32 *)work->response_buf = - cpu_to_be32(conn->vals->header_size); - rsp_hdr->ProtocolId = rcv_hdr->ProtocolId; - rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; - rsp_hdr->Command = rcv_hdr->Command; - - /* - * Message is response. We don't grant oplock yet. - */ - rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR); - rsp_hdr->NextCommand = 0; - rsp_hdr->MessageId = rcv_hdr->MessageId; - rsp_hdr->Id.SyncId.ProcessId = rcv_hdr->Id.SyncId.ProcessId; - rsp_hdr->Id.SyncId.TreeId = rcv_hdr->Id.SyncId.TreeId; - rsp_hdr->SessionId = rcv_hdr->SessionId; - memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16); - - work->syncronous = true; - if (work->async_id) { - ksmbd_release_id(&conn->async_ida, work->async_id); - work->async_id = 0; - } - - return 0; -} - -/** - * smb2_allocate_rsp_buf() - allocate smb2 response buffer - * @work: smb work containing smb request buffer - * - * Return: 0 on success, otherwise -ENOMEM - */ -int smb2_allocate_rsp_buf(struct ksmbd_work *work) -{ - struct smb2_hdr *hdr = smb2_get_msg(work->request_buf); - size_t small_sz = MAX_CIFS_SMALL_BUFFER_SIZE; - size_t large_sz = small_sz + work->conn->vals->max_trans_size; - size_t sz = small_sz; - int cmd = le16_to_cpu(hdr->Command); - - if (cmd == SMB2_IOCTL_HE || cmd == SMB2_QUERY_DIRECTORY_HE) - sz = large_sz; - - if (cmd == SMB2_QUERY_INFO_HE) { - struct smb2_query_info_req *req; - - req = smb2_get_msg(work->request_buf); - if ((req->InfoType == SMB2_O_INFO_FILE && - (req->FileInfoClass == FILE_FULL_EA_INFORMATION || - req->FileInfoClass == FILE_ALL_INFORMATION)) || - req->InfoType == SMB2_O_INFO_SECURITY) - sz = large_sz; - } - - /* allocate large response buf for chained commands */ - if (le32_to_cpu(hdr->NextCommand) > 0) - sz = large_sz; - - work->response_buf = kvmalloc(sz, GFP_KERNEL | __GFP_ZERO); - if (!work->response_buf) - return -ENOMEM; - - work->response_sz = sz; - return 0; -} - -/** - * smb2_check_user_session() - check for valid session for a user - * @work: smb work containing smb request buffer - * - * Return: 0 on success, otherwise error - */ -int smb2_check_user_session(struct ksmbd_work *work) -{ - struct smb2_hdr *req_hdr = smb2_get_msg(work->request_buf); - struct ksmbd_conn *conn = work->conn; - unsigned int cmd = conn->ops->get_cmd_val(work); - unsigned long long sess_id; - - /* - * SMB2_ECHO, SMB2_NEGOTIATE, SMB2_SESSION_SETUP command do not - * require a session id, so no need to validate user session's for - * these commands. - */ - if (cmd == SMB2_ECHO_HE || cmd == SMB2_NEGOTIATE_HE || - cmd == SMB2_SESSION_SETUP_HE) - return 0; - - if (!ksmbd_conn_good(conn)) - return -EIO; - - sess_id = le64_to_cpu(req_hdr->SessionId); - - /* - * If request is not the first in Compound request, - * Just validate session id in header with work->sess->id. - */ - if (work->next_smb2_rcv_hdr_off) { - if (!work->sess) { - pr_err("The first operation in the compound does not have sess\n"); - return -EINVAL; - } - if (work->sess->id != sess_id) { - pr_err("session id(%llu) is different with the first operation(%lld)\n", - sess_id, work->sess->id); - return -EINVAL; - } - return 1; - } - - /* Check for validity of user session */ - work->sess = ksmbd_session_lookup_all(conn, sess_id); - if (work->sess) - return 1; - ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id); - return -ENOENT; -} - -static void destroy_previous_session(struct ksmbd_conn *conn, - struct ksmbd_user *user, u64 id) -{ - struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id); - struct ksmbd_user *prev_user; - struct channel *chann; - long index; - - if (!prev_sess) - return; - - prev_user = prev_sess->user; - - if (!prev_user || - strcmp(user->name, prev_user->name) || - user->passkey_sz != prev_user->passkey_sz || - memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) - return; - - prev_sess->state = SMB2_SESSION_EXPIRED; - xa_for_each(&prev_sess->ksmbd_chann_list, index, chann) - ksmbd_conn_set_exiting(chann->conn); -} - -/** - * smb2_get_name() - get filename string from on the wire smb format - * @src: source buffer - * @maxlen: maxlen of source string - * @local_nls: nls_table pointer - * - * Return: matching converted filename on success, otherwise error ptr - */ -static char * -smb2_get_name(const char *src, const int maxlen, struct nls_table *local_nls) -{ - char *name; - - name = smb_strndup_from_utf16(src, maxlen, 1, local_nls); - if (IS_ERR(name)) { - pr_err("failed to get name %ld\n", PTR_ERR(name)); - return name; - } - - ksmbd_conv_path_to_unix(name); - ksmbd_strip_last_slash(name); - return name; -} - -int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg) -{ - struct smb2_hdr *rsp_hdr; - struct ksmbd_conn *conn = work->conn; - int id; - - rsp_hdr = smb2_get_msg(work->response_buf); - rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND; - - id = ksmbd_acquire_async_msg_id(&conn->async_ida); - if (id < 0) { - pr_err("Failed to alloc async message id\n"); - return id; - } - work->syncronous = false; - work->async_id = id; - rsp_hdr->Id.AsyncId = cpu_to_le64(id); - - ksmbd_debug(SMB, - "Send interim Response to inform async request id : %d\n", - work->async_id); - - work->cancel_fn = fn; - work->cancel_argv = arg; - - if (list_empty(&work->async_request_entry)) { - spin_lock(&conn->request_lock); - list_add_tail(&work->async_request_entry, &conn->async_requests); - spin_unlock(&conn->request_lock); - } - - return 0; -} - -void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status) -{ - struct smb2_hdr *rsp_hdr; - - rsp_hdr = smb2_get_msg(work->response_buf); - smb2_set_err_rsp(work); - rsp_hdr->Status = status; - - work->multiRsp = 1; - ksmbd_conn_write(work); - rsp_hdr->Status = 0; - work->multiRsp = 0; -} - -static __le32 smb2_get_reparse_tag_special_file(umode_t mode) -{ - if (S_ISDIR(mode) || S_ISREG(mode)) - return 0; - - if (S_ISLNK(mode)) - return IO_REPARSE_TAG_LX_SYMLINK_LE; - else if (S_ISFIFO(mode)) - return IO_REPARSE_TAG_LX_FIFO_LE; - else if (S_ISSOCK(mode)) - return IO_REPARSE_TAG_AF_UNIX_LE; - else if (S_ISCHR(mode)) - return IO_REPARSE_TAG_LX_CHR_LE; - else if (S_ISBLK(mode)) - return IO_REPARSE_TAG_LX_BLK_LE; - - return 0; -} - -/** - * smb2_get_dos_mode() - get file mode in dos format from unix mode - * @stat: kstat containing file mode - * @attribute: attribute flags - * - * Return: converted dos mode - */ -static int smb2_get_dos_mode(struct kstat *stat, int attribute) -{ - int attr = 0; - - if (S_ISDIR(stat->mode)) { - attr = FILE_ATTRIBUTE_DIRECTORY | - (attribute & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)); - } else { - attr = (attribute & 0x00005137) | FILE_ATTRIBUTE_ARCHIVE; - attr &= ~(FILE_ATTRIBUTE_DIRECTORY); - if (S_ISREG(stat->mode) && (server_conf.share_fake_fscaps & - FILE_SUPPORTS_SPARSE_FILES)) - attr |= FILE_ATTRIBUTE_SPARSE_FILE; - - if (smb2_get_reparse_tag_special_file(stat->mode)) - attr |= FILE_ATTRIBUTE_REPARSE_POINT; - } - - return attr; -} - -static void build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt, - __le16 hash_id) -{ - pneg_ctxt->ContextType = SMB2_PREAUTH_INTEGRITY_CAPABILITIES; - pneg_ctxt->DataLength = cpu_to_le16(38); - pneg_ctxt->HashAlgorithmCount = cpu_to_le16(1); - pneg_ctxt->Reserved = cpu_to_le32(0); - pneg_ctxt->SaltLength = cpu_to_le16(SMB311_SALT_SIZE); - get_random_bytes(pneg_ctxt->Salt, SMB311_SALT_SIZE); - pneg_ctxt->HashAlgorithms = hash_id; -} - -static void build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt, - __le16 cipher_type) -{ - pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES; - pneg_ctxt->DataLength = cpu_to_le16(4); - pneg_ctxt->Reserved = cpu_to_le32(0); - pneg_ctxt->CipherCount = cpu_to_le16(1); - pneg_ctxt->Ciphers[0] = cipher_type; -} - -static void build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt, - __le16 comp_algo) -{ - pneg_ctxt->ContextType = SMB2_COMPRESSION_CAPABILITIES; - pneg_ctxt->DataLength = - cpu_to_le16(sizeof(struct smb2_compression_capabilities_context) - - sizeof(struct smb2_neg_context)); - pneg_ctxt->Reserved = cpu_to_le32(0); - pneg_ctxt->CompressionAlgorithmCount = cpu_to_le16(1); - pneg_ctxt->Flags = cpu_to_le32(0); - pneg_ctxt->CompressionAlgorithms[0] = comp_algo; -} - -static void build_sign_cap_ctxt(struct smb2_signing_capabilities *pneg_ctxt, - __le16 sign_algo) -{ - pneg_ctxt->ContextType = SMB2_SIGNING_CAPABILITIES; - pneg_ctxt->DataLength = - cpu_to_le16((sizeof(struct smb2_signing_capabilities) + 2) - - sizeof(struct smb2_neg_context)); - pneg_ctxt->Reserved = cpu_to_le32(0); - pneg_ctxt->SigningAlgorithmCount = cpu_to_le16(1); - pneg_ctxt->SigningAlgorithms[0] = sign_algo; -} - -static void build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt) -{ - pneg_ctxt->ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE; - pneg_ctxt->DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN); - /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */ - pneg_ctxt->Name[0] = 0x93; - pneg_ctxt->Name[1] = 0xAD; - pneg_ctxt->Name[2] = 0x25; - pneg_ctxt->Name[3] = 0x50; - pneg_ctxt->Name[4] = 0x9C; - pneg_ctxt->Name[5] = 0xB4; - pneg_ctxt->Name[6] = 0x11; - pneg_ctxt->Name[7] = 0xE7; - pneg_ctxt->Name[8] = 0xB4; - pneg_ctxt->Name[9] = 0x23; - pneg_ctxt->Name[10] = 0x83; - pneg_ctxt->Name[11] = 0xDE; - pneg_ctxt->Name[12] = 0x96; - pneg_ctxt->Name[13] = 0x8B; - pneg_ctxt->Name[14] = 0xCD; - pneg_ctxt->Name[15] = 0x7C; -} - -static void assemble_neg_contexts(struct ksmbd_conn *conn, - struct smb2_negotiate_rsp *rsp, - void *smb2_buf_len) -{ - char *pneg_ctxt = (char *)rsp + - le32_to_cpu(rsp->NegotiateContextOffset); - int neg_ctxt_cnt = 1; - int ctxt_size; - - ksmbd_debug(SMB, - "assemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n"); - build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt, - conn->preauth_info->Preauth_HashId); - rsp->NegotiateContextCount = cpu_to_le16(neg_ctxt_cnt); - inc_rfc1001_len(smb2_buf_len, AUTH_GSS_PADDING); - ctxt_size = sizeof(struct smb2_preauth_neg_context); - /* Round to 8 byte boundary */ - pneg_ctxt += round_up(sizeof(struct smb2_preauth_neg_context), 8); - - if (conn->cipher_type) { - ctxt_size = round_up(ctxt_size, 8); - ksmbd_debug(SMB, - "assemble SMB2_ENCRYPTION_CAPABILITIES context\n"); - build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt, - conn->cipher_type); - rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); - ctxt_size += sizeof(struct smb2_encryption_neg_context) + 2; - /* Round to 8 byte boundary */ - pneg_ctxt += - round_up(sizeof(struct smb2_encryption_neg_context) + 2, - 8); - } - - if (conn->compress_algorithm) { - ctxt_size = round_up(ctxt_size, 8); - ksmbd_debug(SMB, - "assemble SMB2_COMPRESSION_CAPABILITIES context\n"); - /* Temporarily set to SMB3_COMPRESS_NONE */ - build_compression_ctxt((struct smb2_compression_capabilities_context *)pneg_ctxt, - conn->compress_algorithm); - rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); - ctxt_size += sizeof(struct smb2_compression_capabilities_context) + 2; - /* Round to 8 byte boundary */ - pneg_ctxt += round_up(sizeof(struct smb2_compression_capabilities_context) + 2, - 8); - } - - if (conn->posix_ext_supported) { - ctxt_size = round_up(ctxt_size, 8); - ksmbd_debug(SMB, - "assemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n"); - build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt); - rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); - ctxt_size += sizeof(struct smb2_posix_neg_context); - /* Round to 8 byte boundary */ - pneg_ctxt += round_up(sizeof(struct smb2_posix_neg_context), 8); - } - - if (conn->signing_negotiated) { - ctxt_size = round_up(ctxt_size, 8); - ksmbd_debug(SMB, - "assemble SMB2_SIGNING_CAPABILITIES context\n"); - build_sign_cap_ctxt((struct smb2_signing_capabilities *)pneg_ctxt, - conn->signing_algorithm); - rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); - ctxt_size += sizeof(struct smb2_signing_capabilities) + 2; - } - - inc_rfc1001_len(smb2_buf_len, ctxt_size); -} - -static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn, - struct smb2_preauth_neg_context *pneg_ctxt, - int ctxt_len) -{ - /* - * sizeof(smb2_preauth_neg_context) assumes SMB311_SALT_SIZE Salt, - * which may not be present. Only check for used HashAlgorithms[1]. - */ - if (ctxt_len < - sizeof(struct smb2_neg_context) + MIN_PREAUTH_CTXT_DATA_LEN) - return STATUS_INVALID_PARAMETER; - - if (pneg_ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512) - return STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP; - - conn->preauth_info->Preauth_HashId = SMB2_PREAUTH_INTEGRITY_SHA512; - return STATUS_SUCCESS; -} - -static void decode_encrypt_ctxt(struct ksmbd_conn *conn, - struct smb2_encryption_neg_context *pneg_ctxt, - int ctxt_len) -{ - int cph_cnt; - int i, cphs_size; - - if (sizeof(struct smb2_encryption_neg_context) > ctxt_len) { - pr_err("Invalid SMB2_ENCRYPTION_CAPABILITIES context size\n"); - return; - } - - conn->cipher_type = 0; - - cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount); - cphs_size = cph_cnt * sizeof(__le16); - - if (sizeof(struct smb2_encryption_neg_context) + cphs_size > - ctxt_len) { - pr_err("Invalid cipher count(%d)\n", cph_cnt); - return; - } - - if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION)) - return; - - for (i = 0; i < cph_cnt; i++) { - if (pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_GCM || - pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_CCM || - pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES256_CCM || - pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES256_GCM) { - ksmbd_debug(SMB, "Cipher ID = 0x%x\n", - pneg_ctxt->Ciphers[i]); - conn->cipher_type = pneg_ctxt->Ciphers[i]; - break; - } - } -} - -/** - * smb3_encryption_negotiated() - checks if server and client agreed on enabling encryption - * @conn: smb connection - * - * Return: true if connection should be encrypted, else false - */ -bool smb3_encryption_negotiated(struct ksmbd_conn *conn) -{ - if (!conn->ops->generate_encryptionkey) - return false; - - /* - * SMB 3.0 and 3.0.2 dialects use the SMB2_GLOBAL_CAP_ENCRYPTION flag. - * SMB 3.1.1 uses the cipher_type field. - */ - return (conn->vals->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) || - conn->cipher_type; -} - -static void decode_compress_ctxt(struct ksmbd_conn *conn, - struct smb2_compression_capabilities_context *pneg_ctxt) -{ - conn->compress_algorithm = SMB3_COMPRESS_NONE; -} - -static void decode_sign_cap_ctxt(struct ksmbd_conn *conn, - struct smb2_signing_capabilities *pneg_ctxt, - int ctxt_len) -{ - int sign_algo_cnt; - int i, sign_alos_size; - - if (sizeof(struct smb2_signing_capabilities) > ctxt_len) { - pr_err("Invalid SMB2_SIGNING_CAPABILITIES context length\n"); - return; - } - - conn->signing_negotiated = false; - sign_algo_cnt = le16_to_cpu(pneg_ctxt->SigningAlgorithmCount); - sign_alos_size = sign_algo_cnt * sizeof(__le16); - - if (sizeof(struct smb2_signing_capabilities) + sign_alos_size > - ctxt_len) { - pr_err("Invalid signing algorithm count(%d)\n", sign_algo_cnt); - return; - } - - for (i = 0; i < sign_algo_cnt; i++) { - if (pneg_ctxt->SigningAlgorithms[i] == SIGNING_ALG_HMAC_SHA256_LE || - pneg_ctxt->SigningAlgorithms[i] == SIGNING_ALG_AES_CMAC_LE) { - ksmbd_debug(SMB, "Signing Algorithm ID = 0x%x\n", - pneg_ctxt->SigningAlgorithms[i]); - conn->signing_negotiated = true; - conn->signing_algorithm = - pneg_ctxt->SigningAlgorithms[i]; - break; - } - } -} - -static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn, - struct smb2_negotiate_req *req, - unsigned int len_of_smb) -{ - /* +4 is to account for the RFC1001 len field */ - struct smb2_neg_context *pctx = (struct smb2_neg_context *)req; - int i = 0, len_of_ctxts; - unsigned int offset = le32_to_cpu(req->NegotiateContextOffset); - unsigned int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount); - __le32 status = STATUS_INVALID_PARAMETER; - - ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt); - if (len_of_smb <= offset) { - ksmbd_debug(SMB, "Invalid response: negotiate context offset\n"); - return status; - } - - len_of_ctxts = len_of_smb - offset; - - while (i++ < neg_ctxt_cnt) { - int clen, ctxt_len; - - if (len_of_ctxts < (int)sizeof(struct smb2_neg_context)) - break; - - pctx = (struct smb2_neg_context *)((char *)pctx + offset); - clen = le16_to_cpu(pctx->DataLength); - ctxt_len = clen + sizeof(struct smb2_neg_context); - - if (ctxt_len > len_of_ctxts) - break; - - if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) { - ksmbd_debug(SMB, - "deassemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n"); - if (conn->preauth_info->Preauth_HashId) - break; - - status = decode_preauth_ctxt(conn, - (struct smb2_preauth_neg_context *)pctx, - ctxt_len); - if (status != STATUS_SUCCESS) - break; - } else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) { - ksmbd_debug(SMB, - "deassemble SMB2_ENCRYPTION_CAPABILITIES context\n"); - if (conn->cipher_type) - break; - - decode_encrypt_ctxt(conn, - (struct smb2_encryption_neg_context *)pctx, - ctxt_len); - } else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) { - ksmbd_debug(SMB, - "deassemble SMB2_COMPRESSION_CAPABILITIES context\n"); - if (conn->compress_algorithm) - break; - - decode_compress_ctxt(conn, - (struct smb2_compression_capabilities_context *)pctx); - } else if (pctx->ContextType == SMB2_NETNAME_NEGOTIATE_CONTEXT_ID) { - ksmbd_debug(SMB, - "deassemble SMB2_NETNAME_NEGOTIATE_CONTEXT_ID context\n"); - } else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) { - ksmbd_debug(SMB, - "deassemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n"); - conn->posix_ext_supported = true; - } else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES) { - ksmbd_debug(SMB, - "deassemble SMB2_SIGNING_CAPABILITIES context\n"); - - decode_sign_cap_ctxt(conn, - (struct smb2_signing_capabilities *)pctx, - ctxt_len); - } - - /* offsets must be 8 byte aligned */ - offset = (ctxt_len + 7) & ~0x7; - len_of_ctxts -= offset; - } - return status; -} - -/** - * smb2_handle_negotiate() - handler for smb2 negotiate command - * @work: smb work containing smb request buffer - * - * Return: 0 - */ -int smb2_handle_negotiate(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_negotiate_req *req = smb2_get_msg(work->request_buf); - struct smb2_negotiate_rsp *rsp = smb2_get_msg(work->response_buf); - int rc = 0; - unsigned int smb2_buf_len, smb2_neg_size; - __le32 status; - - ksmbd_debug(SMB, "Received negotiate request\n"); - conn->need_neg = false; - if (ksmbd_conn_good(conn)) { - pr_err("conn->tcp_status is already in CifsGood State\n"); - work->send_no_response = 1; - return rc; - } - - smb2_buf_len = get_rfc1002_len(work->request_buf); - smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects); - if (smb2_neg_size > smb2_buf_len) { - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - rc = -EINVAL; - goto err_out; - } - - if (req->DialectCount == 0) { - pr_err("malformed packet\n"); - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - rc = -EINVAL; - goto err_out; - } - - if (conn->dialect == SMB311_PROT_ID) { - unsigned int nego_ctxt_off = le32_to_cpu(req->NegotiateContextOffset); - - if (smb2_buf_len < nego_ctxt_off) { - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - rc = -EINVAL; - goto err_out; - } - - if (smb2_neg_size > nego_ctxt_off) { - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - rc = -EINVAL; - goto err_out; - } - - if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) > - nego_ctxt_off) { - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - rc = -EINVAL; - goto err_out; - } - } else { - if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) > - smb2_buf_len) { - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - rc = -EINVAL; - goto err_out; - } - } - - conn->cli_cap = le32_to_cpu(req->Capabilities); - switch (conn->dialect) { - case SMB311_PROT_ID: - conn->preauth_info = - kzalloc(sizeof(struct preauth_integrity_info), - GFP_KERNEL); - if (!conn->preauth_info) { - rc = -ENOMEM; - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - goto err_out; - } - - status = deassemble_neg_contexts(conn, req, - get_rfc1002_len(work->request_buf)); - if (status != STATUS_SUCCESS) { - pr_err("deassemble_neg_contexts error(0x%x)\n", - status); - rsp->hdr.Status = status; - rc = -EINVAL; - kfree(conn->preauth_info); - conn->preauth_info = NULL; - goto err_out; - } - - rc = init_smb3_11_server(conn); - if (rc < 0) { - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - kfree(conn->preauth_info); - conn->preauth_info = NULL; - goto err_out; - } - - ksmbd_gen_preauth_integrity_hash(conn, - work->request_buf, - conn->preauth_info->Preauth_HashValue); - rsp->NegotiateContextOffset = - cpu_to_le32(OFFSET_OF_NEG_CONTEXT); - assemble_neg_contexts(conn, rsp, work->response_buf); - break; - case SMB302_PROT_ID: - init_smb3_02_server(conn); - break; - case SMB30_PROT_ID: - init_smb3_0_server(conn); - break; - case SMB21_PROT_ID: - init_smb2_1_server(conn); - break; - case SMB2X_PROT_ID: - case BAD_PROT_ID: - default: - ksmbd_debug(SMB, "Server dialect :0x%x not supported\n", - conn->dialect); - rsp->hdr.Status = STATUS_NOT_SUPPORTED; - rc = -EINVAL; - goto err_out; - } - rsp->Capabilities = cpu_to_le32(conn->vals->capabilities); - - /* For stats */ - conn->connection_type = conn->dialect; - - rsp->MaxTransactSize = cpu_to_le32(conn->vals->max_trans_size); - rsp->MaxReadSize = cpu_to_le32(conn->vals->max_read_size); - rsp->MaxWriteSize = cpu_to_le32(conn->vals->max_write_size); - - memcpy(conn->ClientGUID, req->ClientGUID, - SMB2_CLIENT_GUID_SIZE); - conn->cli_sec_mode = le16_to_cpu(req->SecurityMode); - - rsp->StructureSize = cpu_to_le16(65); - rsp->DialectRevision = cpu_to_le16(conn->dialect); - /* Not setting conn guid rsp->ServerGUID, as it - * not used by client for identifying server - */ - memset(rsp->ServerGUID, 0, SMB2_CLIENT_GUID_SIZE); - - rsp->SystemTime = cpu_to_le64(ksmbd_systime()); - rsp->ServerStartTime = 0; - ksmbd_debug(SMB, "negotiate context offset %d, count %d\n", - le32_to_cpu(rsp->NegotiateContextOffset), - le16_to_cpu(rsp->NegotiateContextCount)); - - rsp->SecurityBufferOffset = cpu_to_le16(128); - rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH); - ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) + - le16_to_cpu(rsp->SecurityBufferOffset)); - inc_rfc1001_len(work->response_buf, sizeof(struct smb2_negotiate_rsp) - - sizeof(struct smb2_hdr) - sizeof(rsp->Buffer) + - AUTH_GSS_LENGTH); - rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE; - conn->use_spnego = true; - - if ((server_conf.signing == KSMBD_CONFIG_OPT_AUTO || - server_conf.signing == KSMBD_CONFIG_OPT_DISABLED) && - req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED_LE) - conn->sign = true; - else if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY) { - server_conf.enforced_signing = true; - rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE; - conn->sign = true; - } - - conn->srv_sec_mode = le16_to_cpu(rsp->SecurityMode); - ksmbd_conn_set_need_negotiate(conn); - -err_out: - if (rc < 0) - smb2_set_err_rsp(work); - - return rc; -} - -static int alloc_preauth_hash(struct ksmbd_session *sess, - struct ksmbd_conn *conn) -{ - if (sess->Preauth_HashValue) - return 0; - - sess->Preauth_HashValue = kmemdup(conn->preauth_info->Preauth_HashValue, - PREAUTH_HASHVALUE_SIZE, GFP_KERNEL); - if (!sess->Preauth_HashValue) - return -ENOMEM; - - return 0; -} - -static int generate_preauth_hash(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct ksmbd_session *sess = work->sess; - u8 *preauth_hash; - - if (conn->dialect != SMB311_PROT_ID) - return 0; - - if (conn->binding) { - struct preauth_session *preauth_sess; - - preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id); - if (!preauth_sess) { - preauth_sess = ksmbd_preauth_session_alloc(conn, sess->id); - if (!preauth_sess) - return -ENOMEM; - } - - preauth_hash = preauth_sess->Preauth_HashValue; - } else { - if (!sess->Preauth_HashValue) - if (alloc_preauth_hash(sess, conn)) - return -ENOMEM; - preauth_hash = sess->Preauth_HashValue; - } - - ksmbd_gen_preauth_integrity_hash(conn, work->request_buf, preauth_hash); - return 0; -} - -static int decode_negotiation_token(struct ksmbd_conn *conn, - struct negotiate_message *negblob, - size_t sz) -{ - if (!conn->use_spnego) - return -EINVAL; - - if (ksmbd_decode_negTokenInit((char *)negblob, sz, conn)) { - if (ksmbd_decode_negTokenTarg((char *)negblob, sz, conn)) { - conn->auth_mechs |= KSMBD_AUTH_NTLMSSP; - conn->preferred_auth_mech = KSMBD_AUTH_NTLMSSP; - conn->use_spnego = false; - } - } - return 0; -} - -static int ntlm_negotiate(struct ksmbd_work *work, - struct negotiate_message *negblob, - size_t negblob_len) -{ - struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); - struct challenge_message *chgblob; - unsigned char *spnego_blob = NULL; - u16 spnego_blob_len; - char *neg_blob; - int sz, rc; - - ksmbd_debug(SMB, "negotiate phase\n"); - rc = ksmbd_decode_ntlmssp_neg_blob(negblob, negblob_len, work->conn); - if (rc) - return rc; - - sz = le16_to_cpu(rsp->SecurityBufferOffset); - chgblob = - (struct challenge_message *)((char *)&rsp->hdr.ProtocolId + sz); - memset(chgblob, 0, sizeof(struct challenge_message)); - - if (!work->conn->use_spnego) { - sz = ksmbd_build_ntlmssp_challenge_blob(chgblob, work->conn); - if (sz < 0) - return -ENOMEM; - - rsp->SecurityBufferLength = cpu_to_le16(sz); - return 0; - } - - sz = sizeof(struct challenge_message); - sz += (strlen(ksmbd_netbios_name()) * 2 + 1 + 4) * 6; - - neg_blob = kzalloc(sz, GFP_KERNEL); - if (!neg_blob) - return -ENOMEM; - - chgblob = (struct challenge_message *)neg_blob; - sz = ksmbd_build_ntlmssp_challenge_blob(chgblob, work->conn); - if (sz < 0) { - rc = -ENOMEM; - goto out; - } - - rc = build_spnego_ntlmssp_neg_blob(&spnego_blob, &spnego_blob_len, - neg_blob, sz); - if (rc) { - rc = -ENOMEM; - goto out; - } - - sz = le16_to_cpu(rsp->SecurityBufferOffset); - memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len); - rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len); - -out: - kfree(spnego_blob); - kfree(neg_blob); - return rc; -} - -static struct authenticate_message *user_authblob(struct ksmbd_conn *conn, - struct smb2_sess_setup_req *req) -{ - int sz; - - if (conn->use_spnego && conn->mechToken) - return (struct authenticate_message *)conn->mechToken; - - sz = le16_to_cpu(req->SecurityBufferOffset); - return (struct authenticate_message *)((char *)&req->hdr.ProtocolId - + sz); -} - -static struct ksmbd_user *session_user(struct ksmbd_conn *conn, - struct smb2_sess_setup_req *req) -{ - struct authenticate_message *authblob; - struct ksmbd_user *user; - char *name; - unsigned int name_off, name_len, secbuf_len; - - secbuf_len = le16_to_cpu(req->SecurityBufferLength); - if (secbuf_len < sizeof(struct authenticate_message)) { - ksmbd_debug(SMB, "blob len %d too small\n", secbuf_len); - return NULL; - } - authblob = user_authblob(conn, req); - name_off = le32_to_cpu(authblob->UserName.BufferOffset); - name_len = le16_to_cpu(authblob->UserName.Length); - - if (secbuf_len < (u64)name_off + name_len) - return NULL; - - name = smb_strndup_from_utf16((const char *)authblob + name_off, - name_len, - true, - conn->local_nls); - if (IS_ERR(name)) { - pr_err("cannot allocate memory\n"); - return NULL; - } - - ksmbd_debug(SMB, "session setup request for user %s\n", name); - user = ksmbd_login_user(name); - kfree(name); - return user; -} - -static int ntlm_authenticate(struct ksmbd_work *work) -{ - struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf); - struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); - struct ksmbd_conn *conn = work->conn; - struct ksmbd_session *sess = work->sess; - struct channel *chann = NULL; - struct ksmbd_user *user; - u64 prev_id; - int sz, rc; - - ksmbd_debug(SMB, "authenticate phase\n"); - if (conn->use_spnego) { - unsigned char *spnego_blob; - u16 spnego_blob_len; - - rc = build_spnego_ntlmssp_auth_blob(&spnego_blob, - &spnego_blob_len, - 0); - if (rc) - return -ENOMEM; - - sz = le16_to_cpu(rsp->SecurityBufferOffset); - memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len); - rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len); - kfree(spnego_blob); - inc_rfc1001_len(work->response_buf, spnego_blob_len - 1); - } - - user = session_user(conn, req); - if (!user) { - ksmbd_debug(SMB, "Unknown user name or an error\n"); - return -EPERM; - } - - /* Check for previous session */ - prev_id = le64_to_cpu(req->PreviousSessionId); - if (prev_id && prev_id != sess->id) - destroy_previous_session(conn, user, prev_id); - - if (sess->state == SMB2_SESSION_VALID) { - /* - * Reuse session if anonymous try to connect - * on reauthetication. - */ - if (conn->binding == false && ksmbd_anonymous_user(user)) { - ksmbd_free_user(user); - return 0; - } - - if (!ksmbd_compare_user(sess->user, user)) { - ksmbd_free_user(user); - return -EPERM; - } - ksmbd_free_user(user); - } else { - sess->user = user; - } - - if (conn->binding == false && user_guest(sess->user)) { - rsp->SessionFlags = SMB2_SESSION_FLAG_IS_GUEST_LE; - } else { - struct authenticate_message *authblob; - - authblob = user_authblob(conn, req); - sz = le16_to_cpu(req->SecurityBufferLength); - rc = ksmbd_decode_ntlmssp_auth_blob(authblob, sz, conn, sess); - if (rc) { - set_user_flag(sess->user, KSMBD_USER_FLAG_BAD_PASSWORD); - ksmbd_debug(SMB, "authentication failed\n"); - return -EPERM; - } - } - - /* - * If session state is SMB2_SESSION_VALID, We can assume - * that it is reauthentication. And the user/password - * has been verified, so return it here. - */ - if (sess->state == SMB2_SESSION_VALID) { - if (conn->binding) - goto binding_session; - return 0; - } - - if ((rsp->SessionFlags != SMB2_SESSION_FLAG_IS_GUEST_LE && - (conn->sign || server_conf.enforced_signing)) || - (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) - sess->sign = true; - - if (smb3_encryption_negotiated(conn) && - !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) { - rc = conn->ops->generate_encryptionkey(conn, sess); - if (rc) { - ksmbd_debug(SMB, - "SMB3 encryption key generation failed\n"); - return -EINVAL; - } - sess->enc = true; - rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE; - /* - * signing is disable if encryption is enable - * on this session - */ - sess->sign = false; - } - -binding_session: - if (conn->dialect >= SMB30_PROT_ID) { - chann = lookup_chann_list(sess, conn); - if (!chann) { - chann = kmalloc(sizeof(struct channel), GFP_KERNEL); - if (!chann) - return -ENOMEM; - - chann->conn = conn; - xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL); - } - } - - if (conn->ops->generate_signingkey) { - rc = conn->ops->generate_signingkey(sess, conn); - if (rc) { - ksmbd_debug(SMB, "SMB3 signing key generation failed\n"); - return -EINVAL; - } - } - - if (!ksmbd_conn_lookup_dialect(conn)) { - pr_err("fail to verify the dialect\n"); - return -ENOENT; - } - return 0; -} - -#ifdef CONFIG_SMB_SERVER_KERBEROS5 -static int krb5_authenticate(struct ksmbd_work *work) -{ - struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf); - struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); - struct ksmbd_conn *conn = work->conn; - struct ksmbd_session *sess = work->sess; - char *in_blob, *out_blob; - struct channel *chann = NULL; - u64 prev_sess_id; - int in_len, out_len; - int retval; - - in_blob = (char *)&req->hdr.ProtocolId + - le16_to_cpu(req->SecurityBufferOffset); - in_len = le16_to_cpu(req->SecurityBufferLength); - out_blob = (char *)&rsp->hdr.ProtocolId + - le16_to_cpu(rsp->SecurityBufferOffset); - out_len = work->response_sz - - (le16_to_cpu(rsp->SecurityBufferOffset) + 4); - - /* Check previous session */ - prev_sess_id = le64_to_cpu(req->PreviousSessionId); - if (prev_sess_id && prev_sess_id != sess->id) - destroy_previous_session(conn, sess->user, prev_sess_id); - - if (sess->state == SMB2_SESSION_VALID) - ksmbd_free_user(sess->user); - - retval = ksmbd_krb5_authenticate(sess, in_blob, in_len, - out_blob, &out_len); - if (retval) { - ksmbd_debug(SMB, "krb5 authentication failed\n"); - return -EINVAL; - } - rsp->SecurityBufferLength = cpu_to_le16(out_len); - inc_rfc1001_len(work->response_buf, out_len - 1); - - if ((conn->sign || server_conf.enforced_signing) || - (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) - sess->sign = true; - - if (smb3_encryption_negotiated(conn)) { - retval = conn->ops->generate_encryptionkey(conn, sess); - if (retval) { - ksmbd_debug(SMB, - "SMB3 encryption key generation failed\n"); - return -EINVAL; - } - sess->enc = true; - rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE; - sess->sign = false; - } - - if (conn->dialect >= SMB30_PROT_ID) { - chann = lookup_chann_list(sess, conn); - if (!chann) { - chann = kmalloc(sizeof(struct channel), GFP_KERNEL); - if (!chann) - return -ENOMEM; - - chann->conn = conn; - xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL); - } - } - - if (conn->ops->generate_signingkey) { - retval = conn->ops->generate_signingkey(sess, conn); - if (retval) { - ksmbd_debug(SMB, "SMB3 signing key generation failed\n"); - return -EINVAL; - } - } - - if (!ksmbd_conn_lookup_dialect(conn)) { - pr_err("fail to verify the dialect\n"); - return -ENOENT; - } - return 0; -} -#else -static int krb5_authenticate(struct ksmbd_work *work) -{ - return -EOPNOTSUPP; -} -#endif - -int smb2_sess_setup(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf); - struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf); - struct ksmbd_session *sess; - struct negotiate_message *negblob; - unsigned int negblob_len, negblob_off; - int rc = 0; - - ksmbd_debug(SMB, "Received request for session setup\n"); - - rsp->StructureSize = cpu_to_le16(9); - rsp->SessionFlags = 0; - rsp->SecurityBufferOffset = cpu_to_le16(72); - rsp->SecurityBufferLength = 0; - inc_rfc1001_len(work->response_buf, 9); - - ksmbd_conn_lock(conn); - if (!req->hdr.SessionId) { - sess = ksmbd_smb2_session_create(); - if (!sess) { - rc = -ENOMEM; - goto out_err; - } - rsp->hdr.SessionId = cpu_to_le64(sess->id); - rc = ksmbd_session_register(conn, sess); - if (rc) - goto out_err; - } else if (conn->dialect >= SMB30_PROT_ID && - (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) && - req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) { - u64 sess_id = le64_to_cpu(req->hdr.SessionId); - - sess = ksmbd_session_lookup_slowpath(sess_id); - if (!sess) { - rc = -ENOENT; - goto out_err; - } - - if (conn->dialect != sess->dialect) { - rc = -EINVAL; - goto out_err; - } - - if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) { - rc = -EINVAL; - goto out_err; - } - - if (strncmp(conn->ClientGUID, sess->ClientGUID, - SMB2_CLIENT_GUID_SIZE)) { - rc = -ENOENT; - goto out_err; - } - - if (sess->state == SMB2_SESSION_IN_PROGRESS) { - rc = -EACCES; - goto out_err; - } - - if (sess->state == SMB2_SESSION_EXPIRED) { - rc = -EFAULT; - goto out_err; - } - - if (ksmbd_conn_need_reconnect(conn)) { - rc = -EFAULT; - sess = NULL; - goto out_err; - } - - if (ksmbd_session_lookup(conn, sess_id)) { - rc = -EACCES; - goto out_err; - } - - if (user_guest(sess->user)) { - rc = -EOPNOTSUPP; - goto out_err; - } - - conn->binding = true; - } else if ((conn->dialect < SMB30_PROT_ID || - server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) && - (req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) { - sess = NULL; - rc = -EACCES; - goto out_err; - } else { - sess = ksmbd_session_lookup(conn, - le64_to_cpu(req->hdr.SessionId)); - if (!sess) { - rc = -ENOENT; - goto out_err; - } - - if (sess->state == SMB2_SESSION_EXPIRED) { - rc = -EFAULT; - goto out_err; - } - - if (ksmbd_conn_need_reconnect(conn)) { - rc = -EFAULT; - sess = NULL; - goto out_err; - } - } - work->sess = sess; - - negblob_off = le16_to_cpu(req->SecurityBufferOffset); - negblob_len = le16_to_cpu(req->SecurityBufferLength); - if (negblob_off < offsetof(struct smb2_sess_setup_req, Buffer) || - negblob_len < offsetof(struct negotiate_message, NegotiateFlags)) { - rc = -EINVAL; - goto out_err; - } - - negblob = (struct negotiate_message *)((char *)&req->hdr.ProtocolId + - negblob_off); - - if (decode_negotiation_token(conn, negblob, negblob_len) == 0) { - if (conn->mechToken) - negblob = (struct negotiate_message *)conn->mechToken; - } - - if (server_conf.auth_mechs & conn->auth_mechs) { - rc = generate_preauth_hash(work); - if (rc) - goto out_err; - - if (conn->preferred_auth_mech & - (KSMBD_AUTH_KRB5 | KSMBD_AUTH_MSKRB5)) { - rc = krb5_authenticate(work); - if (rc) { - rc = -EINVAL; - goto out_err; - } - - if (!ksmbd_conn_need_reconnect(conn)) { - ksmbd_conn_set_good(conn); - sess->state = SMB2_SESSION_VALID; - } - kfree(sess->Preauth_HashValue); - sess->Preauth_HashValue = NULL; - } else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) { - if (negblob->MessageType == NtLmNegotiate) { - rc = ntlm_negotiate(work, negblob, negblob_len); - if (rc) - goto out_err; - rsp->hdr.Status = - STATUS_MORE_PROCESSING_REQUIRED; - /* - * Note: here total size -1 is done as an - * adjustment for 0 size blob - */ - inc_rfc1001_len(work->response_buf, - le16_to_cpu(rsp->SecurityBufferLength) - 1); - - } else if (negblob->MessageType == NtLmAuthenticate) { - rc = ntlm_authenticate(work); - if (rc) - goto out_err; - - if (!ksmbd_conn_need_reconnect(conn)) { - ksmbd_conn_set_good(conn); - sess->state = SMB2_SESSION_VALID; - } - if (conn->binding) { - struct preauth_session *preauth_sess; - - preauth_sess = - ksmbd_preauth_session_lookup(conn, sess->id); - if (preauth_sess) { - list_del(&preauth_sess->preauth_entry); - kfree(preauth_sess); - } - } - kfree(sess->Preauth_HashValue); - sess->Preauth_HashValue = NULL; - } else { - pr_info_ratelimited("Unknown NTLMSSP message type : 0x%x\n", - le32_to_cpu(negblob->MessageType)); - rc = -EINVAL; - } - } else { - /* TODO: need one more negotiation */ - pr_err("Not support the preferred authentication\n"); - rc = -EINVAL; - } - } else { - pr_err("Not support authentication\n"); - rc = -EINVAL; - } - -out_err: - if (rc == -EINVAL) - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - else if (rc == -ENOENT) - rsp->hdr.Status = STATUS_USER_SESSION_DELETED; - else if (rc == -EACCES) - rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED; - else if (rc == -EFAULT) - rsp->hdr.Status = STATUS_NETWORK_SESSION_EXPIRED; - else if (rc == -ENOMEM) - rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; - else if (rc == -EOPNOTSUPP) - rsp->hdr.Status = STATUS_NOT_SUPPORTED; - else if (rc) - rsp->hdr.Status = STATUS_LOGON_FAILURE; - - if (conn->use_spnego && conn->mechToken) { - kfree(conn->mechToken); - conn->mechToken = NULL; - } - - if (rc < 0) { - /* - * SecurityBufferOffset should be set to zero - * in session setup error response. - */ - rsp->SecurityBufferOffset = 0; - - if (sess) { - bool try_delay = false; - - /* - * To avoid dictionary attacks (repeated session setups rapidly sent) to - * connect to server, ksmbd make a delay of a 5 seconds on session setup - * failure to make it harder to send enough random connection requests - * to break into a server. - */ - if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION) - try_delay = true; - - sess->last_active = jiffies; - sess->state = SMB2_SESSION_EXPIRED; - if (try_delay) { - ksmbd_conn_set_need_reconnect(conn); - ssleep(5); - ksmbd_conn_set_need_negotiate(conn); - } - } - } - - ksmbd_conn_unlock(conn); - return rc; -} - -/** - * smb2_tree_connect() - handler for smb2 tree connect command - * @work: smb work containing smb request buffer - * - * Return: 0 on success, otherwise error - */ -int smb2_tree_connect(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_tree_connect_req *req = smb2_get_msg(work->request_buf); - struct smb2_tree_connect_rsp *rsp = smb2_get_msg(work->response_buf); - struct ksmbd_session *sess = work->sess; - char *treename = NULL, *name = NULL; - struct ksmbd_tree_conn_status status; - struct ksmbd_share_config *share; - int rc = -EINVAL; - - treename = smb_strndup_from_utf16(req->Buffer, - le16_to_cpu(req->PathLength), true, - conn->local_nls); - if (IS_ERR(treename)) { - pr_err("treename is NULL\n"); - status.ret = KSMBD_TREE_CONN_STATUS_ERROR; - goto out_err1; - } - - name = ksmbd_extract_sharename(conn->um, treename); - if (IS_ERR(name)) { - status.ret = KSMBD_TREE_CONN_STATUS_ERROR; - goto out_err1; - } - - ksmbd_debug(SMB, "tree connect request for tree %s treename %s\n", - name, treename); - - status = ksmbd_tree_conn_connect(conn, sess, name); - if (status.ret == KSMBD_TREE_CONN_STATUS_OK) - rsp->hdr.Id.SyncId.TreeId = cpu_to_le32(status.tree_conn->id); - else - goto out_err1; - - share = status.tree_conn->share_conf; - if (test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) { - ksmbd_debug(SMB, "IPC share path request\n"); - rsp->ShareType = SMB2_SHARE_TYPE_PIPE; - rsp->MaximalAccess = FILE_READ_DATA_LE | FILE_READ_EA_LE | - FILE_EXECUTE_LE | FILE_READ_ATTRIBUTES_LE | - FILE_DELETE_LE | FILE_READ_CONTROL_LE | - FILE_WRITE_DAC_LE | FILE_WRITE_OWNER_LE | - FILE_SYNCHRONIZE_LE; - } else { - rsp->ShareType = SMB2_SHARE_TYPE_DISK; - rsp->MaximalAccess = FILE_READ_DATA_LE | FILE_READ_EA_LE | - FILE_EXECUTE_LE | FILE_READ_ATTRIBUTES_LE; - if (test_tree_conn_flag(status.tree_conn, - KSMBD_TREE_CONN_FLAG_WRITABLE)) { - rsp->MaximalAccess |= FILE_WRITE_DATA_LE | - FILE_APPEND_DATA_LE | FILE_WRITE_EA_LE | - FILE_DELETE_LE | FILE_WRITE_ATTRIBUTES_LE | - FILE_DELETE_CHILD_LE | FILE_READ_CONTROL_LE | - FILE_WRITE_DAC_LE | FILE_WRITE_OWNER_LE | - FILE_SYNCHRONIZE_LE; - } - } - - status.tree_conn->maximal_access = le32_to_cpu(rsp->MaximalAccess); - if (conn->posix_ext_supported) - status.tree_conn->posix_extensions = true; - - rsp->StructureSize = cpu_to_le16(16); - inc_rfc1001_len(work->response_buf, 16); -out_err1: - rsp->Capabilities = 0; - rsp->Reserved = 0; - /* default manual caching */ - rsp->ShareFlags = SMB2_SHAREFLAG_MANUAL_CACHING; - - if (!IS_ERR(treename)) - kfree(treename); - if (!IS_ERR(name)) - kfree(name); - - switch (status.ret) { - case KSMBD_TREE_CONN_STATUS_OK: - rsp->hdr.Status = STATUS_SUCCESS; - rc = 0; - break; - case -ESTALE: - case -ENOENT: - case KSMBD_TREE_CONN_STATUS_NO_SHARE: - rsp->hdr.Status = STATUS_BAD_NETWORK_NAME; - break; - case -ENOMEM: - case KSMBD_TREE_CONN_STATUS_NOMEM: - rsp->hdr.Status = STATUS_NO_MEMORY; - break; - case KSMBD_TREE_CONN_STATUS_ERROR: - case KSMBD_TREE_CONN_STATUS_TOO_MANY_CONNS: - case KSMBD_TREE_CONN_STATUS_TOO_MANY_SESSIONS: - rsp->hdr.Status = STATUS_ACCESS_DENIED; - break; - case -EINVAL: - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - break; - default: - rsp->hdr.Status = STATUS_ACCESS_DENIED; - } - - if (status.ret != KSMBD_TREE_CONN_STATUS_OK) - smb2_set_err_rsp(work); - - return rc; -} - -/** - * smb2_create_open_flags() - convert smb open flags to unix open flags - * @file_present: is file already present - * @access: file access flags - * @disposition: file disposition flags - * @may_flags: set with MAY_ flags - * - * Return: file open flags - */ -static int smb2_create_open_flags(bool file_present, __le32 access, - __le32 disposition, - int *may_flags) -{ - int oflags = O_NONBLOCK | O_LARGEFILE; - - if (access & FILE_READ_DESIRED_ACCESS_LE && - access & FILE_WRITE_DESIRE_ACCESS_LE) { - oflags |= O_RDWR; - *may_flags = MAY_OPEN | MAY_READ | MAY_WRITE; - } else if (access & FILE_WRITE_DESIRE_ACCESS_LE) { - oflags |= O_WRONLY; - *may_flags = MAY_OPEN | MAY_WRITE; - } else { - oflags |= O_RDONLY; - *may_flags = MAY_OPEN | MAY_READ; - } - - if (access == FILE_READ_ATTRIBUTES_LE) - oflags |= O_PATH; - - if (file_present) { - switch (disposition & FILE_CREATE_MASK_LE) { - case FILE_OPEN_LE: - case FILE_CREATE_LE: - break; - case FILE_SUPERSEDE_LE: - case FILE_OVERWRITE_LE: - case FILE_OVERWRITE_IF_LE: - oflags |= O_TRUNC; - break; - default: - break; - } - } else { - switch (disposition & FILE_CREATE_MASK_LE) { - case FILE_SUPERSEDE_LE: - case FILE_CREATE_LE: - case FILE_OPEN_IF_LE: - case FILE_OVERWRITE_IF_LE: - oflags |= O_CREAT; - break; - case FILE_OPEN_LE: - case FILE_OVERWRITE_LE: - oflags &= ~O_CREAT; - break; - default: - break; - } - } - - return oflags; -} - -/** - * smb2_tree_disconnect() - handler for smb tree connect request - * @work: smb work containing request buffer - * - * Return: 0 - */ -int smb2_tree_disconnect(struct ksmbd_work *work) -{ - struct smb2_tree_disconnect_rsp *rsp = smb2_get_msg(work->response_buf); - struct ksmbd_session *sess = work->sess; - struct ksmbd_tree_connect *tcon = work->tcon; - - rsp->StructureSize = cpu_to_le16(4); - inc_rfc1001_len(work->response_buf, 4); - - ksmbd_debug(SMB, "request\n"); - - if (!tcon || test_and_set_bit(TREE_CONN_EXPIRE, &tcon->status)) { - struct smb2_tree_disconnect_req *req = - smb2_get_msg(work->request_buf); - - ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); - - rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; - smb2_set_err_rsp(work); - return 0; - } - - ksmbd_close_tree_conn_fds(work); - ksmbd_tree_conn_disconnect(sess, tcon); - work->tcon = NULL; - return 0; -} - -/** - * smb2_session_logoff() - handler for session log off request - * @work: smb work containing request buffer - * - * Return: 0 - */ -int smb2_session_logoff(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_logoff_rsp *rsp = smb2_get_msg(work->response_buf); - struct ksmbd_session *sess; - struct smb2_logoff_req *req = smb2_get_msg(work->request_buf); - u64 sess_id = le64_to_cpu(req->hdr.SessionId); - - rsp->StructureSize = cpu_to_le16(4); - inc_rfc1001_len(work->response_buf, 4); - - ksmbd_debug(SMB, "request\n"); - - ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT); - ksmbd_close_session_fds(work); - ksmbd_conn_wait_idle(conn, sess_id); - - /* - * Re-lookup session to validate if session is deleted - * while waiting request complete - */ - sess = ksmbd_session_lookup_all(conn, sess_id); - if (ksmbd_tree_conn_session_logoff(sess)) { - ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); - rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; - smb2_set_err_rsp(work); - return 0; - } - - ksmbd_destroy_file_table(&sess->file_table); - sess->state = SMB2_SESSION_EXPIRED; - - ksmbd_free_user(sess->user); - sess->user = NULL; - ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE); - return 0; -} - -/** - * create_smb2_pipe() - create IPC pipe - * @work: smb work containing request buffer - * - * Return: 0 on success, otherwise error - */ -static noinline int create_smb2_pipe(struct ksmbd_work *work) -{ - struct smb2_create_rsp *rsp = smb2_get_msg(work->response_buf); - struct smb2_create_req *req = smb2_get_msg(work->request_buf); - int id; - int err; - char *name; - - name = smb_strndup_from_utf16(req->Buffer, le16_to_cpu(req->NameLength), - 1, work->conn->local_nls); - if (IS_ERR(name)) { - rsp->hdr.Status = STATUS_NO_MEMORY; - err = PTR_ERR(name); - goto out; - } - - id = ksmbd_session_rpc_open(work->sess, name); - if (id < 0) { - pr_err("Unable to open RPC pipe: %d\n", id); - err = id; - goto out; - } - - rsp->hdr.Status = STATUS_SUCCESS; - rsp->StructureSize = cpu_to_le16(89); - rsp->OplockLevel = SMB2_OPLOCK_LEVEL_NONE; - rsp->Flags = 0; - rsp->CreateAction = cpu_to_le32(FILE_OPENED); - - rsp->CreationTime = cpu_to_le64(0); - rsp->LastAccessTime = cpu_to_le64(0); - rsp->ChangeTime = cpu_to_le64(0); - rsp->AllocationSize = cpu_to_le64(0); - rsp->EndofFile = cpu_to_le64(0); - rsp->FileAttributes = FILE_ATTRIBUTE_NORMAL_LE; - rsp->Reserved2 = 0; - rsp->VolatileFileId = id; - rsp->PersistentFileId = 0; - rsp->CreateContextsOffset = 0; - rsp->CreateContextsLength = 0; - - inc_rfc1001_len(work->response_buf, 88); /* StructureSize - 1*/ - kfree(name); - return 0; - -out: - switch (err) { - case -EINVAL: - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - break; - case -ENOSPC: - case -ENOMEM: - rsp->hdr.Status = STATUS_NO_MEMORY; - break; - } - - if (!IS_ERR(name)) - kfree(name); - - smb2_set_err_rsp(work); - return err; -} - -/** - * smb2_set_ea() - handler for setting extended attributes using set - * info command - * @eabuf: set info command buffer - * @buf_len: set info command buffer length - * @path: dentry path for get ea - * - * Return: 0 on success, otherwise error - */ -static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len, - const struct path *path) -{ - struct user_namespace *user_ns = mnt_user_ns(path->mnt); - char *attr_name = NULL, *value; - int rc = 0; - unsigned int next = 0; - - if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength + - le16_to_cpu(eabuf->EaValueLength)) - return -EINVAL; - - attr_name = kmalloc(XATTR_NAME_MAX + 1, GFP_KERNEL); - if (!attr_name) - return -ENOMEM; - - do { - if (!eabuf->EaNameLength) - goto next; - - ksmbd_debug(SMB, - "name : <%s>, name_len : %u, value_len : %u, next : %u\n", - eabuf->name, eabuf->EaNameLength, - le16_to_cpu(eabuf->EaValueLength), - le32_to_cpu(eabuf->NextEntryOffset)); - - if (eabuf->EaNameLength > - (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) { - rc = -EINVAL; - break; - } - - memcpy(attr_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); - memcpy(&attr_name[XATTR_USER_PREFIX_LEN], eabuf->name, - eabuf->EaNameLength); - attr_name[XATTR_USER_PREFIX_LEN + eabuf->EaNameLength] = '\0'; - value = (char *)&eabuf->name + eabuf->EaNameLength + 1; - - if (!eabuf->EaValueLength) { - rc = ksmbd_vfs_casexattr_len(user_ns, - path->dentry, - attr_name, - XATTR_USER_PREFIX_LEN + - eabuf->EaNameLength); - - /* delete the EA only when it exits */ - if (rc > 0) { - rc = ksmbd_vfs_remove_xattr(user_ns, - path->dentry, - attr_name); - - if (rc < 0) { - ksmbd_debug(SMB, - "remove xattr failed(%d)\n", - rc); - break; - } - } - - /* if the EA doesn't exist, just do nothing. */ - rc = 0; - } else { - rc = ksmbd_vfs_setxattr(user_ns, - path->dentry, attr_name, value, - le16_to_cpu(eabuf->EaValueLength), 0); - if (rc < 0) { - ksmbd_debug(SMB, - "ksmbd_vfs_setxattr is failed(%d)\n", - rc); - break; - } - } - -next: - next = le32_to_cpu(eabuf->NextEntryOffset); - if (next == 0 || buf_len < next) - break; - buf_len -= next; - eabuf = (struct smb2_ea_info *)((char *)eabuf + next); - if (next < (u32)eabuf->EaNameLength + le16_to_cpu(eabuf->EaValueLength)) - break; - - } while (next != 0); - - kfree(attr_name); - return rc; -} - -static noinline int smb2_set_stream_name_xattr(const struct path *path, - struct ksmbd_file *fp, - char *stream_name, int s_type) -{ - struct user_namespace *user_ns = mnt_user_ns(path->mnt); - size_t xattr_stream_size; - char *xattr_stream_name; - int rc; - - rc = ksmbd_vfs_xattr_stream_name(stream_name, - &xattr_stream_name, - &xattr_stream_size, - s_type); - if (rc) - return rc; - - fp->stream.name = xattr_stream_name; - fp->stream.size = xattr_stream_size; - - /* Check if there is stream prefix in xattr space */ - rc = ksmbd_vfs_casexattr_len(user_ns, - path->dentry, - xattr_stream_name, - xattr_stream_size); - if (rc >= 0) - return 0; - - if (fp->cdoption == FILE_OPEN_LE) { - ksmbd_debug(SMB, "XATTR stream name lookup failed: %d\n", rc); - return -EBADF; - } - - rc = ksmbd_vfs_setxattr(user_ns, path->dentry, - xattr_stream_name, NULL, 0, 0); - if (rc < 0) - pr_err("Failed to store XATTR stream name :%d\n", rc); - return 0; -} - -static int smb2_remove_smb_xattrs(const struct path *path) -{ - struct user_namespace *user_ns = mnt_user_ns(path->mnt); - char *name, *xattr_list = NULL; - ssize_t xattr_list_len; - int err = 0; - - xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list); - if (xattr_list_len < 0) { - goto out; - } else if (!xattr_list_len) { - ksmbd_debug(SMB, "empty xattr in the file\n"); - goto out; - } - - for (name = xattr_list; name - xattr_list < xattr_list_len; - name += strlen(name) + 1) { - ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name)); - - if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && - !strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX, - STREAM_PREFIX_LEN)) { - err = ksmbd_vfs_remove_xattr(user_ns, path->dentry, - name); - if (err) - ksmbd_debug(SMB, "remove xattr failed : %s\n", - name); - } - } -out: - kvfree(xattr_list); - return err; -} - -static int smb2_create_truncate(const struct path *path) -{ - int rc = vfs_truncate(path, 0); - - if (rc) { - pr_err("vfs_truncate failed, rc %d\n", rc); - return rc; - } - - rc = smb2_remove_smb_xattrs(path); - if (rc == -EOPNOTSUPP) - rc = 0; - if (rc) - ksmbd_debug(SMB, - "ksmbd_truncate_stream_name_xattr failed, rc %d\n", - rc); - return rc; -} - -static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, const struct path *path, - struct ksmbd_file *fp) -{ - struct xattr_dos_attrib da = {0}; - int rc; - - if (!test_share_config_flag(tcon->share_conf, - KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) - return; - - da.version = 4; - da.attr = le32_to_cpu(fp->f_ci->m_fattr); - da.itime = da.create_time = fp->create_time; - da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME | - XATTR_DOSINFO_ITIME; - - rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_user_ns(path->mnt), - path->dentry, &da); - if (rc) - ksmbd_debug(SMB, "failed to store file attribute into xattr\n"); -} - -static void smb2_update_xattrs(struct ksmbd_tree_connect *tcon, - const struct path *path, struct ksmbd_file *fp) -{ - struct xattr_dos_attrib da; - int rc; - - fp->f_ci->m_fattr &= ~(FILE_ATTRIBUTE_HIDDEN_LE | FILE_ATTRIBUTE_SYSTEM_LE); - - /* get FileAttributes from XATTR_NAME_DOS_ATTRIBUTE */ - if (!test_share_config_flag(tcon->share_conf, - KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) - return; - - rc = ksmbd_vfs_get_dos_attrib_xattr(mnt_user_ns(path->mnt), - path->dentry, &da); - if (rc > 0) { - fp->f_ci->m_fattr = cpu_to_le32(da.attr); - fp->create_time = da.create_time; - fp->itime = da.itime; - } -} - -static int smb2_creat(struct ksmbd_work *work, struct path *path, char *name, - int open_flags, umode_t posix_mode, bool is_dir) -{ - struct ksmbd_tree_connect *tcon = work->tcon; - struct ksmbd_share_config *share = tcon->share_conf; - umode_t mode; - int rc; - - if (!(open_flags & O_CREAT)) - return -EBADF; - - ksmbd_debug(SMB, "file does not exist, so creating\n"); - if (is_dir == true) { - ksmbd_debug(SMB, "creating directory\n"); - - mode = share_config_directory_mode(share, posix_mode); - rc = ksmbd_vfs_mkdir(work, name, mode); - if (rc) - return rc; - } else { - ksmbd_debug(SMB, "creating regular file\n"); - - mode = share_config_create_mode(share, posix_mode); - rc = ksmbd_vfs_create(work, name, mode); - if (rc) - return rc; - } - - rc = ksmbd_vfs_kern_path(work, name, 0, path, 0); - if (rc) { - pr_err("cannot get linux path (%s), err = %d\n", - name, rc); - return rc; - } - return 0; -} - -static int smb2_create_sd_buffer(struct ksmbd_work *work, - struct smb2_create_req *req, - const struct path *path) -{ - struct create_context *context; - struct create_sd_buf_req *sd_buf; - - if (!req->CreateContextsOffset) - return -ENOENT; - - /* Parse SD BUFFER create contexts */ - context = smb2_find_context_vals(req, SMB2_CREATE_SD_BUFFER, 4); - if (!context) - return -ENOENT; - else if (IS_ERR(context)) - return PTR_ERR(context); - - ksmbd_debug(SMB, - "Set ACLs using SMB2_CREATE_SD_BUFFER context\n"); - sd_buf = (struct create_sd_buf_req *)context; - if (le16_to_cpu(context->DataOffset) + - le32_to_cpu(context->DataLength) < - sizeof(struct create_sd_buf_req)) - return -EINVAL; - return set_info_sec(work->conn, work->tcon, path, &sd_buf->ntsd, - le32_to_cpu(sd_buf->ccontext.DataLength), true); -} - -static void ksmbd_acls_fattr(struct smb_fattr *fattr, - struct user_namespace *mnt_userns, - struct inode *inode) -{ - vfsuid_t vfsuid = i_uid_into_vfsuid(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_acls = NULL; - fattr->cf_dacls = NULL; - - if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { - fattr->cf_acls = get_acl(inode, ACL_TYPE_ACCESS); - if (S_ISDIR(inode->i_mode)) - fattr->cf_dacls = get_acl(inode, ACL_TYPE_DEFAULT); - } -} - -/** - * smb2_open() - handler for smb file open request - * @work: smb work containing request buffer - * - * Return: 0 on success, otherwise error - */ -int smb2_open(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct ksmbd_session *sess = work->sess; - struct ksmbd_tree_connect *tcon = work->tcon; - struct smb2_create_req *req; - struct smb2_create_rsp *rsp; - struct path path; - struct ksmbd_share_config *share = tcon->share_conf; - struct ksmbd_file *fp = NULL; - struct file *filp = NULL; - struct user_namespace *user_ns = NULL; - struct kstat stat; - struct create_context *context; - struct lease_ctx_info *lc = NULL; - struct create_ea_buf_req *ea_buf = NULL; - struct oplock_info *opinfo; - __le32 *next_ptr = NULL; - int req_op_level = 0, open_flags = 0, may_flags = 0, file_info = 0; - int rc = 0; - int contxt_cnt = 0, query_disk_id = 0; - int maximal_access_ctxt = 0, posix_ctxt = 0; - int s_type = 0; - int next_off = 0; - char *name = NULL; - char *stream_name = NULL; - bool file_present = false, created = false, already_permitted = false; - int share_ret, need_truncate = 0; - u64 time; - umode_t posix_mode = 0; - __le32 daccess, maximal_access = 0; - - WORK_BUFFERS(work, req, rsp); - - if (req->hdr.NextCommand && !work->next_smb2_rcv_hdr_off && - (req->hdr.Flags & SMB2_FLAGS_RELATED_OPERATIONS)) { - ksmbd_debug(SMB, "invalid flag in chained command\n"); - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - smb2_set_err_rsp(work); - return -EINVAL; - } - - if (test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) { - ksmbd_debug(SMB, "IPC pipe create request\n"); - return create_smb2_pipe(work); - } - - if (req->NameLength) { - if ((req->CreateOptions & FILE_DIRECTORY_FILE_LE) && - *(char *)req->Buffer == '\\') { - pr_err("not allow directory name included leading slash\n"); - rc = -EINVAL; - goto err_out1; - } - - name = smb2_get_name(req->Buffer, - le16_to_cpu(req->NameLength), - work->conn->local_nls); - if (IS_ERR(name)) { - rc = PTR_ERR(name); - if (rc != -ENOMEM) - rc = -ENOENT; - name = NULL; - goto err_out1; - } - - ksmbd_debug(SMB, "converted name = %s\n", name); - if (strchr(name, ':')) { - if (!test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_STREAMS)) { - rc = -EBADF; - goto err_out1; - } - rc = parse_stream_name(name, &stream_name, &s_type); - if (rc < 0) - goto err_out1; - } - - rc = ksmbd_validate_filename(name); - if (rc < 0) - goto err_out1; - - if (ksmbd_share_veto_filename(share, name)) { - rc = -ENOENT; - ksmbd_debug(SMB, "Reject open(), vetoed file: %s\n", - name); - goto err_out1; - } - } else { - name = kstrdup("", GFP_KERNEL); - if (!name) { - rc = -ENOMEM; - goto err_out1; - } - } - - req_op_level = req->RequestedOplockLevel; - if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) - lc = parse_lease_state(req); - - if (le32_to_cpu(req->ImpersonationLevel) > le32_to_cpu(IL_DELEGATE)) { - pr_err("Invalid impersonationlevel : 0x%x\n", - le32_to_cpu(req->ImpersonationLevel)); - rc = -EIO; - rsp->hdr.Status = STATUS_BAD_IMPERSONATION_LEVEL; - goto err_out1; - } - - if (req->CreateOptions && !(req->CreateOptions & CREATE_OPTIONS_MASK_LE)) { - pr_err("Invalid create options : 0x%x\n", - le32_to_cpu(req->CreateOptions)); - rc = -EINVAL; - goto err_out1; - } else { - if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE && - req->CreateOptions & FILE_RANDOM_ACCESS_LE) - req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); - - if (req->CreateOptions & - (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | - FILE_RESERVE_OPFILTER_LE)) { - rc = -EOPNOTSUPP; - goto err_out1; - } - - if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) { - if (req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE) { - rc = -EINVAL; - goto err_out1; - } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) { - req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); - } - } - } - - if (le32_to_cpu(req->CreateDisposition) > - le32_to_cpu(FILE_OVERWRITE_IF_LE)) { - pr_err("Invalid create disposition : 0x%x\n", - le32_to_cpu(req->CreateDisposition)); - rc = -EINVAL; - goto err_out1; - } - - if (!(req->DesiredAccess & DESIRED_ACCESS_MASK)) { - pr_err("Invalid desired access : 0x%x\n", - le32_to_cpu(req->DesiredAccess)); - rc = -EACCES; - goto err_out1; - } - - if (req->FileAttributes && !(req->FileAttributes & FILE_ATTRIBUTE_MASK_LE)) { - pr_err("Invalid file attribute : 0x%x\n", - le32_to_cpu(req->FileAttributes)); - rc = -EINVAL; - goto err_out1; - } - - if (req->CreateContextsOffset) { - /* Parse non-durable handle create contexts */ - context = smb2_find_context_vals(req, SMB2_CREATE_EA_BUFFER, 4); - if (IS_ERR(context)) { - rc = PTR_ERR(context); - goto err_out1; - } else if (context) { - ea_buf = (struct create_ea_buf_req *)context; - if (le16_to_cpu(context->DataOffset) + - le32_to_cpu(context->DataLength) < - sizeof(struct create_ea_buf_req)) { - rc = -EINVAL; - goto err_out1; - } - if (req->CreateOptions & FILE_NO_EA_KNOWLEDGE_LE) { - rsp->hdr.Status = STATUS_ACCESS_DENIED; - rc = -EACCES; - goto err_out1; - } - } - - context = smb2_find_context_vals(req, - SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST, 4); - if (IS_ERR(context)) { - rc = PTR_ERR(context); - goto err_out1; - } else if (context) { - ksmbd_debug(SMB, - "get query maximal access context\n"); - maximal_access_ctxt = 1; - } - - context = smb2_find_context_vals(req, - SMB2_CREATE_TIMEWARP_REQUEST, 4); - if (IS_ERR(context)) { - rc = PTR_ERR(context); - goto err_out1; - } else if (context) { - ksmbd_debug(SMB, "get timewarp context\n"); - rc = -EBADF; - goto err_out1; - } - - if (tcon->posix_extensions) { - context = smb2_find_context_vals(req, - SMB2_CREATE_TAG_POSIX, 16); - if (IS_ERR(context)) { - rc = PTR_ERR(context); - goto err_out1; - } else if (context) { - struct create_posix *posix = - (struct create_posix *)context; - if (le16_to_cpu(context->DataOffset) + - le32_to_cpu(context->DataLength) < - sizeof(struct create_posix) - 4) { - rc = -EINVAL; - goto err_out1; - } - ksmbd_debug(SMB, "get posix context\n"); - - posix_mode = le32_to_cpu(posix->Mode); - posix_ctxt = 1; - } - } - } - - if (ksmbd_override_fsids(work)) { - rc = -ENOMEM; - goto err_out1; - } - - rc = ksmbd_vfs_kern_path(work, name, LOOKUP_NO_SYMLINKS, &path, 1); - if (!rc) { - if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) { - /* - * If file exists with under flags, return access - * denied error. - */ - if (req->CreateDisposition == FILE_OVERWRITE_IF_LE || - req->CreateDisposition == FILE_OPEN_IF_LE) { - rc = -EACCES; - path_put(&path); - goto err_out; - } - - if (!test_tree_conn_flag(tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { - ksmbd_debug(SMB, - "User does not have write permission\n"); - rc = -EACCES; - path_put(&path); - goto err_out; - } - } else if (d_is_symlink(path.dentry)) { - rc = -EACCES; - path_put(&path); - goto err_out; - } - } - - if (rc) { - if (rc != -ENOENT) - goto err_out; - ksmbd_debug(SMB, "can not get linux path for %s, rc = %d\n", - name, rc); - rc = 0; - } else { - file_present = true; - user_ns = mnt_user_ns(path.mnt); - } - if (stream_name) { - if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) { - if (s_type == DATA_STREAM) { - rc = -EIO; - rsp->hdr.Status = STATUS_NOT_A_DIRECTORY; - } - } else { - if (file_present && S_ISDIR(d_inode(path.dentry)->i_mode) && - s_type == DATA_STREAM) { - rc = -EIO; - rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY; - } - } - - if (req->CreateOptions & FILE_DIRECTORY_FILE_LE && - req->FileAttributes & FILE_ATTRIBUTE_NORMAL_LE) { - rsp->hdr.Status = STATUS_NOT_A_DIRECTORY; - rc = -EIO; - } - - if (rc < 0) - goto err_out; - } - - if (file_present && req->CreateOptions & FILE_NON_DIRECTORY_FILE_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", - name, req->CreateOptions); - rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY; - rc = -EIO; - goto err_out; - } - - if (file_present && (req->CreateOptions & FILE_DIRECTORY_FILE_LE) && - !(req->CreateDisposition == FILE_CREATE_LE) && - !S_ISDIR(d_inode(path.dentry)->i_mode)) { - rsp->hdr.Status = STATUS_NOT_A_DIRECTORY; - rc = -EIO; - goto err_out; - } - - if (!stream_name && file_present && - req->CreateDisposition == FILE_CREATE_LE) { - rc = -EEXIST; - goto err_out; - } - - daccess = smb_map_generic_desired_access(req->DesiredAccess); - - if (file_present && !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) { - rc = smb_check_perm_dacl(conn, &path, &daccess, - sess->user->uid); - if (rc) - goto err_out; - } - - if (daccess & FILE_MAXIMAL_ACCESS_LE) { - if (!file_present) { - daccess = cpu_to_le32(GENERIC_ALL_FLAGS); - } else { - rc = ksmbd_vfs_query_maximal_access(user_ns, - path.dentry, - &daccess); - if (rc) - goto err_out; - already_permitted = true; - } - maximal_access = daccess; - } - - open_flags = smb2_create_open_flags(file_present, daccess, - req->CreateDisposition, - &may_flags); - - if (!test_tree_conn_flag(tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { - if (open_flags & O_CREAT) { - ksmbd_debug(SMB, - "User does not have write permission\n"); - rc = -EACCES; - goto err_out; - } - } - - /*create file if not present */ - if (!file_present) { - rc = smb2_creat(work, &path, name, open_flags, posix_mode, - req->CreateOptions & FILE_DIRECTORY_FILE_LE); - if (rc) { - if (rc == -ENOENT) { - rc = -EIO; - rsp->hdr.Status = STATUS_OBJECT_PATH_NOT_FOUND; - } - goto err_out; - } - - created = true; - user_ns = mnt_user_ns(path.mnt); - if (ea_buf) { - if (le32_to_cpu(ea_buf->ccontext.DataLength) < - sizeof(struct smb2_ea_info)) { - rc = -EINVAL; - goto err_out; - } - - rc = smb2_set_ea(&ea_buf->ea, - le32_to_cpu(ea_buf->ccontext.DataLength), - &path); - if (rc == -EOPNOTSUPP) - rc = 0; - else if (rc) - goto err_out; - } - } else if (!already_permitted) { - /* FILE_READ_ATTRIBUTE is allowed without inode_permission, - * because execute(search) permission on a parent directory, - * is already granted. - */ - if (daccess & ~(FILE_READ_ATTRIBUTES_LE | FILE_READ_CONTROL_LE)) { - rc = inode_permission(user_ns, - d_inode(path.dentry), - may_flags); - if (rc) - goto err_out; - - if ((daccess & FILE_DELETE_LE) || - (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) { - rc = ksmbd_vfs_may_delete(user_ns, - path.dentry); - if (rc) - goto err_out; - } - } - } - - rc = ksmbd_query_inode_status(d_inode(path.dentry->d_parent)); - if (rc == KSMBD_INODE_STATUS_PENDING_DELETE) { - rc = -EBUSY; - goto err_out; - } - - rc = 0; - filp = dentry_open(&path, open_flags, current_cred()); - if (IS_ERR(filp)) { - rc = PTR_ERR(filp); - pr_err("dentry open for dir failed, rc %d\n", rc); - goto err_out; - } - - if (file_present) { - if (!(open_flags & O_TRUNC)) - file_info = FILE_OPENED; - else - file_info = FILE_OVERWRITTEN; - - if ((req->CreateDisposition & FILE_CREATE_MASK_LE) == - FILE_SUPERSEDE_LE) - file_info = FILE_SUPERSEDED; - } else if (open_flags & O_CREAT) { - file_info = FILE_CREATED; - } - - ksmbd_vfs_set_fadvise(filp, req->CreateOptions); - - /* Obtain Volatile-ID */ - fp = ksmbd_open_fd(work, filp); - if (IS_ERR(fp)) { - fput(filp); - rc = PTR_ERR(fp); - fp = NULL; - goto err_out; - } - - /* Get Persistent-ID */ - ksmbd_open_durable_fd(fp); - if (!has_file_id(fp->persistent_id)) { - rc = -ENOMEM; - goto err_out; - } - - fp->cdoption = req->CreateDisposition; - fp->daccess = daccess; - fp->saccess = req->ShareAccess; - fp->coption = req->CreateOptions; - - /* Set default windows and posix acls if creating new file */ - if (created) { - int posix_acl_rc; - struct inode *inode = d_inode(path.dentry); - - posix_acl_rc = ksmbd_vfs_inherit_posix_acl(user_ns, - inode, - d_inode(path.dentry->d_parent)); - if (posix_acl_rc) - ksmbd_debug(SMB, "inherit posix acl failed : %d\n", posix_acl_rc); - - if (test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_ACL_XATTR)) { - rc = smb_inherit_dacl(conn, &path, sess->user->uid, - sess->user->gid); - } - - if (rc) { - rc = smb2_create_sd_buffer(work, req, &path); - if (rc) { - if (posix_acl_rc) - ksmbd_vfs_set_init_posix_acl(user_ns, - inode); - - if (test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_ACL_XATTR)) { - struct smb_fattr fattr; - struct smb_ntsd *pntsd; - int pntsd_size, ace_num = 0; - - ksmbd_acls_fattr(&fattr, user_ns, inode); - if (fattr.cf_acls) - ace_num = fattr.cf_acls->a_count; - if (fattr.cf_dacls) - ace_num += fattr.cf_dacls->a_count; - - pntsd = kmalloc(sizeof(struct smb_ntsd) + - sizeof(struct smb_sid) * 3 + - sizeof(struct smb_acl) + - sizeof(struct smb_ace) * ace_num * 2, - GFP_KERNEL); - if (!pntsd) { - posix_acl_release(fattr.cf_acls); - posix_acl_release(fattr.cf_dacls); - goto err_out; - } - - rc = build_sec_desc(user_ns, - pntsd, NULL, 0, - OWNER_SECINFO | - GROUP_SECINFO | - DACL_SECINFO, - &pntsd_size, &fattr); - posix_acl_release(fattr.cf_acls); - posix_acl_release(fattr.cf_dacls); - if (rc) { - kfree(pntsd); - goto err_out; - } - - rc = ksmbd_vfs_set_sd_xattr(conn, - user_ns, - path.dentry, - pntsd, - pntsd_size); - kfree(pntsd); - if (rc) - pr_err("failed to store ntacl in xattr : %d\n", - rc); - } - } - } - rc = 0; - } - - if (stream_name) { - rc = smb2_set_stream_name_xattr(&path, - fp, - stream_name, - s_type); - if (rc) - goto err_out; - file_info = FILE_CREATED; - } - - fp->attrib_only = !(req->DesiredAccess & ~(FILE_READ_ATTRIBUTES_LE | - FILE_WRITE_ATTRIBUTES_LE | FILE_SYNCHRONIZE_LE)); - if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC && - !fp->attrib_only && !stream_name) { - smb_break_all_oplock(work, fp); - need_truncate = 1; - } - - /* fp should be searchable through ksmbd_inode.m_fp_list - * after daccess, saccess, attrib_only, and stream are - * initialized. - */ - write_lock(&fp->f_ci->m_lock); - list_add(&fp->node, &fp->f_ci->m_fp_list); - write_unlock(&fp->f_ci->m_lock); - - /* Check delete pending among previous fp before oplock break */ - if (ksmbd_inode_pending_delete(fp)) { - rc = -EBUSY; - goto err_out; - } - - share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp); - if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) || - (req_op_level == SMB2_OPLOCK_LEVEL_LEASE && - !(conn->vals->capabilities & SMB2_GLOBAL_CAP_LEASING))) { - if (share_ret < 0 && !S_ISDIR(file_inode(fp->filp)->i_mode)) { - rc = share_ret; - goto err_out; - } - } else { - if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) { - req_op_level = smb2_map_lease_to_oplock(lc->req_state); - ksmbd_debug(SMB, - "lease req for(%s) req oplock state 0x%x, lease state 0x%x\n", - name, req_op_level, lc->req_state); - rc = find_same_lease_key(sess, fp->f_ci, lc); - if (rc) - goto err_out; - } else if (open_flags == O_RDONLY && - (req_op_level == SMB2_OPLOCK_LEVEL_BATCH || - req_op_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)) - req_op_level = SMB2_OPLOCK_LEVEL_II; - - rc = smb_grant_oplock(work, req_op_level, - fp->persistent_id, fp, - le32_to_cpu(req->hdr.Id.SyncId.TreeId), - lc, share_ret); - if (rc < 0) - goto err_out; - } - - if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) - ksmbd_fd_set_delete_on_close(fp, file_info); - - if (need_truncate) { - rc = smb2_create_truncate(&path); - if (rc) - goto err_out; - } - - if (req->CreateContextsOffset) { - struct create_alloc_size_req *az_req; - - az_req = (struct create_alloc_size_req *)smb2_find_context_vals(req, - SMB2_CREATE_ALLOCATION_SIZE, 4); - if (IS_ERR(az_req)) { - rc = PTR_ERR(az_req); - goto err_out; - } else if (az_req) { - loff_t alloc_size; - int err; - - if (le16_to_cpu(az_req->ccontext.DataOffset) + - le32_to_cpu(az_req->ccontext.DataLength) < - sizeof(struct create_alloc_size_req)) { - rc = -EINVAL; - goto err_out; - } - alloc_size = le64_to_cpu(az_req->AllocationSize); - ksmbd_debug(SMB, - "request smb2 create allocate size : %llu\n", - alloc_size); - smb_break_all_levII_oplock(work, fp, 1); - err = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0, - alloc_size); - if (err < 0) - ksmbd_debug(SMB, - "vfs_fallocate is failed : %d\n", - err); - } - - context = smb2_find_context_vals(req, SMB2_CREATE_QUERY_ON_DISK_ID, 4); - if (IS_ERR(context)) { - rc = PTR_ERR(context); - goto err_out; - } else if (context) { - ksmbd_debug(SMB, "get query on disk id context\n"); - query_disk_id = 1; - } - } - - rc = ksmbd_vfs_getattr(&path, &stat); - if (rc) - goto err_out; - - if (stat.result_mask & STATX_BTIME) - fp->create_time = ksmbd_UnixTimeToNT(stat.btime); - else - fp->create_time = ksmbd_UnixTimeToNT(stat.ctime); - if (req->FileAttributes || fp->f_ci->m_fattr == 0) - fp->f_ci->m_fattr = - cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes))); - - if (!created) - smb2_update_xattrs(tcon, &path, fp); - else - smb2_new_xattrs(tcon, &path, fp); - - memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); - - rsp->StructureSize = cpu_to_le16(89); - rcu_read_lock(); - opinfo = rcu_dereference(fp->f_opinfo); - rsp->OplockLevel = opinfo != NULL ? opinfo->level : 0; - rcu_read_unlock(); - rsp->Flags = 0; - rsp->CreateAction = cpu_to_le32(file_info); - rsp->CreationTime = cpu_to_le64(fp->create_time); - time = ksmbd_UnixTimeToNT(stat.atime); - rsp->LastAccessTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(stat.mtime); - rsp->LastWriteTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(stat.ctime); - rsp->ChangeTime = cpu_to_le64(time); - rsp->AllocationSize = S_ISDIR(stat.mode) ? 0 : - cpu_to_le64(stat.blocks << 9); - rsp->EndofFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); - rsp->FileAttributes = fp->f_ci->m_fattr; - - rsp->Reserved2 = 0; - - rsp->PersistentFileId = fp->persistent_id; - rsp->VolatileFileId = fp->volatile_id; - - rsp->CreateContextsOffset = 0; - rsp->CreateContextsLength = 0; - inc_rfc1001_len(work->response_buf, 88); /* StructureSize - 1*/ - - /* If lease is request send lease context response */ - if (opinfo && opinfo->is_lease) { - struct create_context *lease_ccontext; - - ksmbd_debug(SMB, "lease granted on(%s) lease state 0x%x\n", - name, opinfo->o_lease->state); - rsp->OplockLevel = SMB2_OPLOCK_LEVEL_LEASE; - - lease_ccontext = (struct create_context *)rsp->Buffer; - contxt_cnt++; - create_lease_buf(rsp->Buffer, opinfo->o_lease); - le32_add_cpu(&rsp->CreateContextsLength, - conn->vals->create_lease_size); - inc_rfc1001_len(work->response_buf, - conn->vals->create_lease_size); - next_ptr = &lease_ccontext->Next; - next_off = conn->vals->create_lease_size; - } - - if (maximal_access_ctxt) { - struct create_context *mxac_ccontext; - - if (maximal_access == 0) - ksmbd_vfs_query_maximal_access(user_ns, - path.dentry, - &maximal_access); - mxac_ccontext = (struct create_context *)(rsp->Buffer + - le32_to_cpu(rsp->CreateContextsLength)); - contxt_cnt++; - create_mxac_rsp_buf(rsp->Buffer + - le32_to_cpu(rsp->CreateContextsLength), - le32_to_cpu(maximal_access)); - le32_add_cpu(&rsp->CreateContextsLength, - conn->vals->create_mxac_size); - inc_rfc1001_len(work->response_buf, - conn->vals->create_mxac_size); - if (next_ptr) - *next_ptr = cpu_to_le32(next_off); - next_ptr = &mxac_ccontext->Next; - next_off = conn->vals->create_mxac_size; - } - - if (query_disk_id) { - struct create_context *disk_id_ccontext; - - disk_id_ccontext = (struct create_context *)(rsp->Buffer + - le32_to_cpu(rsp->CreateContextsLength)); - contxt_cnt++; - create_disk_id_rsp_buf(rsp->Buffer + - le32_to_cpu(rsp->CreateContextsLength), - stat.ino, tcon->id); - le32_add_cpu(&rsp->CreateContextsLength, - conn->vals->create_disk_id_size); - inc_rfc1001_len(work->response_buf, - conn->vals->create_disk_id_size); - if (next_ptr) - *next_ptr = cpu_to_le32(next_off); - next_ptr = &disk_id_ccontext->Next; - next_off = conn->vals->create_disk_id_size; - } - - if (posix_ctxt) { - contxt_cnt++; - create_posix_rsp_buf(rsp->Buffer + - le32_to_cpu(rsp->CreateContextsLength), - fp); - le32_add_cpu(&rsp->CreateContextsLength, - conn->vals->create_posix_size); - inc_rfc1001_len(work->response_buf, - conn->vals->create_posix_size); - if (next_ptr) - *next_ptr = cpu_to_le32(next_off); - } - - if (contxt_cnt > 0) { - rsp->CreateContextsOffset = - cpu_to_le32(offsetof(struct smb2_create_rsp, Buffer)); - } - -err_out: - if (file_present || created) - path_put(&path); - ksmbd_revert_fsids(work); -err_out1: - if (rc) { - if (rc == -EINVAL) - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - else if (rc == -EOPNOTSUPP) - rsp->hdr.Status = STATUS_NOT_SUPPORTED; - else if (rc == -EACCES || rc == -ESTALE || rc == -EXDEV) - rsp->hdr.Status = STATUS_ACCESS_DENIED; - else if (rc == -ENOENT) - rsp->hdr.Status = STATUS_OBJECT_NAME_INVALID; - else if (rc == -EPERM) - rsp->hdr.Status = STATUS_SHARING_VIOLATION; - else if (rc == -EBUSY) - rsp->hdr.Status = STATUS_DELETE_PENDING; - else if (rc == -EBADF) - rsp->hdr.Status = STATUS_OBJECT_NAME_NOT_FOUND; - else if (rc == -ENOEXEC) - rsp->hdr.Status = STATUS_DUPLICATE_OBJECTID; - else if (rc == -ENXIO) - rsp->hdr.Status = STATUS_NO_SUCH_DEVICE; - else if (rc == -EEXIST) - rsp->hdr.Status = STATUS_OBJECT_NAME_COLLISION; - else if (rc == -EMFILE) - rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; - if (!rsp->hdr.Status) - rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR; - - if (fp) - ksmbd_fd_put(work, fp); - smb2_set_err_rsp(work); - ksmbd_debug(SMB, "Error response: %x\n", rsp->hdr.Status); - } - - kfree(name); - kfree(lc); - - return 0; -} - -static int readdir_info_level_struct_sz(int info_level) -{ - switch (info_level) { - case FILE_FULL_DIRECTORY_INFORMATION: - return sizeof(struct file_full_directory_info); - case FILE_BOTH_DIRECTORY_INFORMATION: - return sizeof(struct file_both_directory_info); - case FILE_DIRECTORY_INFORMATION: - return sizeof(struct file_directory_info); - case FILE_NAMES_INFORMATION: - return sizeof(struct file_names_info); - case FILEID_FULL_DIRECTORY_INFORMATION: - return sizeof(struct file_id_full_dir_info); - case FILEID_BOTH_DIRECTORY_INFORMATION: - return sizeof(struct file_id_both_directory_info); - case SMB_FIND_FILE_POSIX_INFO: - return sizeof(struct smb2_posix_info); - default: - return -EOPNOTSUPP; - } -} - -static int dentry_name(struct ksmbd_dir_info *d_info, int info_level) -{ - switch (info_level) { - case FILE_FULL_DIRECTORY_INFORMATION: - { - struct file_full_directory_info *ffdinfo; - - ffdinfo = (struct file_full_directory_info *)d_info->rptr; - d_info->rptr += le32_to_cpu(ffdinfo->NextEntryOffset); - d_info->name = ffdinfo->FileName; - d_info->name_len = le32_to_cpu(ffdinfo->FileNameLength); - return 0; - } - case FILE_BOTH_DIRECTORY_INFORMATION: - { - struct file_both_directory_info *fbdinfo; - - fbdinfo = (struct file_both_directory_info *)d_info->rptr; - d_info->rptr += le32_to_cpu(fbdinfo->NextEntryOffset); - d_info->name = fbdinfo->FileName; - d_info->name_len = le32_to_cpu(fbdinfo->FileNameLength); - return 0; - } - case FILE_DIRECTORY_INFORMATION: - { - struct file_directory_info *fdinfo; - - fdinfo = (struct file_directory_info *)d_info->rptr; - d_info->rptr += le32_to_cpu(fdinfo->NextEntryOffset); - d_info->name = fdinfo->FileName; - d_info->name_len = le32_to_cpu(fdinfo->FileNameLength); - return 0; - } - case FILE_NAMES_INFORMATION: - { - struct file_names_info *fninfo; - - fninfo = (struct file_names_info *)d_info->rptr; - d_info->rptr += le32_to_cpu(fninfo->NextEntryOffset); - d_info->name = fninfo->FileName; - d_info->name_len = le32_to_cpu(fninfo->FileNameLength); - return 0; - } - case FILEID_FULL_DIRECTORY_INFORMATION: - { - struct file_id_full_dir_info *dinfo; - - dinfo = (struct file_id_full_dir_info *)d_info->rptr; - d_info->rptr += le32_to_cpu(dinfo->NextEntryOffset); - d_info->name = dinfo->FileName; - d_info->name_len = le32_to_cpu(dinfo->FileNameLength); - return 0; - } - case FILEID_BOTH_DIRECTORY_INFORMATION: - { - struct file_id_both_directory_info *fibdinfo; - - fibdinfo = (struct file_id_both_directory_info *)d_info->rptr; - d_info->rptr += le32_to_cpu(fibdinfo->NextEntryOffset); - d_info->name = fibdinfo->FileName; - d_info->name_len = le32_to_cpu(fibdinfo->FileNameLength); - return 0; - } - case SMB_FIND_FILE_POSIX_INFO: - { - struct smb2_posix_info *posix_info; - - posix_info = (struct smb2_posix_info *)d_info->rptr; - d_info->rptr += le32_to_cpu(posix_info->NextEntryOffset); - d_info->name = posix_info->name; - d_info->name_len = le32_to_cpu(posix_info->name_len); - return 0; - } - default: - return -EINVAL; - } -} - -/** - * smb2_populate_readdir_entry() - encode directory entry in smb2 response - * buffer - * @conn: connection instance - * @info_level: smb information level - * @d_info: structure included variables for query dir - * @ksmbd_kstat: ksmbd wrapper of dirent stat information - * - * if directory has many entries, find first can't read it fully. - * find next might be called multiple times to read remaining dir entries - * - * Return: 0 on success, otherwise error - */ -static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level, - struct ksmbd_dir_info *d_info, - struct ksmbd_kstat *ksmbd_kstat) -{ - int next_entry_offset = 0; - char *conv_name; - int conv_len; - void *kstat; - int struct_sz, rc = 0; - - conv_name = ksmbd_convert_dir_info_name(d_info, - conn->local_nls, - &conv_len); - if (!conv_name) - return -ENOMEM; - - /* Somehow the name has only terminating NULL bytes */ - if (conv_len < 0) { - rc = -EINVAL; - goto free_conv_name; - } - - struct_sz = readdir_info_level_struct_sz(info_level) - 1 + conv_len; - next_entry_offset = ALIGN(struct_sz, KSMBD_DIR_INFO_ALIGNMENT); - d_info->last_entry_off_align = next_entry_offset - struct_sz; - - if (next_entry_offset > d_info->out_buf_len) { - d_info->out_buf_len = 0; - rc = -ENOSPC; - goto free_conv_name; - } - - kstat = d_info->wptr; - if (info_level != FILE_NAMES_INFORMATION) - kstat = ksmbd_vfs_init_kstat(&d_info->wptr, ksmbd_kstat); - - switch (info_level) { - case FILE_FULL_DIRECTORY_INFORMATION: - { - struct file_full_directory_info *ffdinfo; - - ffdinfo = (struct file_full_directory_info *)kstat; - ffdinfo->FileNameLength = cpu_to_le32(conv_len); - ffdinfo->EaSize = - smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode); - if (ffdinfo->EaSize) - ffdinfo->ExtFileAttributes = FILE_ATTRIBUTE_REPARSE_POINT_LE; - if (d_info->hide_dot_file && d_info->name[0] == '.') - ffdinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE; - memcpy(ffdinfo->FileName, conv_name, conv_len); - ffdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case FILE_BOTH_DIRECTORY_INFORMATION: - { - struct file_both_directory_info *fbdinfo; - - fbdinfo = (struct file_both_directory_info *)kstat; - fbdinfo->FileNameLength = cpu_to_le32(conv_len); - fbdinfo->EaSize = - smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode); - if (fbdinfo->EaSize) - fbdinfo->ExtFileAttributes = FILE_ATTRIBUTE_REPARSE_POINT_LE; - fbdinfo->ShortNameLength = 0; - fbdinfo->Reserved = 0; - if (d_info->hide_dot_file && d_info->name[0] == '.') - fbdinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE; - memcpy(fbdinfo->FileName, conv_name, conv_len); - fbdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case FILE_DIRECTORY_INFORMATION: - { - struct file_directory_info *fdinfo; - - fdinfo = (struct file_directory_info *)kstat; - fdinfo->FileNameLength = cpu_to_le32(conv_len); - if (d_info->hide_dot_file && d_info->name[0] == '.') - fdinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE; - memcpy(fdinfo->FileName, conv_name, conv_len); - fdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case FILE_NAMES_INFORMATION: - { - struct file_names_info *fninfo; - - fninfo = (struct file_names_info *)kstat; - fninfo->FileNameLength = cpu_to_le32(conv_len); - memcpy(fninfo->FileName, conv_name, conv_len); - fninfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case FILEID_FULL_DIRECTORY_INFORMATION: - { - struct file_id_full_dir_info *dinfo; - - dinfo = (struct file_id_full_dir_info *)kstat; - dinfo->FileNameLength = cpu_to_le32(conv_len); - dinfo->EaSize = - smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode); - if (dinfo->EaSize) - dinfo->ExtFileAttributes = FILE_ATTRIBUTE_REPARSE_POINT_LE; - dinfo->Reserved = 0; - dinfo->UniqueId = cpu_to_le64(ksmbd_kstat->kstat->ino); - if (d_info->hide_dot_file && d_info->name[0] == '.') - dinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE; - memcpy(dinfo->FileName, conv_name, conv_len); - dinfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case FILEID_BOTH_DIRECTORY_INFORMATION: - { - struct file_id_both_directory_info *fibdinfo; - - fibdinfo = (struct file_id_both_directory_info *)kstat; - fibdinfo->FileNameLength = cpu_to_le32(conv_len); - fibdinfo->EaSize = - smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode); - if (fibdinfo->EaSize) - fibdinfo->ExtFileAttributes = FILE_ATTRIBUTE_REPARSE_POINT_LE; - fibdinfo->UniqueId = cpu_to_le64(ksmbd_kstat->kstat->ino); - fibdinfo->ShortNameLength = 0; - fibdinfo->Reserved = 0; - fibdinfo->Reserved2 = cpu_to_le16(0); - if (d_info->hide_dot_file && d_info->name[0] == '.') - fibdinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE; - memcpy(fibdinfo->FileName, conv_name, conv_len); - fibdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case SMB_FIND_FILE_POSIX_INFO: - { - struct smb2_posix_info *posix_info; - u64 time; - - posix_info = (struct smb2_posix_info *)kstat; - posix_info->Ignored = 0; - posix_info->CreationTime = cpu_to_le64(ksmbd_kstat->create_time); - time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime); - posix_info->ChangeTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->atime); - posix_info->LastAccessTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->mtime); - posix_info->LastWriteTime = cpu_to_le64(time); - posix_info->EndOfFile = cpu_to_le64(ksmbd_kstat->kstat->size); - posix_info->AllocationSize = cpu_to_le64(ksmbd_kstat->kstat->blocks << 9); - posix_info->DeviceId = cpu_to_le32(ksmbd_kstat->kstat->rdev); - posix_info->HardLinks = cpu_to_le32(ksmbd_kstat->kstat->nlink); - posix_info->Mode = cpu_to_le32(ksmbd_kstat->kstat->mode & 0777); - posix_info->Inode = cpu_to_le64(ksmbd_kstat->kstat->ino); - posix_info->DosAttributes = - S_ISDIR(ksmbd_kstat->kstat->mode) ? - FILE_ATTRIBUTE_DIRECTORY_LE : FILE_ATTRIBUTE_ARCHIVE_LE; - if (d_info->hide_dot_file && d_info->name[0] == '.') - 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), - SIDUNIX_USER, (struct smb_sid *)&posix_info->SidBuffer[0]); - id_to_sid(from_kgid_munged(&init_user_ns, ksmbd_kstat->kstat->gid), - SIDUNIX_GROUP, (struct smb_sid *)&posix_info->SidBuffer[16]); - memcpy(posix_info->name, conv_name, conv_len); - posix_info->name_len = cpu_to_le32(conv_len); - posix_info->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - - } /* switch (info_level) */ - - d_info->last_entry_offset = d_info->data_count; - d_info->data_count += next_entry_offset; - d_info->out_buf_len -= next_entry_offset; - d_info->wptr += next_entry_offset; - - ksmbd_debug(SMB, - "info_level : %d, buf_len :%d, next_offset : %d, data_count : %d\n", - info_level, d_info->out_buf_len, - next_entry_offset, d_info->data_count); - -free_conv_name: - kfree(conv_name); - return rc; -} - -struct smb2_query_dir_private { - struct ksmbd_work *work; - char *search_pattern; - struct ksmbd_file *dir_fp; - - struct ksmbd_dir_info *d_info; - int info_level; -}; - -static void lock_dir(struct ksmbd_file *dir_fp) -{ - struct dentry *dir = dir_fp->filp->f_path.dentry; - - inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); -} - -static void unlock_dir(struct ksmbd_file *dir_fp) -{ - struct dentry *dir = dir_fp->filp->f_path.dentry; - - inode_unlock(d_inode(dir)); -} - -static int process_query_dir_entries(struct smb2_query_dir_private *priv) -{ - struct user_namespace *user_ns = file_mnt_user_ns(priv->dir_fp->filp); - struct kstat kstat; - struct ksmbd_kstat ksmbd_kstat; - int rc; - int i; - - for (i = 0; i < priv->d_info->num_entry; i++) { - struct dentry *dent; - - if (dentry_name(priv->d_info, priv->info_level)) - return -EINVAL; - - lock_dir(priv->dir_fp); - dent = lookup_one(user_ns, priv->d_info->name, - priv->dir_fp->filp->f_path.dentry, - priv->d_info->name_len); - unlock_dir(priv->dir_fp); - - if (IS_ERR(dent)) { - ksmbd_debug(SMB, "Cannot lookup `%s' [%ld]\n", - priv->d_info->name, - PTR_ERR(dent)); - continue; - } - if (unlikely(d_is_negative(dent))) { - dput(dent); - ksmbd_debug(SMB, "Negative dentry `%s'\n", - priv->d_info->name); - continue; - } - - ksmbd_kstat.kstat = &kstat; - if (priv->info_level != FILE_NAMES_INFORMATION) - ksmbd_vfs_fill_dentry_attrs(priv->work, - user_ns, - dent, - &ksmbd_kstat); - - rc = smb2_populate_readdir_entry(priv->work->conn, - priv->info_level, - priv->d_info, - &ksmbd_kstat); - dput(dent); - if (rc) - return rc; - } - return 0; -} - -static int reserve_populate_dentry(struct ksmbd_dir_info *d_info, - int info_level) -{ - int struct_sz; - int conv_len; - int next_entry_offset; - - struct_sz = readdir_info_level_struct_sz(info_level); - if (struct_sz == -EOPNOTSUPP) - return -EOPNOTSUPP; - - conv_len = (d_info->name_len + 1) * 2; - next_entry_offset = ALIGN(struct_sz - 1 + conv_len, - KSMBD_DIR_INFO_ALIGNMENT); - - if (next_entry_offset > d_info->out_buf_len) { - d_info->out_buf_len = 0; - return -ENOSPC; - } - - switch (info_level) { - case FILE_FULL_DIRECTORY_INFORMATION: - { - struct file_full_directory_info *ffdinfo; - - ffdinfo = (struct file_full_directory_info *)d_info->wptr; - memcpy(ffdinfo->FileName, d_info->name, d_info->name_len); - ffdinfo->FileName[d_info->name_len] = 0x00; - ffdinfo->FileNameLength = cpu_to_le32(d_info->name_len); - ffdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case FILE_BOTH_DIRECTORY_INFORMATION: - { - struct file_both_directory_info *fbdinfo; - - fbdinfo = (struct file_both_directory_info *)d_info->wptr; - memcpy(fbdinfo->FileName, d_info->name, d_info->name_len); - fbdinfo->FileName[d_info->name_len] = 0x00; - fbdinfo->FileNameLength = cpu_to_le32(d_info->name_len); - fbdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case FILE_DIRECTORY_INFORMATION: - { - struct file_directory_info *fdinfo; - - fdinfo = (struct file_directory_info *)d_info->wptr; - memcpy(fdinfo->FileName, d_info->name, d_info->name_len); - fdinfo->FileName[d_info->name_len] = 0x00; - fdinfo->FileNameLength = cpu_to_le32(d_info->name_len); - fdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case FILE_NAMES_INFORMATION: - { - struct file_names_info *fninfo; - - fninfo = (struct file_names_info *)d_info->wptr; - memcpy(fninfo->FileName, d_info->name, d_info->name_len); - fninfo->FileName[d_info->name_len] = 0x00; - fninfo->FileNameLength = cpu_to_le32(d_info->name_len); - fninfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case FILEID_FULL_DIRECTORY_INFORMATION: - { - struct file_id_full_dir_info *dinfo; - - dinfo = (struct file_id_full_dir_info *)d_info->wptr; - memcpy(dinfo->FileName, d_info->name, d_info->name_len); - dinfo->FileName[d_info->name_len] = 0x00; - dinfo->FileNameLength = cpu_to_le32(d_info->name_len); - dinfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case FILEID_BOTH_DIRECTORY_INFORMATION: - { - struct file_id_both_directory_info *fibdinfo; - - fibdinfo = (struct file_id_both_directory_info *)d_info->wptr; - memcpy(fibdinfo->FileName, d_info->name, d_info->name_len); - fibdinfo->FileName[d_info->name_len] = 0x00; - fibdinfo->FileNameLength = cpu_to_le32(d_info->name_len); - fibdinfo->NextEntryOffset = cpu_to_le32(next_entry_offset); - break; - } - case SMB_FIND_FILE_POSIX_INFO: - { - struct smb2_posix_info *posix_info; - - posix_info = (struct smb2_posix_info *)d_info->wptr; - memcpy(posix_info->name, d_info->name, d_info->name_len); - posix_info->name[d_info->name_len] = 0x00; - posix_info->name_len = cpu_to_le32(d_info->name_len); - posix_info->NextEntryOffset = - cpu_to_le32(next_entry_offset); - break; - } - } /* switch (info_level) */ - - d_info->num_entry++; - d_info->out_buf_len -= next_entry_offset; - d_info->wptr += next_entry_offset; - return 0; -} - -static bool __query_dir(struct dir_context *ctx, const char *name, int namlen, - loff_t offset, u64 ino, unsigned int d_type) -{ - struct ksmbd_readdir_data *buf; - struct smb2_query_dir_private *priv; - struct ksmbd_dir_info *d_info; - int rc; - - buf = container_of(ctx, struct ksmbd_readdir_data, ctx); - priv = buf->private; - d_info = priv->d_info; - - /* dot and dotdot entries are already reserved */ - if (!strcmp(".", name) || !strcmp("..", name)) - return true; - if (ksmbd_share_veto_filename(priv->work->tcon->share_conf, name)) - return true; - if (!match_pattern(name, namlen, priv->search_pattern)) - return true; - - d_info->name = name; - d_info->name_len = namlen; - rc = reserve_populate_dentry(d_info, priv->info_level); - if (rc) - return false; - if (d_info->flags & SMB2_RETURN_SINGLE_ENTRY) - d_info->out_buf_len = 0; - return true; -} - -static int verify_info_level(int info_level) -{ - switch (info_level) { - case FILE_FULL_DIRECTORY_INFORMATION: - case FILE_BOTH_DIRECTORY_INFORMATION: - case FILE_DIRECTORY_INFORMATION: - case FILE_NAMES_INFORMATION: - case FILEID_FULL_DIRECTORY_INFORMATION: - case FILEID_BOTH_DIRECTORY_INFORMATION: - case SMB_FIND_FILE_POSIX_INFO: - break; - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static int smb2_resp_buf_len(struct ksmbd_work *work, unsigned short hdr2_len) -{ - int free_len; - - free_len = (int)(work->response_sz - - (get_rfc1002_len(work->response_buf) + 4)) - hdr2_len; - return free_len; -} - -static int smb2_calc_max_out_buf_len(struct ksmbd_work *work, - unsigned short hdr2_len, - unsigned int out_buf_len) -{ - int free_len; - - if (out_buf_len > work->conn->vals->max_trans_size) - return -EINVAL; - - free_len = smb2_resp_buf_len(work, hdr2_len); - if (free_len < 0) - return -EINVAL; - - return min_t(int, out_buf_len, free_len); -} - -int smb2_query_dir(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_query_directory_req *req; - struct smb2_query_directory_rsp *rsp; - struct ksmbd_share_config *share = work->tcon->share_conf; - struct ksmbd_file *dir_fp = NULL; - struct ksmbd_dir_info d_info; - int rc = 0; - char *srch_ptr = NULL; - unsigned char srch_flag; - int buffer_sz; - struct smb2_query_dir_private query_dir_private = {NULL, }; - - WORK_BUFFERS(work, req, rsp); - - if (ksmbd_override_fsids(work)) { - rsp->hdr.Status = STATUS_NO_MEMORY; - smb2_set_err_rsp(work); - return -ENOMEM; - } - - rc = verify_info_level(req->FileInformationClass); - if (rc) { - rc = -EFAULT; - goto err_out2; - } - - dir_fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); - if (!dir_fp) { - rc = -EBADF; - goto err_out2; - } - - if (!(dir_fp->daccess & FILE_LIST_DIRECTORY_LE) || - inode_permission(file_mnt_user_ns(dir_fp->filp), - file_inode(dir_fp->filp), - MAY_READ | MAY_EXEC)) { - pr_err("no right to enumerate directory (%pD)\n", dir_fp->filp); - rc = -EACCES; - goto err_out2; - } - - if (!S_ISDIR(file_inode(dir_fp->filp)->i_mode)) { - pr_err("can't do query dir for a file\n"); - rc = -EINVAL; - goto err_out2; - } - - srch_flag = req->Flags; - srch_ptr = smb_strndup_from_utf16(req->Buffer, - le16_to_cpu(req->FileNameLength), 1, - conn->local_nls); - if (IS_ERR(srch_ptr)) { - ksmbd_debug(SMB, "Search Pattern not found\n"); - rc = -EINVAL; - goto err_out2; - } else { - ksmbd_debug(SMB, "Search pattern is %s\n", srch_ptr); - } - - if (srch_flag & SMB2_REOPEN || srch_flag & SMB2_RESTART_SCANS) { - ksmbd_debug(SMB, "Restart directory scan\n"); - generic_file_llseek(dir_fp->filp, 0, SEEK_SET); - } - - memset(&d_info, 0, sizeof(struct ksmbd_dir_info)); - d_info.wptr = (char *)rsp->Buffer; - d_info.rptr = (char *)rsp->Buffer; - d_info.out_buf_len = - smb2_calc_max_out_buf_len(work, 8, - le32_to_cpu(req->OutputBufferLength)); - if (d_info.out_buf_len < 0) { - rc = -EINVAL; - goto err_out; - } - d_info.flags = srch_flag; - - /* - * reserve dot and dotdot entries in head of buffer - * in first response - */ - rc = ksmbd_populate_dot_dotdot_entries(work, req->FileInformationClass, - dir_fp, &d_info, srch_ptr, - smb2_populate_readdir_entry); - if (rc == -ENOSPC) - rc = 0; - else if (rc) - goto err_out; - - if (test_share_config_flag(share, KSMBD_SHARE_FLAG_HIDE_DOT_FILES)) - d_info.hide_dot_file = true; - - buffer_sz = d_info.out_buf_len; - d_info.rptr = d_info.wptr; - query_dir_private.work = work; - query_dir_private.search_pattern = srch_ptr; - query_dir_private.dir_fp = dir_fp; - query_dir_private.d_info = &d_info; - query_dir_private.info_level = req->FileInformationClass; - dir_fp->readdir_data.private = &query_dir_private; - set_ctx_actor(&dir_fp->readdir_data.ctx, __query_dir); - - rc = iterate_dir(dir_fp->filp, &dir_fp->readdir_data.ctx); - /* - * req->OutputBufferLength is too small to contain even one entry. - * In this case, it immediately returns OutputBufferLength 0 to client. - */ - if (!d_info.out_buf_len && !d_info.num_entry) - goto no_buf_len; - if (rc > 0 || rc == -ENOSPC) - rc = 0; - else if (rc) - goto err_out; - - d_info.wptr = d_info.rptr; - d_info.out_buf_len = buffer_sz; - rc = process_query_dir_entries(&query_dir_private); - if (rc) - goto err_out; - - if (!d_info.data_count && d_info.out_buf_len >= 0) { - if (srch_flag & SMB2_RETURN_SINGLE_ENTRY && !is_asterisk(srch_ptr)) { - rsp->hdr.Status = STATUS_NO_SUCH_FILE; - } else { - dir_fp->dot_dotdot[0] = dir_fp->dot_dotdot[1] = 0; - rsp->hdr.Status = STATUS_NO_MORE_FILES; - } - rsp->StructureSize = cpu_to_le16(9); - rsp->OutputBufferOffset = cpu_to_le16(0); - rsp->OutputBufferLength = cpu_to_le32(0); - rsp->Buffer[0] = 0; - inc_rfc1001_len(work->response_buf, 9); - } else { -no_buf_len: - ((struct file_directory_info *) - ((char *)rsp->Buffer + d_info.last_entry_offset)) - ->NextEntryOffset = 0; - if (d_info.data_count >= d_info.last_entry_off_align) - d_info.data_count -= d_info.last_entry_off_align; - - rsp->StructureSize = cpu_to_le16(9); - rsp->OutputBufferOffset = cpu_to_le16(72); - rsp->OutputBufferLength = cpu_to_le32(d_info.data_count); - inc_rfc1001_len(work->response_buf, 8 + d_info.data_count); - } - - kfree(srch_ptr); - ksmbd_fd_put(work, dir_fp); - ksmbd_revert_fsids(work); - return 0; - -err_out: - pr_err("error while processing smb2 query dir rc = %d\n", rc); - kfree(srch_ptr); - -err_out2: - if (rc == -EINVAL) - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - else if (rc == -EACCES) - rsp->hdr.Status = STATUS_ACCESS_DENIED; - else if (rc == -ENOENT) - rsp->hdr.Status = STATUS_NO_SUCH_FILE; - else if (rc == -EBADF) - rsp->hdr.Status = STATUS_FILE_CLOSED; - else if (rc == -ENOMEM) - rsp->hdr.Status = STATUS_NO_MEMORY; - else if (rc == -EFAULT) - rsp->hdr.Status = STATUS_INVALID_INFO_CLASS; - else if (rc == -EIO) - rsp->hdr.Status = STATUS_FILE_CORRUPT_ERROR; - if (!rsp->hdr.Status) - rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR; - - smb2_set_err_rsp(work); - ksmbd_fd_put(work, dir_fp); - ksmbd_revert_fsids(work); - return 0; -} - -/** - * buffer_check_err() - helper function to check buffer errors - * @reqOutputBufferLength: max buffer length expected in command response - * @rsp: query info response buffer contains output buffer length - * @rsp_org: base response buffer pointer in case of chained response - * @infoclass_size: query info class response buffer size - * - * Return: 0 on success, otherwise error - */ -static int buffer_check_err(int reqOutputBufferLength, - struct smb2_query_info_rsp *rsp, - void *rsp_org, int infoclass_size) -{ - if (reqOutputBufferLength < le32_to_cpu(rsp->OutputBufferLength)) { - if (reqOutputBufferLength < infoclass_size) { - pr_err("Invalid Buffer Size Requested\n"); - rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH; - *(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr)); - return -EINVAL; - } - - ksmbd_debug(SMB, "Buffer Overflow\n"); - rsp->hdr.Status = STATUS_BUFFER_OVERFLOW; - *(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr) + - reqOutputBufferLength); - rsp->OutputBufferLength = cpu_to_le32(reqOutputBufferLength); - } - return 0; -} - -static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp, - void *rsp_org) -{ - struct smb2_file_standard_info *sinfo; - - sinfo = (struct smb2_file_standard_info *)rsp->Buffer; - - sinfo->AllocationSize = cpu_to_le64(4096); - sinfo->EndOfFile = cpu_to_le64(0); - sinfo->NumberOfLinks = cpu_to_le32(1); - sinfo->DeletePending = 1; - sinfo->Directory = 0; - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_standard_info)); - inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_standard_info)); -} - -static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num, - void *rsp_org) -{ - struct smb2_file_internal_info *file_info; - - file_info = (struct smb2_file_internal_info *)rsp->Buffer; - - /* any unique number */ - file_info->IndexNumber = cpu_to_le64(num | (1ULL << 63)); - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_internal_info)); - inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_internal_info)); -} - -static int smb2_get_info_file_pipe(struct ksmbd_session *sess, - struct smb2_query_info_req *req, - struct smb2_query_info_rsp *rsp, - void *rsp_org) -{ - u64 id; - int rc; - - /* - * Windows can sometime send query file info request on - * pipe without opening it, checking error condition here - */ - id = req->VolatileFileId; - if (!ksmbd_session_rpc_method(sess, id)) - return -ENOENT; - - ksmbd_debug(SMB, "FileInfoClass %u, FileId 0x%llx\n", - req->FileInfoClass, req->VolatileFileId); - - switch (req->FileInfoClass) { - case FILE_STANDARD_INFORMATION: - get_standard_info_pipe(rsp, rsp_org); - rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), - rsp, rsp_org, - FILE_STANDARD_INFORMATION_SIZE); - break; - case FILE_INTERNAL_INFORMATION: - get_internal_info_pipe(rsp, id, rsp_org); - rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), - rsp, rsp_org, - FILE_INTERNAL_INFORMATION_SIZE); - break; - default: - ksmbd_debug(SMB, "smb2_info_file_pipe for %u not supported\n", - req->FileInfoClass); - rc = -EOPNOTSUPP; - } - return rc; -} - -/** - * smb2_get_ea() - handler for smb2 get extended attribute command - * @work: smb work containing query info command buffer - * @fp: ksmbd_file pointer - * @req: get extended attribute request - * @rsp: response buffer pointer - * @rsp_org: base response buffer pointer in case of chained response - * - * Return: 0 on success, otherwise error - */ -static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp, - struct smb2_query_info_req *req, - struct smb2_query_info_rsp *rsp, void *rsp_org) -{ - struct smb2_ea_info *eainfo, *prev_eainfo; - char *name, *ptr, *xattr_list = NULL, *buf; - int rc, name_len, value_len, xattr_list_len, idx; - ssize_t buf_free_len, alignment_bytes, next_offset, rsp_data_cnt = 0; - struct smb2_ea_info_req *ea_req = NULL; - const struct path *path; - struct user_namespace *user_ns = file_mnt_user_ns(fp->filp); - - if (!(fp->daccess & FILE_READ_EA_LE)) { - pr_err("Not permitted to read ext attr : 0x%x\n", - fp->daccess); - return -EACCES; - } - - path = &fp->filp->f_path; - /* single EA entry is requested with given user.* name */ - if (req->InputBufferLength) { - if (le32_to_cpu(req->InputBufferLength) < - sizeof(struct smb2_ea_info_req)) - return -EINVAL; - - ea_req = (struct smb2_ea_info_req *)req->Buffer; - } else { - /* need to send all EAs, if no specific EA is requested*/ - if (le32_to_cpu(req->Flags) & SL_RETURN_SINGLE_ENTRY) - ksmbd_debug(SMB, - "All EAs are requested but need to send single EA entry in rsp flags 0x%x\n", - le32_to_cpu(req->Flags)); - } - - buf_free_len = - smb2_calc_max_out_buf_len(work, 8, - le32_to_cpu(req->OutputBufferLength)); - if (buf_free_len < 0) - return -EINVAL; - - rc = ksmbd_vfs_listxattr(path->dentry, &xattr_list); - if (rc < 0) { - rsp->hdr.Status = STATUS_INVALID_HANDLE; - goto out; - } else if (!rc) { /* there is no EA in the file */ - ksmbd_debug(SMB, "no ea data in the file\n"); - goto done; - } - xattr_list_len = rc; - - ptr = (char *)rsp->Buffer; - eainfo = (struct smb2_ea_info *)ptr; - prev_eainfo = eainfo; - idx = 0; - - while (idx < xattr_list_len) { - name = xattr_list + idx; - name_len = strlen(name); - - ksmbd_debug(SMB, "%s, len %d\n", name, name_len); - idx += name_len + 1; - - /* - * CIFS does not support EA other than user.* namespace, - * still keep the framework generic, to list other attrs - * in future. - */ - if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) - continue; - - if (!strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX, - STREAM_PREFIX_LEN)) - continue; - - if (req->InputBufferLength && - strncmp(&name[XATTR_USER_PREFIX_LEN], ea_req->name, - ea_req->EaNameLength)) - continue; - - if (!strncmp(&name[XATTR_USER_PREFIX_LEN], - DOS_ATTRIBUTE_PREFIX, DOS_ATTRIBUTE_PREFIX_LEN)) - continue; - - if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) - name_len -= XATTR_USER_PREFIX_LEN; - - ptr = (char *)(&eainfo->name + name_len + 1); - buf_free_len -= (offsetof(struct smb2_ea_info, name) + - name_len + 1); - /* bailout if xattr can't fit in buf_free_len */ - value_len = ksmbd_vfs_getxattr(user_ns, path->dentry, - name, &buf); - if (value_len <= 0) { - rc = -ENOENT; - rsp->hdr.Status = STATUS_INVALID_HANDLE; - goto out; - } - - buf_free_len -= value_len; - if (buf_free_len < 0) { - kfree(buf); - break; - } - - memcpy(ptr, buf, value_len); - kfree(buf); - - ptr += value_len; - eainfo->Flags = 0; - eainfo->EaNameLength = name_len; - - if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) - memcpy(eainfo->name, &name[XATTR_USER_PREFIX_LEN], - name_len); - else - memcpy(eainfo->name, name, name_len); - - eainfo->name[name_len] = '\0'; - eainfo->EaValueLength = cpu_to_le16(value_len); - next_offset = offsetof(struct smb2_ea_info, name) + - name_len + 1 + value_len; - - /* align next xattr entry at 4 byte bundary */ - alignment_bytes = ((next_offset + 3) & ~3) - next_offset; - if (alignment_bytes) { - memset(ptr, '\0', alignment_bytes); - ptr += alignment_bytes; - next_offset += alignment_bytes; - buf_free_len -= alignment_bytes; - } - eainfo->NextEntryOffset = cpu_to_le32(next_offset); - prev_eainfo = eainfo; - eainfo = (struct smb2_ea_info *)ptr; - rsp_data_cnt += next_offset; - - if (req->InputBufferLength) { - ksmbd_debug(SMB, "single entry requested\n"); - break; - } - } - - /* no more ea entries */ - prev_eainfo->NextEntryOffset = 0; -done: - rc = 0; - if (rsp_data_cnt == 0) - rsp->hdr.Status = STATUS_NO_EAS_ON_FILE; - rsp->OutputBufferLength = cpu_to_le32(rsp_data_cnt); - inc_rfc1001_len(rsp_org, rsp_data_cnt); -out: - kvfree(xattr_list); - return rc; -} - -static void get_file_access_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) -{ - struct smb2_file_access_info *file_info; - - file_info = (struct smb2_file_access_info *)rsp->Buffer; - file_info->AccessFlags = fp->daccess; - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_access_info)); - inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_access_info)); -} - -static int get_file_basic_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) -{ - struct smb2_file_basic_info *basic_info; - struct kstat stat; - u64 time; - - if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { - pr_err("no right to read the attributes : 0x%x\n", - fp->daccess); - return -EACCES; - } - - basic_info = (struct smb2_file_basic_info *)rsp->Buffer; - generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp), - &stat); - basic_info->CreationTime = cpu_to_le64(fp->create_time); - time = ksmbd_UnixTimeToNT(stat.atime); - basic_info->LastAccessTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(stat.mtime); - basic_info->LastWriteTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(stat.ctime); - basic_info->ChangeTime = cpu_to_le64(time); - basic_info->Attributes = fp->f_ci->m_fattr; - basic_info->Pad1 = 0; - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_basic_info)); - inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_basic_info)); - return 0; -} - -static void get_file_standard_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) -{ - struct smb2_file_standard_info *sinfo; - unsigned int delete_pending; - struct inode *inode; - struct kstat stat; - - inode = file_inode(fp->filp); - generic_fillattr(file_mnt_user_ns(fp->filp), inode, &stat); - - sinfo = (struct smb2_file_standard_info *)rsp->Buffer; - delete_pending = ksmbd_inode_pending_delete(fp); - - sinfo->AllocationSize = cpu_to_le64(inode->i_blocks << 9); - sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); - sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending); - sinfo->DeletePending = delete_pending; - sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0; - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_standard_info)); - inc_rfc1001_len(rsp_org, - sizeof(struct smb2_file_standard_info)); -} - -static void get_file_alignment_info(struct smb2_query_info_rsp *rsp, - void *rsp_org) -{ - struct smb2_file_alignment_info *file_info; - - file_info = (struct smb2_file_alignment_info *)rsp->Buffer; - file_info->AlignmentRequirement = 0; - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_alignment_info)); - inc_rfc1001_len(rsp_org, - sizeof(struct smb2_file_alignment_info)); -} - -static int get_file_all_info(struct ksmbd_work *work, - struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, - void *rsp_org) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_file_all_info *file_info; - unsigned int delete_pending; - struct inode *inode; - struct kstat stat; - int conv_len; - char *filename; - u64 time; - - if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { - ksmbd_debug(SMB, "no right to read the attributes : 0x%x\n", - fp->daccess); - return -EACCES; - } - - filename = convert_to_nt_pathname(work->tcon->share_conf, &fp->filp->f_path); - if (IS_ERR(filename)) - return PTR_ERR(filename); - - inode = file_inode(fp->filp); - generic_fillattr(file_mnt_user_ns(fp->filp), inode, &stat); - - ksmbd_debug(SMB, "filename = %s\n", filename); - delete_pending = ksmbd_inode_pending_delete(fp); - file_info = (struct smb2_file_all_info *)rsp->Buffer; - - file_info->CreationTime = cpu_to_le64(fp->create_time); - time = ksmbd_UnixTimeToNT(stat.atime); - file_info->LastAccessTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(stat.mtime); - file_info->LastWriteTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(stat.ctime); - file_info->ChangeTime = cpu_to_le64(time); - file_info->Attributes = fp->f_ci->m_fattr; - file_info->Pad1 = 0; - file_info->AllocationSize = - cpu_to_le64(inode->i_blocks << 9); - file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); - file_info->NumberOfLinks = - cpu_to_le32(get_nlink(&stat) - delete_pending); - file_info->DeletePending = delete_pending; - file_info->Directory = S_ISDIR(stat.mode) ? 1 : 0; - file_info->Pad2 = 0; - file_info->IndexNumber = cpu_to_le64(stat.ino); - file_info->EASize = 0; - file_info->AccessFlags = fp->daccess; - file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos); - file_info->Mode = fp->coption; - file_info->AlignmentRequirement = 0; - conv_len = smbConvertToUTF16((__le16 *)file_info->FileName, filename, - PATH_MAX, conn->local_nls, 0); - conv_len *= 2; - file_info->FileNameLength = cpu_to_le32(conv_len); - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_all_info) + conv_len - 1); - kfree(filename); - inc_rfc1001_len(rsp_org, le32_to_cpu(rsp->OutputBufferLength)); - return 0; -} - -static void get_file_alternate_info(struct ksmbd_work *work, - struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, - void *rsp_org) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_file_alt_name_info *file_info; - struct dentry *dentry = fp->filp->f_path.dentry; - int conv_len; - - spin_lock(&dentry->d_lock); - file_info = (struct smb2_file_alt_name_info *)rsp->Buffer; - conv_len = ksmbd_extract_shortname(conn, - dentry->d_name.name, - file_info->FileName); - spin_unlock(&dentry->d_lock); - file_info->FileNameLength = cpu_to_le32(conv_len); - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_alt_name_info) + conv_len); - inc_rfc1001_len(rsp_org, le32_to_cpu(rsp->OutputBufferLength)); -} - -static void get_file_stream_info(struct ksmbd_work *work, - struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, - void *rsp_org) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_file_stream_info *file_info; - char *stream_name, *xattr_list = NULL, *stream_buf; - struct kstat stat; - const struct path *path = &fp->filp->f_path; - ssize_t xattr_list_len; - int nbytes = 0, streamlen, stream_name_len, next, idx = 0; - int buf_free_len; - struct smb2_query_info_req *req = ksmbd_req_buf_next(work); - - generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp), - &stat); - file_info = (struct smb2_file_stream_info *)rsp->Buffer; - - buf_free_len = - smb2_calc_max_out_buf_len(work, 8, - le32_to_cpu(req->OutputBufferLength)); - if (buf_free_len < 0) - goto out; - - xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list); - if (xattr_list_len < 0) { - goto out; - } else if (!xattr_list_len) { - ksmbd_debug(SMB, "empty xattr in the file\n"); - goto out; - } - - while (idx < xattr_list_len) { - stream_name = xattr_list + idx; - streamlen = strlen(stream_name); - idx += streamlen + 1; - - ksmbd_debug(SMB, "%s, len %d\n", stream_name, streamlen); - - if (strncmp(&stream_name[XATTR_USER_PREFIX_LEN], - STREAM_PREFIX, STREAM_PREFIX_LEN)) - continue; - - stream_name_len = streamlen - (XATTR_USER_PREFIX_LEN + - STREAM_PREFIX_LEN); - streamlen = stream_name_len; - - /* plus : size */ - streamlen += 1; - stream_buf = kmalloc(streamlen + 1, GFP_KERNEL); - if (!stream_buf) - break; - - streamlen = snprintf(stream_buf, streamlen + 1, - ":%s", &stream_name[XATTR_NAME_STREAM_LEN]); - - next = sizeof(struct smb2_file_stream_info) + streamlen * 2; - if (next > buf_free_len) { - kfree(stream_buf); - break; - } - - file_info = (struct smb2_file_stream_info *)&rsp->Buffer[nbytes]; - streamlen = smbConvertToUTF16((__le16 *)file_info->StreamName, - stream_buf, streamlen, - conn->local_nls, 0); - streamlen *= 2; - kfree(stream_buf); - file_info->StreamNameLength = cpu_to_le32(streamlen); - file_info->StreamSize = cpu_to_le64(stream_name_len); - file_info->StreamAllocationSize = cpu_to_le64(stream_name_len); - - nbytes += next; - buf_free_len -= next; - file_info->NextEntryOffset = cpu_to_le32(next); - } - -out: - if (!S_ISDIR(stat.mode) && - buf_free_len >= sizeof(struct smb2_file_stream_info) + 7 * 2) { - file_info = (struct smb2_file_stream_info *) - &rsp->Buffer[nbytes]; - streamlen = smbConvertToUTF16((__le16 *)file_info->StreamName, - "::$DATA", 7, conn->local_nls, 0); - streamlen *= 2; - file_info->StreamNameLength = cpu_to_le32(streamlen); - file_info->StreamSize = cpu_to_le64(stat.size); - file_info->StreamAllocationSize = cpu_to_le64(stat.blocks << 9); - nbytes += sizeof(struct smb2_file_stream_info) + streamlen; - } - - /* last entry offset should be 0 */ - file_info->NextEntryOffset = 0; - kvfree(xattr_list); - - rsp->OutputBufferLength = cpu_to_le32(nbytes); - inc_rfc1001_len(rsp_org, nbytes); -} - -static void get_file_internal_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) -{ - struct smb2_file_internal_info *file_info; - struct kstat stat; - - generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp), - &stat); - file_info = (struct smb2_file_internal_info *)rsp->Buffer; - file_info->IndexNumber = cpu_to_le64(stat.ino); - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_internal_info)); - inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_internal_info)); -} - -static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) -{ - struct smb2_file_ntwrk_info *file_info; - struct inode *inode; - struct kstat stat; - u64 time; - - if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { - pr_err("no right to read the attributes : 0x%x\n", - fp->daccess); - return -EACCES; - } - - file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer; - - inode = file_inode(fp->filp); - generic_fillattr(file_mnt_user_ns(fp->filp), inode, &stat); - - file_info->CreationTime = cpu_to_le64(fp->create_time); - time = ksmbd_UnixTimeToNT(stat.atime); - file_info->LastAccessTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(stat.mtime); - file_info->LastWriteTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(stat.ctime); - file_info->ChangeTime = cpu_to_le64(time); - file_info->Attributes = fp->f_ci->m_fattr; - file_info->AllocationSize = - cpu_to_le64(inode->i_blocks << 9); - file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); - file_info->Reserved = cpu_to_le32(0); - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_ntwrk_info)); - inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_ntwrk_info)); - return 0; -} - -static void get_file_ea_info(struct smb2_query_info_rsp *rsp, void *rsp_org) -{ - struct smb2_file_ea_info *file_info; - - file_info = (struct smb2_file_ea_info *)rsp->Buffer; - file_info->EASize = 0; - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_ea_info)); - inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_ea_info)); -} - -static void get_file_position_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) -{ - struct smb2_file_pos_info *file_info; - - file_info = (struct smb2_file_pos_info *)rsp->Buffer; - file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos); - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_pos_info)); - inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_pos_info)); -} - -static void get_file_mode_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) -{ - struct smb2_file_mode_info *file_info; - - file_info = (struct smb2_file_mode_info *)rsp->Buffer; - file_info->Mode = fp->coption & FILE_MODE_INFO_MASK; - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_mode_info)); - inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_mode_info)); -} - -static void get_file_compression_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) -{ - struct smb2_file_comp_info *file_info; - struct kstat stat; - - generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp), - &stat); - - file_info = (struct smb2_file_comp_info *)rsp->Buffer; - file_info->CompressedFileSize = cpu_to_le64(stat.blocks << 9); - file_info->CompressionFormat = COMPRESSION_FORMAT_NONE; - file_info->CompressionUnitShift = 0; - file_info->ChunkShift = 0; - file_info->ClusterShift = 0; - memset(&file_info->Reserved[0], 0, 3); - - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_comp_info)); - inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_comp_info)); -} - -static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) -{ - struct smb2_file_attr_tag_info *file_info; - - if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { - pr_err("no right to read the attributes : 0x%x\n", - fp->daccess); - return -EACCES; - } - - file_info = (struct smb2_file_attr_tag_info *)rsp->Buffer; - file_info->FileAttributes = fp->f_ci->m_fattr; - file_info->ReparseTag = 0; - rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_attr_tag_info)); - inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_attr_tag_info)); - return 0; -} - -static int find_file_posix_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) -{ - struct smb311_posix_qinfo *file_info; - 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; - int out_buf_len = sizeof(struct smb311_posix_qinfo) + 32; - - file_info = (struct smb311_posix_qinfo *)rsp->Buffer; - file_info->CreationTime = cpu_to_le64(fp->create_time); - time = ksmbd_UnixTimeToNT(inode->i_atime); - file_info->LastAccessTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(inode->i_mtime); - file_info->LastWriteTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(inode->i_ctime); - file_info->ChangeTime = cpu_to_le64(time); - file_info->DosAttributes = fp->f_ci->m_fattr; - file_info->Inode = cpu_to_le64(inode->i_ino); - file_info->EndOfFile = cpu_to_le64(inode->i_size); - file_info->AllocationSize = cpu_to_le64(inode->i_blocks << 9); - file_info->HardLinks = cpu_to_le32(inode->i_nlink); - file_info->Mode = cpu_to_le32(inode->i_mode & 0777); - file_info->DeviceId = cpu_to_le32(inode->i_rdev); - - /* - * Sids(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, 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, - struct smb2_query_info_req *req, - struct smb2_query_info_rsp *rsp) -{ - struct ksmbd_file *fp; - int fileinfoclass = 0; - int rc = 0; - int file_infoclass_size; - unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; - - if (test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_PIPE)) { - /* smb2 info file called for pipe */ - return smb2_get_info_file_pipe(work->sess, req, rsp, - work->response_buf); - } - - if (work->next_smb2_rcv_hdr_off) { - if (!has_file_id(req->VolatileFileId)) { - ksmbd_debug(SMB, "Compound request set FID = %llu\n", - work->compound_fid); - id = work->compound_fid; - pid = work->compound_pfid; - } - } - - if (!has_file_id(id)) { - id = req->VolatileFileId; - pid = req->PersistentFileId; - } - - fp = ksmbd_lookup_fd_slow(work, id, pid); - if (!fp) - return -ENOENT; - - fileinfoclass = req->FileInfoClass; - - switch (fileinfoclass) { - case FILE_ACCESS_INFORMATION: - get_file_access_info(rsp, fp, work->response_buf); - file_infoclass_size = FILE_ACCESS_INFORMATION_SIZE; - break; - - case FILE_BASIC_INFORMATION: - rc = get_file_basic_info(rsp, fp, work->response_buf); - file_infoclass_size = FILE_BASIC_INFORMATION_SIZE; - break; - - case FILE_STANDARD_INFORMATION: - get_file_standard_info(rsp, fp, work->response_buf); - file_infoclass_size = FILE_STANDARD_INFORMATION_SIZE; - break; - - case FILE_ALIGNMENT_INFORMATION: - get_file_alignment_info(rsp, work->response_buf); - file_infoclass_size = FILE_ALIGNMENT_INFORMATION_SIZE; - break; - - case FILE_ALL_INFORMATION: - rc = get_file_all_info(work, rsp, fp, work->response_buf); - file_infoclass_size = FILE_ALL_INFORMATION_SIZE; - break; - - case FILE_ALTERNATE_NAME_INFORMATION: - get_file_alternate_info(work, rsp, fp, work->response_buf); - file_infoclass_size = FILE_ALTERNATE_NAME_INFORMATION_SIZE; - break; - - case FILE_STREAM_INFORMATION: - get_file_stream_info(work, rsp, fp, work->response_buf); - file_infoclass_size = FILE_STREAM_INFORMATION_SIZE; - break; - - case FILE_INTERNAL_INFORMATION: - get_file_internal_info(rsp, fp, work->response_buf); - file_infoclass_size = FILE_INTERNAL_INFORMATION_SIZE; - break; - - case FILE_NETWORK_OPEN_INFORMATION: - rc = get_file_network_open_info(rsp, fp, work->response_buf); - file_infoclass_size = FILE_NETWORK_OPEN_INFORMATION_SIZE; - break; - - case FILE_EA_INFORMATION: - get_file_ea_info(rsp, work->response_buf); - file_infoclass_size = FILE_EA_INFORMATION_SIZE; - break; - - case FILE_FULL_EA_INFORMATION: - rc = smb2_get_ea(work, fp, req, rsp, work->response_buf); - file_infoclass_size = FILE_FULL_EA_INFORMATION_SIZE; - break; - - case FILE_POSITION_INFORMATION: - get_file_position_info(rsp, fp, work->response_buf); - file_infoclass_size = FILE_POSITION_INFORMATION_SIZE; - break; - - case FILE_MODE_INFORMATION: - get_file_mode_info(rsp, fp, work->response_buf); - file_infoclass_size = FILE_MODE_INFORMATION_SIZE; - break; - - case FILE_COMPRESSION_INFORMATION: - get_file_compression_info(rsp, fp, work->response_buf); - file_infoclass_size = FILE_COMPRESSION_INFORMATION_SIZE; - break; - - case FILE_ATTRIBUTE_TAG_INFORMATION: - rc = get_file_attribute_tag_info(rsp, fp, work->response_buf); - file_infoclass_size = FILE_ATTRIBUTE_TAG_INFORMATION_SIZE; - break; - case SMB_FIND_FILE_POSIX_INFO: - if (!work->tcon->posix_extensions) { - pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); - rc = -EOPNOTSUPP; - } else { - file_infoclass_size = find_file_posix_info(rsp, fp, - work->response_buf); - } - break; - default: - ksmbd_debug(SMB, "fileinfoclass %d not supported yet\n", - fileinfoclass); - rc = -EOPNOTSUPP; - } - if (!rc) - rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), - rsp, work->response_buf, - file_infoclass_size); - ksmbd_fd_put(work, fp); - return rc; -} - -static int smb2_get_info_filesystem(struct ksmbd_work *work, - struct smb2_query_info_req *req, - struct smb2_query_info_rsp *rsp) -{ - struct ksmbd_session *sess = work->sess; - struct ksmbd_conn *conn = work->conn; - struct ksmbd_share_config *share = work->tcon->share_conf; - int fsinfoclass = 0; - struct kstatfs stfs; - struct path path; - int rc = 0, len; - int fs_infoclass_size = 0; - - if (!share->path) - return -EIO; - - rc = kern_path(share->path, LOOKUP_NO_SYMLINKS, &path); - if (rc) { - pr_err("cannot create vfs path\n"); - return -EIO; - } - - rc = vfs_statfs(&path, &stfs); - if (rc) { - pr_err("cannot do stat of path %s\n", share->path); - path_put(&path); - return -EIO; - } - - fsinfoclass = req->FileInfoClass; - - switch (fsinfoclass) { - case FS_DEVICE_INFORMATION: - { - struct filesystem_device_info *info; - - info = (struct filesystem_device_info *)rsp->Buffer; - - info->DeviceType = cpu_to_le32(stfs.f_type); - info->DeviceCharacteristics = cpu_to_le32(0x00000020); - rsp->OutputBufferLength = cpu_to_le32(8); - inc_rfc1001_len(work->response_buf, 8); - fs_infoclass_size = FS_DEVICE_INFORMATION_SIZE; - break; - } - case FS_ATTRIBUTE_INFORMATION: - { - struct filesystem_attribute_info *info; - size_t sz; - - info = (struct filesystem_attribute_info *)rsp->Buffer; - info->Attributes = cpu_to_le32(FILE_SUPPORTS_OBJECT_IDS | - FILE_PERSISTENT_ACLS | - FILE_UNICODE_ON_DISK | - FILE_CASE_PRESERVED_NAMES | - FILE_CASE_SENSITIVE_SEARCH | - FILE_SUPPORTS_BLOCK_REFCOUNTING); - - info->Attributes |= cpu_to_le32(server_conf.share_fake_fscaps); - - if (test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_STREAMS)) - info->Attributes |= cpu_to_le32(FILE_NAMED_STREAMS); - - info->MaxPathNameComponentLength = cpu_to_le32(stfs.f_namelen); - len = smbConvertToUTF16((__le16 *)info->FileSystemName, - "NTFS", PATH_MAX, conn->local_nls, 0); - len = len * 2; - info->FileSystemNameLen = cpu_to_le32(len); - sz = sizeof(struct filesystem_attribute_info) - 2 + len; - rsp->OutputBufferLength = cpu_to_le32(sz); - inc_rfc1001_len(work->response_buf, sz); - fs_infoclass_size = FS_ATTRIBUTE_INFORMATION_SIZE; - break; - } - case FS_VOLUME_INFORMATION: - { - struct filesystem_vol_info *info; - size_t sz; - unsigned int serial_crc = 0; - - info = (struct filesystem_vol_info *)(rsp->Buffer); - info->VolumeCreationTime = 0; - serial_crc = crc32_le(serial_crc, share->name, - strlen(share->name)); - serial_crc = crc32_le(serial_crc, share->path, - strlen(share->path)); - serial_crc = crc32_le(serial_crc, ksmbd_netbios_name(), - strlen(ksmbd_netbios_name())); - /* Taking dummy value of serial number*/ - info->SerialNumber = cpu_to_le32(serial_crc); - len = smbConvertToUTF16((__le16 *)info->VolumeLabel, - share->name, PATH_MAX, - conn->local_nls, 0); - len = len * 2; - info->VolumeLabelSize = cpu_to_le32(len); - info->Reserved = 0; - sz = sizeof(struct filesystem_vol_info) - 2 + len; - rsp->OutputBufferLength = cpu_to_le32(sz); - inc_rfc1001_len(work->response_buf, sz); - fs_infoclass_size = FS_VOLUME_INFORMATION_SIZE; - break; - } - case FS_SIZE_INFORMATION: - { - struct filesystem_info *info; - - info = (struct filesystem_info *)(rsp->Buffer); - info->TotalAllocationUnits = cpu_to_le64(stfs.f_blocks); - info->FreeAllocationUnits = cpu_to_le64(stfs.f_bfree); - info->SectorsPerAllocationUnit = cpu_to_le32(1); - info->BytesPerSector = cpu_to_le32(stfs.f_bsize); - rsp->OutputBufferLength = cpu_to_le32(24); - inc_rfc1001_len(work->response_buf, 24); - fs_infoclass_size = FS_SIZE_INFORMATION_SIZE; - break; - } - case FS_FULL_SIZE_INFORMATION: - { - struct smb2_fs_full_size_info *info; - - info = (struct smb2_fs_full_size_info *)(rsp->Buffer); - info->TotalAllocationUnits = cpu_to_le64(stfs.f_blocks); - info->CallerAvailableAllocationUnits = - cpu_to_le64(stfs.f_bavail); - info->ActualAvailableAllocationUnits = - cpu_to_le64(stfs.f_bfree); - info->SectorsPerAllocationUnit = cpu_to_le32(1); - info->BytesPerSector = cpu_to_le32(stfs.f_bsize); - rsp->OutputBufferLength = cpu_to_le32(32); - inc_rfc1001_len(work->response_buf, 32); - fs_infoclass_size = FS_FULL_SIZE_INFORMATION_SIZE; - break; - } - case FS_OBJECT_ID_INFORMATION: - { - struct object_id_info *info; - - info = (struct object_id_info *)(rsp->Buffer); - - if (!user_guest(sess->user)) - memcpy(info->objid, user_passkey(sess->user), 16); - else - memset(info->objid, 0, 16); - - info->extended_info.magic = cpu_to_le32(EXTENDED_INFO_MAGIC); - info->extended_info.version = cpu_to_le32(1); - info->extended_info.release = cpu_to_le32(1); - info->extended_info.rel_date = 0; - memcpy(info->extended_info.version_string, "1.1.0", strlen("1.1.0")); - rsp->OutputBufferLength = cpu_to_le32(64); - inc_rfc1001_len(work->response_buf, 64); - fs_infoclass_size = FS_OBJECT_ID_INFORMATION_SIZE; - break; - } - case FS_SECTOR_SIZE_INFORMATION: - { - struct smb3_fs_ss_info *info; - unsigned int sector_size = - min_t(unsigned int, path.mnt->mnt_sb->s_blocksize, 4096); - - info = (struct smb3_fs_ss_info *)(rsp->Buffer); - - info->LogicalBytesPerSector = cpu_to_le32(sector_size); - info->PhysicalBytesPerSectorForAtomicity = - cpu_to_le32(sector_size); - info->PhysicalBytesPerSectorForPerf = cpu_to_le32(sector_size); - info->FSEffPhysicalBytesPerSectorForAtomicity = - cpu_to_le32(sector_size); - info->Flags = cpu_to_le32(SSINFO_FLAGS_ALIGNED_DEVICE | - SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE); - info->ByteOffsetForSectorAlignment = 0; - info->ByteOffsetForPartitionAlignment = 0; - rsp->OutputBufferLength = cpu_to_le32(28); - inc_rfc1001_len(work->response_buf, 28); - fs_infoclass_size = FS_SECTOR_SIZE_INFORMATION_SIZE; - break; - } - case FS_CONTROL_INFORMATION: - { - /* - * TODO : The current implementation is based on - * test result with win7(NTFS) server. It's need to - * modify this to get valid Quota values - * from Linux kernel - */ - struct smb2_fs_control_info *info; - - info = (struct smb2_fs_control_info *)(rsp->Buffer); - info->FreeSpaceStartFiltering = 0; - info->FreeSpaceThreshold = 0; - info->FreeSpaceStopFiltering = 0; - info->DefaultQuotaThreshold = cpu_to_le64(SMB2_NO_FID); - info->DefaultQuotaLimit = cpu_to_le64(SMB2_NO_FID); - info->Padding = 0; - rsp->OutputBufferLength = cpu_to_le32(48); - inc_rfc1001_len(work->response_buf, 48); - fs_infoclass_size = FS_CONTROL_INFORMATION_SIZE; - break; - } - case FS_POSIX_INFORMATION: - { - struct filesystem_posix_info *info; - - if (!work->tcon->posix_extensions) { - pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); - rc = -EOPNOTSUPP; - } else { - info = (struct filesystem_posix_info *)(rsp->Buffer); - info->OptimalTransferSize = cpu_to_le32(stfs.f_bsize); - info->BlockSize = cpu_to_le32(stfs.f_bsize); - info->TotalBlocks = cpu_to_le64(stfs.f_blocks); - info->BlocksAvail = cpu_to_le64(stfs.f_bfree); - info->UserBlocksAvail = cpu_to_le64(stfs.f_bavail); - info->TotalFileNodes = cpu_to_le64(stfs.f_files); - info->FreeFileNodes = cpu_to_le64(stfs.f_ffree); - rsp->OutputBufferLength = cpu_to_le32(56); - inc_rfc1001_len(work->response_buf, 56); - fs_infoclass_size = FS_POSIX_INFORMATION_SIZE; - } - break; - } - default: - path_put(&path); - return -EOPNOTSUPP; - } - rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), - rsp, work->response_buf, - fs_infoclass_size); - path_put(&path); - return rc; -} - -static int smb2_get_info_sec(struct ksmbd_work *work, - struct smb2_query_info_req *req, - struct smb2_query_info_rsp *rsp) -{ - struct ksmbd_file *fp; - struct user_namespace *user_ns; - struct smb_ntsd *pntsd = (struct smb_ntsd *)rsp->Buffer, *ppntsd = NULL; - struct smb_fattr fattr = {{0}}; - struct inode *inode; - __u32 secdesclen = 0; - unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; - int addition_info = le32_to_cpu(req->AdditionalInformation); - int rc = 0, ppntsd_size = 0; - - if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO | - PROTECTED_DACL_SECINFO | - UNPROTECTED_DACL_SECINFO)) { - ksmbd_debug(SMB, "Unsupported addition info: 0x%x)\n", - addition_info); - - pntsd->revision = cpu_to_le16(1); - pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PROTECTED); - pntsd->osidoffset = 0; - pntsd->gsidoffset = 0; - pntsd->sacloffset = 0; - pntsd->dacloffset = 0; - - secdesclen = sizeof(struct smb_ntsd); - rsp->OutputBufferLength = cpu_to_le32(secdesclen); - inc_rfc1001_len(work->response_buf, secdesclen); - - return 0; - } - - if (work->next_smb2_rcv_hdr_off) { - if (!has_file_id(req->VolatileFileId)) { - ksmbd_debug(SMB, "Compound request set FID = %llu\n", - work->compound_fid); - id = work->compound_fid; - pid = work->compound_pfid; - } - } - - if (!has_file_id(id)) { - id = req->VolatileFileId; - pid = req->PersistentFileId; - } - - fp = ksmbd_lookup_fd_slow(work, id, pid); - if (!fp) - return -ENOENT; - - user_ns = file_mnt_user_ns(fp->filp); - inode = file_inode(fp->filp); - ksmbd_acls_fattr(&fattr, user_ns, inode); - - if (test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_ACL_XATTR)) - ppntsd_size = ksmbd_vfs_get_sd_xattr(work->conn, user_ns, - fp->filp->f_path.dentry, - &ppntsd); - - /* Check if sd buffer size exceeds response buffer size */ - if (smb2_resp_buf_len(work, 8) > ppntsd_size) - rc = build_sec_desc(user_ns, pntsd, ppntsd, ppntsd_size, - addition_info, &secdesclen, &fattr); - posix_acl_release(fattr.cf_acls); - posix_acl_release(fattr.cf_dacls); - kfree(ppntsd); - ksmbd_fd_put(work, fp); - if (rc) - return rc; - - rsp->OutputBufferLength = cpu_to_le32(secdesclen); - inc_rfc1001_len(work->response_buf, secdesclen); - return 0; -} - -/** - * smb2_query_info() - handler for smb2 query info command - * @work: smb work containing query info request buffer - * - * Return: 0 on success, otherwise error - */ -int smb2_query_info(struct ksmbd_work *work) -{ - struct smb2_query_info_req *req; - struct smb2_query_info_rsp *rsp; - int rc = 0; - - WORK_BUFFERS(work, req, rsp); - - ksmbd_debug(SMB, "GOT query info request\n"); - - switch (req->InfoType) { - case SMB2_O_INFO_FILE: - ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILE\n"); - rc = smb2_get_info_file(work, req, rsp); - break; - case SMB2_O_INFO_FILESYSTEM: - ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILESYSTEM\n"); - rc = smb2_get_info_filesystem(work, req, rsp); - break; - case SMB2_O_INFO_SECURITY: - ksmbd_debug(SMB, "GOT SMB2_O_INFO_SECURITY\n"); - rc = smb2_get_info_sec(work, req, rsp); - break; - default: - ksmbd_debug(SMB, "InfoType %d not supported yet\n", - req->InfoType); - rc = -EOPNOTSUPP; - } - - if (rc < 0) { - if (rc == -EACCES) - rsp->hdr.Status = STATUS_ACCESS_DENIED; - else if (rc == -ENOENT) - rsp->hdr.Status = STATUS_FILE_CLOSED; - else if (rc == -EIO) - rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR; - else if (rc == -EOPNOTSUPP || rsp->hdr.Status == 0) - rsp->hdr.Status = STATUS_INVALID_INFO_CLASS; - smb2_set_err_rsp(work); - - ksmbd_debug(SMB, "error while processing smb2 query rc = %d\n", - rc); - return rc; - } - rsp->StructureSize = cpu_to_le16(9); - rsp->OutputBufferOffset = cpu_to_le16(72); - inc_rfc1001_len(work->response_buf, 8); - return 0; -} - -/** - * smb2_close_pipe() - handler for closing IPC pipe - * @work: smb work containing close request buffer - * - * Return: 0 - */ -static noinline int smb2_close_pipe(struct ksmbd_work *work) -{ - u64 id; - struct smb2_close_req *req = smb2_get_msg(work->request_buf); - struct smb2_close_rsp *rsp = smb2_get_msg(work->response_buf); - - id = req->VolatileFileId; - ksmbd_session_rpc_close(work->sess, id); - - rsp->StructureSize = cpu_to_le16(60); - rsp->Flags = 0; - rsp->Reserved = 0; - rsp->CreationTime = 0; - rsp->LastAccessTime = 0; - rsp->LastWriteTime = 0; - rsp->ChangeTime = 0; - rsp->AllocationSize = 0; - rsp->EndOfFile = 0; - rsp->Attributes = 0; - inc_rfc1001_len(work->response_buf, 60); - return 0; -} - -/** - * smb2_close() - handler for smb2 close file command - * @work: smb work containing close request buffer - * - * Return: 0 - */ -int smb2_close(struct ksmbd_work *work) -{ - u64 volatile_id = KSMBD_NO_FID; - u64 sess_id; - struct smb2_close_req *req; - struct smb2_close_rsp *rsp; - struct ksmbd_conn *conn = work->conn; - struct ksmbd_file *fp; - struct inode *inode; - u64 time; - int err = 0; - - WORK_BUFFERS(work, req, rsp); - - if (test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_PIPE)) { - ksmbd_debug(SMB, "IPC pipe close request\n"); - return smb2_close_pipe(work); - } - - sess_id = le64_to_cpu(req->hdr.SessionId); - if (req->hdr.Flags & SMB2_FLAGS_RELATED_OPERATIONS) - sess_id = work->compound_sid; - - work->compound_sid = 0; - if (check_session_id(conn, sess_id)) { - work->compound_sid = sess_id; - } else { - rsp->hdr.Status = STATUS_USER_SESSION_DELETED; - if (req->hdr.Flags & SMB2_FLAGS_RELATED_OPERATIONS) - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - err = -EBADF; - goto out; - } - - if (work->next_smb2_rcv_hdr_off && - !has_file_id(req->VolatileFileId)) { - if (!has_file_id(work->compound_fid)) { - /* file already closed, return FILE_CLOSED */ - ksmbd_debug(SMB, "file already closed\n"); - rsp->hdr.Status = STATUS_FILE_CLOSED; - err = -EBADF; - goto out; - } else { - ksmbd_debug(SMB, - "Compound request set FID = %llu:%llu\n", - work->compound_fid, - work->compound_pfid); - volatile_id = work->compound_fid; - - /* file closed, stored id is not valid anymore */ - work->compound_fid = KSMBD_NO_FID; - work->compound_pfid = KSMBD_NO_FID; - } - } else { - volatile_id = req->VolatileFileId; - } - ksmbd_debug(SMB, "volatile_id = %llu\n", volatile_id); - - rsp->StructureSize = cpu_to_le16(60); - rsp->Reserved = 0; - - if (req->Flags == SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB) { - fp = ksmbd_lookup_fd_fast(work, volatile_id); - if (!fp) { - err = -ENOENT; - goto out; - } - - inode = file_inode(fp->filp); - rsp->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; - rsp->AllocationSize = S_ISDIR(inode->i_mode) ? 0 : - cpu_to_le64(inode->i_blocks << 9); - rsp->EndOfFile = cpu_to_le64(inode->i_size); - rsp->Attributes = fp->f_ci->m_fattr; - rsp->CreationTime = cpu_to_le64(fp->create_time); - time = ksmbd_UnixTimeToNT(inode->i_atime); - rsp->LastAccessTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(inode->i_mtime); - rsp->LastWriteTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(inode->i_ctime); - rsp->ChangeTime = cpu_to_le64(time); - ksmbd_fd_put(work, fp); - } else { - rsp->Flags = 0; - rsp->AllocationSize = 0; - rsp->EndOfFile = 0; - rsp->Attributes = 0; - rsp->CreationTime = 0; - rsp->LastAccessTime = 0; - rsp->LastWriteTime = 0; - rsp->ChangeTime = 0; - } - - err = ksmbd_close_fd(work, volatile_id); -out: - if (err) { - if (rsp->hdr.Status == 0) - rsp->hdr.Status = STATUS_FILE_CLOSED; - smb2_set_err_rsp(work); - } else { - inc_rfc1001_len(work->response_buf, 60); - } - - return 0; -} - -/** - * smb2_echo() - handler for smb2 echo(ping) command - * @work: smb work containing echo request buffer - * - * Return: 0 - */ -int smb2_echo(struct ksmbd_work *work) -{ - struct smb2_echo_rsp *rsp = smb2_get_msg(work->response_buf); - - rsp->StructureSize = cpu_to_le16(4); - rsp->Reserved = 0; - inc_rfc1001_len(work->response_buf, 4); - return 0; -} - -static int smb2_rename(struct ksmbd_work *work, - struct ksmbd_file *fp, - struct user_namespace *user_ns, - struct smb2_file_rename_info *file_info, - struct nls_table *local_nls) -{ - struct ksmbd_share_config *share = fp->tcon->share_conf; - char *new_name = NULL, *abs_oldname = NULL, *old_name = NULL; - char *pathname = NULL; - struct path path; - bool file_present = true; - int rc; - - ksmbd_debug(SMB, "setting FILE_RENAME_INFO\n"); - pathname = kmalloc(PATH_MAX, GFP_KERNEL); - if (!pathname) - return -ENOMEM; - - abs_oldname = file_path(fp->filp, pathname, PATH_MAX); - if (IS_ERR(abs_oldname)) { - rc = -EINVAL; - goto out; - } - old_name = strrchr(abs_oldname, '/'); - if (old_name && old_name[1] != '\0') { - old_name++; - } else { - ksmbd_debug(SMB, "can't get last component in path %s\n", - abs_oldname); - rc = -ENOENT; - goto out; - } - - new_name = smb2_get_name(file_info->FileName, - le32_to_cpu(file_info->FileNameLength), - local_nls); - if (IS_ERR(new_name)) { - rc = PTR_ERR(new_name); - goto out; - } - - if (strchr(new_name, ':')) { - int s_type; - char *xattr_stream_name, *stream_name = NULL; - size_t xattr_stream_size; - int len; - - rc = parse_stream_name(new_name, &stream_name, &s_type); - if (rc < 0) - goto out; - - len = strlen(new_name); - if (len > 0 && new_name[len - 1] != '/') { - pr_err("not allow base filename in rename\n"); - rc = -ESHARE; - goto out; - } - - rc = ksmbd_vfs_xattr_stream_name(stream_name, - &xattr_stream_name, - &xattr_stream_size, - s_type); - if (rc) - goto out; - - rc = ksmbd_vfs_setxattr(user_ns, - fp->filp->f_path.dentry, - xattr_stream_name, - NULL, 0, 0); - if (rc < 0) { - pr_err("failed to store stream name in xattr: %d\n", - rc); - rc = -EINVAL; - goto out; - } - - goto out; - } - - ksmbd_debug(SMB, "new name %s\n", new_name); - rc = ksmbd_vfs_kern_path(work, new_name, LOOKUP_NO_SYMLINKS, &path, 1); - if (rc) { - if (rc != -ENOENT) - goto out; - file_present = false; - } else { - path_put(&path); - } - - if (ksmbd_share_veto_filename(share, new_name)) { - rc = -ENOENT; - ksmbd_debug(SMB, "Can't rename vetoed file: %s\n", new_name); - goto out; - } - - if (file_info->ReplaceIfExists) { - if (file_present) { - rc = ksmbd_vfs_remove_file(work, new_name); - if (rc) { - if (rc != -ENOTEMPTY) - rc = -EINVAL; - ksmbd_debug(SMB, "cannot delete %s, rc %d\n", - new_name, rc); - goto out; - } - } - } else { - if (file_present && - strncmp(old_name, path.dentry->d_name.name, strlen(old_name))) { - rc = -EEXIST; - ksmbd_debug(SMB, - "cannot rename already existing file\n"); - goto out; - } - } - - rc = ksmbd_vfs_fp_rename(work, fp, new_name); -out: - kfree(pathname); - if (!IS_ERR(new_name)) - kfree(new_name); - return rc; -} - -static int smb2_create_link(struct ksmbd_work *work, - struct ksmbd_share_config *share, - struct smb2_file_link_info *file_info, - unsigned int buf_len, struct file *filp, - struct nls_table *local_nls) -{ - char *link_name = NULL, *target_name = NULL, *pathname = NULL; - struct path path; - bool file_present = true; - int rc; - - if (buf_len < (u64)sizeof(struct smb2_file_link_info) + - le32_to_cpu(file_info->FileNameLength)) - return -EINVAL; - - ksmbd_debug(SMB, "setting FILE_LINK_INFORMATION\n"); - pathname = kmalloc(PATH_MAX, GFP_KERNEL); - if (!pathname) - return -ENOMEM; - - link_name = smb2_get_name(file_info->FileName, - le32_to_cpu(file_info->FileNameLength), - local_nls); - if (IS_ERR(link_name) || S_ISDIR(file_inode(filp)->i_mode)) { - rc = -EINVAL; - goto out; - } - - ksmbd_debug(SMB, "link name is %s\n", link_name); - target_name = file_path(filp, pathname, PATH_MAX); - if (IS_ERR(target_name)) { - rc = -EINVAL; - goto out; - } - - ksmbd_debug(SMB, "target name is %s\n", target_name); - rc = ksmbd_vfs_kern_path(work, link_name, LOOKUP_NO_SYMLINKS, &path, 0); - if (rc) { - if (rc != -ENOENT) - goto out; - file_present = false; - } else { - path_put(&path); - } - - if (file_info->ReplaceIfExists) { - if (file_present) { - rc = ksmbd_vfs_remove_file(work, link_name); - if (rc) { - rc = -EINVAL; - ksmbd_debug(SMB, "cannot delete %s\n", - link_name); - goto out; - } - } - } else { - if (file_present) { - rc = -EEXIST; - ksmbd_debug(SMB, "link already exists\n"); - goto out; - } - } - - rc = ksmbd_vfs_link(work, target_name, link_name); - if (rc) - rc = -EINVAL; -out: - if (!IS_ERR(link_name)) - kfree(link_name); - kfree(pathname); - return rc; -} - -static int set_file_basic_info(struct ksmbd_file *fp, - struct smb2_file_basic_info *file_info, - struct ksmbd_share_config *share) -{ - struct iattr attrs; - struct file *filp; - struct inode *inode; - struct user_namespace *user_ns; - int rc = 0; - - if (!(fp->daccess & FILE_WRITE_ATTRIBUTES_LE)) - return -EACCES; - - attrs.ia_valid = 0; - filp = fp->filp; - inode = file_inode(filp); - user_ns = file_mnt_user_ns(filp); - - if (file_info->CreationTime) - fp->create_time = le64_to_cpu(file_info->CreationTime); - - if (file_info->LastAccessTime) { - attrs.ia_atime = ksmbd_NTtimeToUnix(file_info->LastAccessTime); - attrs.ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET); - } - - attrs.ia_valid |= ATTR_CTIME; - if (file_info->ChangeTime) - attrs.ia_ctime = ksmbd_NTtimeToUnix(file_info->ChangeTime); - else - attrs.ia_ctime = inode->i_ctime; - - if (file_info->LastWriteTime) { - attrs.ia_mtime = ksmbd_NTtimeToUnix(file_info->LastWriteTime); - attrs.ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET); - } - - if (file_info->Attributes) { - if (!S_ISDIR(inode->i_mode) && - file_info->Attributes & FILE_ATTRIBUTE_DIRECTORY_LE) { - pr_err("can't change a file to a directory\n"); - return -EINVAL; - } - - if (!(S_ISDIR(inode->i_mode) && file_info->Attributes == FILE_ATTRIBUTE_NORMAL_LE)) - fp->f_ci->m_fattr = file_info->Attributes | - (fp->f_ci->m_fattr & FILE_ATTRIBUTE_DIRECTORY_LE); - } - - if (test_share_config_flag(share, KSMBD_SHARE_FLAG_STORE_DOS_ATTRS) && - (file_info->CreationTime || file_info->Attributes)) { - struct xattr_dos_attrib da = {0}; - - da.version = 4; - da.itime = fp->itime; - da.create_time = fp->create_time; - da.attr = le32_to_cpu(fp->f_ci->m_fattr); - da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME | - XATTR_DOSINFO_ITIME; - - rc = ksmbd_vfs_set_dos_attrib_xattr(user_ns, - filp->f_path.dentry, &da); - if (rc) - ksmbd_debug(SMB, - "failed to restore file attribute in EA\n"); - rc = 0; - } - - if (attrs.ia_valid) { - struct dentry *dentry = filp->f_path.dentry; - struct inode *inode = d_inode(dentry); - - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EACCES; - - inode_lock(inode); - inode->i_ctime = attrs.ia_ctime; - attrs.ia_valid &= ~ATTR_CTIME; - rc = notify_change(user_ns, dentry, &attrs, NULL); - inode_unlock(inode); - } - return rc; -} - -static int set_file_allocation_info(struct ksmbd_work *work, - struct ksmbd_file *fp, - struct smb2_file_alloc_info *file_alloc_info) -{ - /* - * TODO : It's working fine only when store dos attributes - * is not yes. need to implement a logic which works - * properly with any smb.conf option - */ - - loff_t alloc_blks; - struct inode *inode; - int rc; - - if (!(fp->daccess & FILE_WRITE_DATA_LE)) - return -EACCES; - - alloc_blks = (le64_to_cpu(file_alloc_info->AllocationSize) + 511) >> 9; - inode = file_inode(fp->filp); - - if (alloc_blks > inode->i_blocks) { - smb_break_all_levII_oplock(work, fp, 1); - rc = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0, - alloc_blks * 512); - if (rc && rc != -EOPNOTSUPP) { - pr_err("vfs_fallocate is failed : %d\n", rc); - return rc; - } - } else if (alloc_blks < inode->i_blocks) { - loff_t size; - - /* - * Allocation size could be smaller than original one - * which means allocated blocks in file should be - * deallocated. use truncate to cut out it, but inode - * size is also updated with truncate offset. - * inode size is retained by backup inode size. - */ - size = i_size_read(inode); - rc = ksmbd_vfs_truncate(work, fp, alloc_blks * 512); - if (rc) { - pr_err("truncate failed!, err %d\n", rc); - return rc; - } - if (size < alloc_blks * 512) - i_size_write(inode, size); - } - return 0; -} - -static int set_end_of_file_info(struct ksmbd_work *work, struct ksmbd_file *fp, - struct smb2_file_eof_info *file_eof_info) -{ - loff_t newsize; - struct inode *inode; - int rc; - - if (!(fp->daccess & FILE_WRITE_DATA_LE)) - return -EACCES; - - newsize = le64_to_cpu(file_eof_info->EndOfFile); - inode = file_inode(fp->filp); - - /* - * If FILE_END_OF_FILE_INFORMATION of set_info_file is called - * on FAT32 shared device, truncate execution time is too long - * and network error could cause from windows client. because - * truncate of some filesystem like FAT32 fill zero data in - * truncated range. - */ - if (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC) { - ksmbd_debug(SMB, "truncated to newsize %lld\n", newsize); - rc = ksmbd_vfs_truncate(work, fp, newsize); - if (rc) { - ksmbd_debug(SMB, "truncate failed!, err %d\n", rc); - if (rc != -EAGAIN) - rc = -EBADF; - return rc; - } - } - return 0; -} - -static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp, - struct smb2_file_rename_info *rename_info, - unsigned int buf_len) -{ - struct user_namespace *user_ns; - struct ksmbd_file *parent_fp; - struct dentry *parent; - struct dentry *dentry = fp->filp->f_path.dentry; - int ret; - - if (!(fp->daccess & FILE_DELETE_LE)) { - pr_err("no right to delete : 0x%x\n", fp->daccess); - return -EACCES; - } - - if (buf_len < (u64)sizeof(struct smb2_file_rename_info) + - le32_to_cpu(rename_info->FileNameLength)) - return -EINVAL; - - user_ns = file_mnt_user_ns(fp->filp); - if (ksmbd_stream_fd(fp)) - goto next; - - parent = dget_parent(dentry); - ret = ksmbd_vfs_lock_parent(user_ns, parent, dentry); - if (ret) { - dput(parent); - return ret; - } - - parent_fp = ksmbd_lookup_fd_inode(d_inode(parent)); - inode_unlock(d_inode(parent)); - dput(parent); - - if (parent_fp) { - if (parent_fp->daccess & FILE_DELETE_LE) { - pr_err("parent dir is opened with delete access\n"); - ksmbd_fd_put(work, parent_fp); - return -ESHARE; - } - ksmbd_fd_put(work, parent_fp); - } -next: - return smb2_rename(work, fp, user_ns, rename_info, - work->conn->local_nls); -} - -static int set_file_disposition_info(struct ksmbd_file *fp, - struct smb2_file_disposition_info *file_info) -{ - struct inode *inode; - - if (!(fp->daccess & FILE_DELETE_LE)) { - pr_err("no right to delete : 0x%x\n", fp->daccess); - return -EACCES; - } - - inode = file_inode(fp->filp); - if (file_info->DeletePending) { - if (S_ISDIR(inode->i_mode) && - ksmbd_vfs_empty_dir(fp) == -ENOTEMPTY) - return -EBUSY; - ksmbd_set_inode_pending_delete(fp); - } else { - ksmbd_clear_inode_pending_delete(fp); - } - return 0; -} - -static int set_file_position_info(struct ksmbd_file *fp, - struct smb2_file_pos_info *file_info) -{ - loff_t current_byte_offset; - unsigned long sector_size; - struct inode *inode; - - inode = file_inode(fp->filp); - current_byte_offset = le64_to_cpu(file_info->CurrentByteOffset); - sector_size = inode->i_sb->s_blocksize; - - if (current_byte_offset < 0 || - (fp->coption == FILE_NO_INTERMEDIATE_BUFFERING_LE && - current_byte_offset & (sector_size - 1))) { - pr_err("CurrentByteOffset is not valid : %llu\n", - current_byte_offset); - return -EINVAL; - } - - fp->filp->f_pos = current_byte_offset; - return 0; -} - -static int set_file_mode_info(struct ksmbd_file *fp, - struct smb2_file_mode_info *file_info) -{ - __le32 mode; - - mode = file_info->Mode; - - if ((mode & ~FILE_MODE_INFO_MASK)) { - pr_err("Mode is not valid : 0x%x\n", le32_to_cpu(mode)); - return -EINVAL; - } - - /* - * TODO : need to implement consideration for - * FILE_SYNCHRONOUS_IO_ALERT and FILE_SYNCHRONOUS_IO_NONALERT - */ - ksmbd_vfs_set_fadvise(fp->filp, mode); - fp->coption = mode; - return 0; -} - -/** - * smb2_set_info_file() - handler for smb2 set info command - * @work: smb work containing set info command buffer - * @fp: ksmbd_file pointer - * @req: request buffer pointer - * @share: ksmbd_share_config pointer - * - * Return: 0 on success, otherwise error - * TODO: need to implement an error handling for STATUS_INFO_LENGTH_MISMATCH - */ -static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, - struct smb2_set_info_req *req, - struct ksmbd_share_config *share) -{ - unsigned int buf_len = le32_to_cpu(req->BufferLength); - - switch (req->FileInfoClass) { - case FILE_BASIC_INFORMATION: - { - if (buf_len < sizeof(struct smb2_file_basic_info)) - return -EINVAL; - - return set_file_basic_info(fp, (struct smb2_file_basic_info *)req->Buffer, share); - } - case FILE_ALLOCATION_INFORMATION: - { - if (buf_len < sizeof(struct smb2_file_alloc_info)) - return -EINVAL; - - return set_file_allocation_info(work, fp, - (struct smb2_file_alloc_info *)req->Buffer); - } - case FILE_END_OF_FILE_INFORMATION: - { - if (buf_len < sizeof(struct smb2_file_eof_info)) - return -EINVAL; - - return set_end_of_file_info(work, fp, - (struct smb2_file_eof_info *)req->Buffer); - } - case FILE_RENAME_INFORMATION: - { - if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { - ksmbd_debug(SMB, - "User does not have write permission\n"); - return -EACCES; - } - - if (buf_len < sizeof(struct smb2_file_rename_info)) - return -EINVAL; - - return set_rename_info(work, fp, - (struct smb2_file_rename_info *)req->Buffer, - buf_len); - } - case FILE_LINK_INFORMATION: - { - if (buf_len < sizeof(struct smb2_file_link_info)) - return -EINVAL; - - return smb2_create_link(work, work->tcon->share_conf, - (struct smb2_file_link_info *)req->Buffer, - buf_len, fp->filp, - work->conn->local_nls); - } - case FILE_DISPOSITION_INFORMATION: - { - if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { - ksmbd_debug(SMB, - "User does not have write permission\n"); - return -EACCES; - } - - if (buf_len < sizeof(struct smb2_file_disposition_info)) - return -EINVAL; - - return set_file_disposition_info(fp, - (struct smb2_file_disposition_info *)req->Buffer); - } - case FILE_FULL_EA_INFORMATION: - { - if (!(fp->daccess & FILE_WRITE_EA_LE)) { - pr_err("Not permitted to write ext attr: 0x%x\n", - fp->daccess); - return -EACCES; - } - - if (buf_len < sizeof(struct smb2_ea_info)) - return -EINVAL; - - return smb2_set_ea((struct smb2_ea_info *)req->Buffer, - buf_len, &fp->filp->f_path); - } - case FILE_POSITION_INFORMATION: - { - if (buf_len < sizeof(struct smb2_file_pos_info)) - return -EINVAL; - - return set_file_position_info(fp, (struct smb2_file_pos_info *)req->Buffer); - } - case FILE_MODE_INFORMATION: - { - if (buf_len < sizeof(struct smb2_file_mode_info)) - return -EINVAL; - - return set_file_mode_info(fp, (struct smb2_file_mode_info *)req->Buffer); - } - } - - pr_err("Unimplemented Fileinfoclass :%d\n", req->FileInfoClass); - return -EOPNOTSUPP; -} - -static int smb2_set_info_sec(struct ksmbd_file *fp, int addition_info, - char *buffer, int buf_len) -{ - struct smb_ntsd *pntsd = (struct smb_ntsd *)buffer; - - fp->saccess |= FILE_SHARE_DELETE_LE; - - return set_info_sec(fp->conn, fp->tcon, &fp->filp->f_path, pntsd, - buf_len, false); -} - -/** - * smb2_set_info() - handler for smb2 set info command handler - * @work: smb work containing set info request buffer - * - * Return: 0 on success, otherwise error - */ -int smb2_set_info(struct ksmbd_work *work) -{ - struct smb2_set_info_req *req; - struct smb2_set_info_rsp *rsp; - struct ksmbd_file *fp; - int rc = 0; - unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; - - ksmbd_debug(SMB, "Received set info request\n"); - - if (work->next_smb2_rcv_hdr_off) { - req = ksmbd_req_buf_next(work); - rsp = ksmbd_resp_buf_next(work); - if (!has_file_id(req->VolatileFileId)) { - ksmbd_debug(SMB, "Compound request set FID = %llu\n", - work->compound_fid); - id = work->compound_fid; - pid = work->compound_pfid; - } - } else { - req = smb2_get_msg(work->request_buf); - rsp = smb2_get_msg(work->response_buf); - } - - if (!has_file_id(id)) { - id = req->VolatileFileId; - pid = req->PersistentFileId; - } - - fp = ksmbd_lookup_fd_slow(work, id, pid); - if (!fp) { - ksmbd_debug(SMB, "Invalid id for close: %u\n", id); - rc = -ENOENT; - goto err_out; - } - - switch (req->InfoType) { - case SMB2_O_INFO_FILE: - ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILE\n"); - rc = smb2_set_info_file(work, fp, req, work->tcon->share_conf); - break; - case SMB2_O_INFO_SECURITY: - ksmbd_debug(SMB, "GOT SMB2_O_INFO_SECURITY\n"); - if (ksmbd_override_fsids(work)) { - rc = -ENOMEM; - goto err_out; - } - rc = smb2_set_info_sec(fp, - le32_to_cpu(req->AdditionalInformation), - req->Buffer, - le32_to_cpu(req->BufferLength)); - ksmbd_revert_fsids(work); - break; - default: - rc = -EOPNOTSUPP; - } - - if (rc < 0) - goto err_out; - - rsp->StructureSize = cpu_to_le16(2); - inc_rfc1001_len(work->response_buf, 2); - ksmbd_fd_put(work, fp); - return 0; - -err_out: - if (rc == -EACCES || rc == -EPERM || rc == -EXDEV) - rsp->hdr.Status = STATUS_ACCESS_DENIED; - else if (rc == -EINVAL) - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - else if (rc == -ESHARE) - rsp->hdr.Status = STATUS_SHARING_VIOLATION; - else if (rc == -ENOENT) - rsp->hdr.Status = STATUS_OBJECT_NAME_INVALID; - else if (rc == -EBUSY || rc == -ENOTEMPTY) - rsp->hdr.Status = STATUS_DIRECTORY_NOT_EMPTY; - else if (rc == -EAGAIN) - rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT; - else if (rc == -EBADF || rc == -ESTALE) - rsp->hdr.Status = STATUS_INVALID_HANDLE; - else if (rc == -EEXIST) - rsp->hdr.Status = STATUS_OBJECT_NAME_COLLISION; - else if (rsp->hdr.Status == 0 || rc == -EOPNOTSUPP) - rsp->hdr.Status = STATUS_INVALID_INFO_CLASS; - smb2_set_err_rsp(work); - ksmbd_fd_put(work, fp); - ksmbd_debug(SMB, "error while processing smb2 query rc = %d\n", rc); - return rc; -} - -/** - * smb2_read_pipe() - handler for smb2 read from IPC pipe - * @work: smb work containing read IPC pipe command buffer - * - * Return: 0 on success, otherwise error - */ -static noinline int smb2_read_pipe(struct ksmbd_work *work) -{ - int nbytes = 0, err; - u64 id; - struct ksmbd_rpc_command *rpc_resp; - struct smb2_read_req *req = smb2_get_msg(work->request_buf); - struct smb2_read_rsp *rsp = smb2_get_msg(work->response_buf); - - id = req->VolatileFileId; - - inc_rfc1001_len(work->response_buf, 16); - rpc_resp = ksmbd_rpc_read(work->sess, id); - if (rpc_resp) { - if (rpc_resp->flags != KSMBD_RPC_OK) { - err = -EINVAL; - goto out; - } - - work->aux_payload_buf = - kvmalloc(rpc_resp->payload_sz, GFP_KERNEL | __GFP_ZERO); - if (!work->aux_payload_buf) { - err = -ENOMEM; - goto out; - } - - memcpy(work->aux_payload_buf, rpc_resp->payload, - rpc_resp->payload_sz); - - nbytes = rpc_resp->payload_sz; - work->resp_hdr_sz = get_rfc1002_len(work->response_buf) + 4; - work->aux_payload_sz = nbytes; - kvfree(rpc_resp); - } - - rsp->StructureSize = cpu_to_le16(17); - rsp->DataOffset = 80; - rsp->Reserved = 0; - rsp->DataLength = cpu_to_le32(nbytes); - rsp->DataRemaining = 0; - rsp->Flags = 0; - inc_rfc1001_len(work->response_buf, nbytes); - return 0; - -out: - rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR; - smb2_set_err_rsp(work); - kvfree(rpc_resp); - return err; -} - -static int smb2_set_remote_key_for_rdma(struct ksmbd_work *work, - struct smb2_buffer_desc_v1 *desc, - __le32 Channel, - __le16 ChannelInfoLength) -{ - unsigned int i, ch_count; - - if (work->conn->dialect == SMB30_PROT_ID && - Channel != SMB2_CHANNEL_RDMA_V1) - return -EINVAL; - - ch_count = le16_to_cpu(ChannelInfoLength) / sizeof(*desc); - if (ksmbd_debug_types & KSMBD_DEBUG_RDMA) { - for (i = 0; i < ch_count; i++) { - pr_info("RDMA r/w request %#x: token %#x, length %#x\n", - i, - le32_to_cpu(desc[i].token), - le32_to_cpu(desc[i].length)); - } - } - if (!ch_count) - return -EINVAL; - - work->need_invalidate_rkey = - (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE); - if (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) - work->remote_key = le32_to_cpu(desc->token); - return 0; -} - -static ssize_t smb2_read_rdma_channel(struct ksmbd_work *work, - struct smb2_read_req *req, void *data_buf, - size_t length) -{ - int err; - - err = ksmbd_conn_rdma_write(work->conn, data_buf, length, - (struct smb2_buffer_desc_v1 *) - ((char *)req + le16_to_cpu(req->ReadChannelInfoOffset)), - le16_to_cpu(req->ReadChannelInfoLength)); - if (err) - return err; - - return length; -} - -/** - * smb2_read() - handler for smb2 read from file - * @work: smb work containing read command buffer - * - * Return: 0 on success, otherwise error - */ -int smb2_read(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_read_req *req; - struct smb2_read_rsp *rsp; - struct ksmbd_file *fp = NULL; - loff_t offset; - size_t length, mincount; - ssize_t nbytes = 0, remain_bytes = 0; - int err = 0; - bool is_rdma_channel = false; - unsigned int max_read_size = conn->vals->max_read_size; - - WORK_BUFFERS(work, req, rsp); - - if (test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_PIPE)) { - ksmbd_debug(SMB, "IPC pipe read request\n"); - return smb2_read_pipe(work); - } - - if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE || - req->Channel == SMB2_CHANNEL_RDMA_V1) { - is_rdma_channel = true; - max_read_size = get_smbd_max_read_write_size(); - } - - if (is_rdma_channel == true) { - unsigned int ch_offset = le16_to_cpu(req->ReadChannelInfoOffset); - - if (ch_offset < offsetof(struct smb2_read_req, Buffer)) { - err = -EINVAL; - goto out; - } - err = smb2_set_remote_key_for_rdma(work, - (struct smb2_buffer_desc_v1 *) - ((char *)req + ch_offset), - req->Channel, - req->ReadChannelInfoLength); - if (err) - goto out; - } - - fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); - if (!fp) { - err = -ENOENT; - goto out; - } - - if (!(fp->daccess & (FILE_READ_DATA_LE | FILE_READ_ATTRIBUTES_LE))) { - pr_err("Not permitted to read : 0x%x\n", fp->daccess); - err = -EACCES; - goto out; - } - - offset = le64_to_cpu(req->Offset); - length = le32_to_cpu(req->Length); - mincount = le32_to_cpu(req->MinimumCount); - - if (length > max_read_size) { - ksmbd_debug(SMB, "limiting read size to max size(%u)\n", - max_read_size); - err = -EINVAL; - goto out; - } - - ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n", - fp->filp, offset, length); - - work->aux_payload_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO); - if (!work->aux_payload_buf) { - err = -ENOMEM; - goto out; - } - - nbytes = ksmbd_vfs_read(work, fp, length, &offset); - if (nbytes < 0) { - err = nbytes; - goto out; - } - - if ((nbytes == 0 && length != 0) || nbytes < mincount) { - kvfree(work->aux_payload_buf); - work->aux_payload_buf = NULL; - rsp->hdr.Status = STATUS_END_OF_FILE; - smb2_set_err_rsp(work); - ksmbd_fd_put(work, fp); - return 0; - } - - ksmbd_debug(SMB, "nbytes %zu, offset %lld mincount %zu\n", - nbytes, offset, mincount); - - if (is_rdma_channel == true) { - /* write data to the client using rdma channel */ - remain_bytes = smb2_read_rdma_channel(work, req, - work->aux_payload_buf, - nbytes); - kvfree(work->aux_payload_buf); - work->aux_payload_buf = NULL; - - nbytes = 0; - if (remain_bytes < 0) { - err = (int)remain_bytes; - goto out; - } - } - - rsp->StructureSize = cpu_to_le16(17); - rsp->DataOffset = 80; - rsp->Reserved = 0; - rsp->DataLength = cpu_to_le32(nbytes); - rsp->DataRemaining = cpu_to_le32(remain_bytes); - rsp->Flags = 0; - inc_rfc1001_len(work->response_buf, 16); - work->resp_hdr_sz = get_rfc1002_len(work->response_buf) + 4; - work->aux_payload_sz = nbytes; - inc_rfc1001_len(work->response_buf, nbytes); - ksmbd_fd_put(work, fp); - return 0; - -out: - if (err) { - if (err == -EISDIR) - rsp->hdr.Status = STATUS_INVALID_DEVICE_REQUEST; - else if (err == -EAGAIN) - rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT; - else if (err == -ENOENT) - rsp->hdr.Status = STATUS_FILE_CLOSED; - else if (err == -EACCES) - rsp->hdr.Status = STATUS_ACCESS_DENIED; - else if (err == -ESHARE) - rsp->hdr.Status = STATUS_SHARING_VIOLATION; - else if (err == -EINVAL) - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - else - rsp->hdr.Status = STATUS_INVALID_HANDLE; - - smb2_set_err_rsp(work); - } - ksmbd_fd_put(work, fp); - return err; -} - -/** - * smb2_write_pipe() - handler for smb2 write on IPC pipe - * @work: smb work containing write IPC pipe command buffer - * - * Return: 0 on success, otherwise error - */ -static noinline int smb2_write_pipe(struct ksmbd_work *work) -{ - struct smb2_write_req *req = smb2_get_msg(work->request_buf); - struct smb2_write_rsp *rsp = smb2_get_msg(work->response_buf); - struct ksmbd_rpc_command *rpc_resp; - u64 id = 0; - int err = 0, ret = 0; - char *data_buf; - size_t length; - - length = le32_to_cpu(req->Length); - id = req->VolatileFileId; - - if ((u64)le16_to_cpu(req->DataOffset) + length > - get_rfc1002_len(work->request_buf)) { - pr_err("invalid write data offset %u, smb_len %u\n", - le16_to_cpu(req->DataOffset), - get_rfc1002_len(work->request_buf)); - err = -EINVAL; - goto out; - } - - data_buf = (char *)(((char *)&req->hdr.ProtocolId) + - le16_to_cpu(req->DataOffset)); - - rpc_resp = ksmbd_rpc_write(work->sess, id, data_buf, length); - if (rpc_resp) { - if (rpc_resp->flags == KSMBD_RPC_ENOTIMPLEMENTED) { - rsp->hdr.Status = STATUS_NOT_SUPPORTED; - kvfree(rpc_resp); - smb2_set_err_rsp(work); - return -EOPNOTSUPP; - } - if (rpc_resp->flags != KSMBD_RPC_OK) { - rsp->hdr.Status = STATUS_INVALID_HANDLE; - smb2_set_err_rsp(work); - kvfree(rpc_resp); - return ret; - } - kvfree(rpc_resp); - } - - rsp->StructureSize = cpu_to_le16(17); - rsp->DataOffset = 0; - rsp->Reserved = 0; - rsp->DataLength = cpu_to_le32(length); - rsp->DataRemaining = 0; - rsp->Reserved2 = 0; - inc_rfc1001_len(work->response_buf, 16); - return 0; -out: - if (err) { - rsp->hdr.Status = STATUS_INVALID_HANDLE; - smb2_set_err_rsp(work); - } - - return err; -} - -static ssize_t smb2_write_rdma_channel(struct ksmbd_work *work, - struct smb2_write_req *req, - struct ksmbd_file *fp, - loff_t offset, size_t length, bool sync) -{ - char *data_buf; - int ret; - ssize_t nbytes; - - data_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO); - if (!data_buf) - return -ENOMEM; - - ret = ksmbd_conn_rdma_read(work->conn, data_buf, length, - (struct smb2_buffer_desc_v1 *) - ((char *)req + le16_to_cpu(req->WriteChannelInfoOffset)), - le16_to_cpu(req->WriteChannelInfoLength)); - if (ret < 0) { - kvfree(data_buf); - return ret; - } - - ret = ksmbd_vfs_write(work, fp, data_buf, length, &offset, sync, &nbytes); - kvfree(data_buf); - if (ret < 0) - return ret; - - return nbytes; -} - -/** - * smb2_write() - handler for smb2 write from file - * @work: smb work containing write command buffer - * - * Return: 0 on success, otherwise error - */ -int smb2_write(struct ksmbd_work *work) -{ - struct smb2_write_req *req; - struct smb2_write_rsp *rsp; - struct ksmbd_file *fp = NULL; - loff_t offset; - size_t length; - ssize_t nbytes; - char *data_buf; - bool writethrough = false, is_rdma_channel = false; - int err = 0; - unsigned int max_write_size = work->conn->vals->max_write_size; - - WORK_BUFFERS(work, req, rsp); - - if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_PIPE)) { - ksmbd_debug(SMB, "IPC pipe write request\n"); - return smb2_write_pipe(work); - } - - offset = le64_to_cpu(req->Offset); - length = le32_to_cpu(req->Length); - - if (req->Channel == SMB2_CHANNEL_RDMA_V1 || - req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) { - is_rdma_channel = true; - max_write_size = get_smbd_max_read_write_size(); - length = le32_to_cpu(req->RemainingBytes); - } - - if (is_rdma_channel == true) { - unsigned int ch_offset = le16_to_cpu(req->WriteChannelInfoOffset); - - if (req->Length != 0 || req->DataOffset != 0 || - ch_offset < offsetof(struct smb2_write_req, Buffer)) { - err = -EINVAL; - goto out; - } - err = smb2_set_remote_key_for_rdma(work, - (struct smb2_buffer_desc_v1 *) - ((char *)req + ch_offset), - req->Channel, - req->WriteChannelInfoLength); - if (err) - goto out; - } - - if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { - ksmbd_debug(SMB, "User does not have write permission\n"); - err = -EACCES; - goto out; - } - - fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); - if (!fp) { - err = -ENOENT; - goto out; - } - - if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_READ_ATTRIBUTES_LE))) { - pr_err("Not permitted to write : 0x%x\n", fp->daccess); - err = -EACCES; - goto out; - } - - if (length > max_write_size) { - ksmbd_debug(SMB, "limiting write size to max size(%u)\n", - max_write_size); - err = -EINVAL; - goto out; - } - - ksmbd_debug(SMB, "flags %u\n", le32_to_cpu(req->Flags)); - if (le32_to_cpu(req->Flags) & SMB2_WRITEFLAG_WRITE_THROUGH) - writethrough = true; - - if (is_rdma_channel == false) { - if (le16_to_cpu(req->DataOffset) < - offsetof(struct smb2_write_req, Buffer)) { - err = -EINVAL; - goto out; - } - - data_buf = (char *)(((char *)&req->hdr.ProtocolId) + - le16_to_cpu(req->DataOffset)); - - ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n", - fp->filp, offset, length); - err = ksmbd_vfs_write(work, fp, data_buf, length, &offset, - writethrough, &nbytes); - if (err < 0) - goto out; - } else { - /* read data from the client using rdma channel, and - * write the data. - */ - nbytes = smb2_write_rdma_channel(work, req, fp, offset, length, - writethrough); - if (nbytes < 0) { - err = (int)nbytes; - goto out; - } - } - - rsp->StructureSize = cpu_to_le16(17); - rsp->DataOffset = 0; - rsp->Reserved = 0; - rsp->DataLength = cpu_to_le32(nbytes); - rsp->DataRemaining = 0; - rsp->Reserved2 = 0; - inc_rfc1001_len(work->response_buf, 16); - ksmbd_fd_put(work, fp); - return 0; - -out: - if (err == -EAGAIN) - rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT; - else if (err == -ENOSPC || err == -EFBIG) - rsp->hdr.Status = STATUS_DISK_FULL; - else if (err == -ENOENT) - rsp->hdr.Status = STATUS_FILE_CLOSED; - else if (err == -EACCES) - rsp->hdr.Status = STATUS_ACCESS_DENIED; - else if (err == -ESHARE) - rsp->hdr.Status = STATUS_SHARING_VIOLATION; - else if (err == -EINVAL) - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - else - rsp->hdr.Status = STATUS_INVALID_HANDLE; - - smb2_set_err_rsp(work); - ksmbd_fd_put(work, fp); - return err; -} - -/** - * smb2_flush() - handler for smb2 flush file - fsync - * @work: smb work containing flush command buffer - * - * Return: 0 on success, otherwise error - */ -int smb2_flush(struct ksmbd_work *work) -{ - struct smb2_flush_req *req; - struct smb2_flush_rsp *rsp; - int err; - - WORK_BUFFERS(work, req, rsp); - - ksmbd_debug(SMB, "SMB2_FLUSH called for fid %llu\n", req->VolatileFileId); - - err = ksmbd_vfs_fsync(work, req->VolatileFileId, req->PersistentFileId); - if (err) - goto out; - - rsp->StructureSize = cpu_to_le16(4); - rsp->Reserved = 0; - inc_rfc1001_len(work->response_buf, 4); - return 0; - -out: - if (err) { - rsp->hdr.Status = STATUS_INVALID_HANDLE; - smb2_set_err_rsp(work); - } - - return err; -} - -/** - * smb2_cancel() - handler for smb2 cancel command - * @work: smb work containing cancel command buffer - * - * Return: 0 on success, otherwise error - */ -int smb2_cancel(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_hdr *hdr = smb2_get_msg(work->request_buf); - struct smb2_hdr *chdr; - struct ksmbd_work *iter; - struct list_head *command_list; - - ksmbd_debug(SMB, "smb2 cancel called on mid %llu, async flags 0x%x\n", - hdr->MessageId, hdr->Flags); - - if (hdr->Flags & SMB2_FLAGS_ASYNC_COMMAND) { - command_list = &conn->async_requests; - - spin_lock(&conn->request_lock); - list_for_each_entry(iter, command_list, - async_request_entry) { - chdr = smb2_get_msg(iter->request_buf); - - if (iter->async_id != - le64_to_cpu(hdr->Id.AsyncId)) - continue; - - ksmbd_debug(SMB, - "smb2 with AsyncId %llu cancelled command = 0x%x\n", - le64_to_cpu(hdr->Id.AsyncId), - le16_to_cpu(chdr->Command)); - iter->state = KSMBD_WORK_CANCELLED; - if (iter->cancel_fn) - iter->cancel_fn(iter->cancel_argv); - break; - } - spin_unlock(&conn->request_lock); - } else { - command_list = &conn->requests; - - spin_lock(&conn->request_lock); - list_for_each_entry(iter, command_list, request_entry) { - chdr = smb2_get_msg(iter->request_buf); - - if (chdr->MessageId != hdr->MessageId || - iter == work) - continue; - - ksmbd_debug(SMB, - "smb2 with mid %llu cancelled command = 0x%x\n", - le64_to_cpu(hdr->MessageId), - le16_to_cpu(chdr->Command)); - iter->state = KSMBD_WORK_CANCELLED; - break; - } - spin_unlock(&conn->request_lock); - } - - /* For SMB2_CANCEL command itself send no response*/ - work->send_no_response = 1; - return 0; -} - -struct file_lock *smb_flock_init(struct file *f) -{ - struct file_lock *fl; - - fl = locks_alloc_lock(); - if (!fl) - goto out; - - locks_init_lock(fl); - - fl->fl_owner = f; - fl->fl_pid = current->tgid; - fl->fl_file = f; - fl->fl_flags = FL_POSIX; - fl->fl_ops = NULL; - fl->fl_lmops = NULL; - -out: - return fl; -} - -static int smb2_set_flock_flags(struct file_lock *flock, int flags) -{ - int cmd = -EINVAL; - - /* Checking for wrong flag combination during lock request*/ - switch (flags) { - case SMB2_LOCKFLAG_SHARED: - ksmbd_debug(SMB, "received shared request\n"); - cmd = F_SETLKW; - flock->fl_type = F_RDLCK; - flock->fl_flags |= FL_SLEEP; - break; - case SMB2_LOCKFLAG_EXCLUSIVE: - ksmbd_debug(SMB, "received exclusive request\n"); - cmd = F_SETLKW; - flock->fl_type = F_WRLCK; - flock->fl_flags |= FL_SLEEP; - break; - case SMB2_LOCKFLAG_SHARED | SMB2_LOCKFLAG_FAIL_IMMEDIATELY: - ksmbd_debug(SMB, - "received shared & fail immediately request\n"); - cmd = F_SETLK; - flock->fl_type = F_RDLCK; - break; - case SMB2_LOCKFLAG_EXCLUSIVE | SMB2_LOCKFLAG_FAIL_IMMEDIATELY: - ksmbd_debug(SMB, - "received exclusive & fail immediately request\n"); - cmd = F_SETLK; - flock->fl_type = F_WRLCK; - break; - case SMB2_LOCKFLAG_UNLOCK: - ksmbd_debug(SMB, "received unlock request\n"); - flock->fl_type = F_UNLCK; - cmd = 0; - break; - } - - return cmd; -} - -static struct ksmbd_lock *smb2_lock_init(struct file_lock *flock, - unsigned int cmd, int flags, - struct list_head *lock_list) -{ - struct ksmbd_lock *lock; - - lock = kzalloc(sizeof(struct ksmbd_lock), GFP_KERNEL); - if (!lock) - return NULL; - - lock->cmd = cmd; - lock->fl = flock; - lock->start = flock->fl_start; - lock->end = flock->fl_end; - lock->flags = flags; - if (lock->start == lock->end) - lock->zero_len = 1; - INIT_LIST_HEAD(&lock->clist); - INIT_LIST_HEAD(&lock->flist); - INIT_LIST_HEAD(&lock->llist); - list_add_tail(&lock->llist, lock_list); - - return lock; -} - -static void smb2_remove_blocked_lock(void **argv) -{ - struct file_lock *flock = (struct file_lock *)argv[0]; - - ksmbd_vfs_posix_lock_unblock(flock); - wake_up(&flock->fl_wait); -} - -static inline bool lock_defer_pending(struct file_lock *fl) -{ - /* check pending lock waiters */ - return waitqueue_active(&fl->fl_wait); -} - -/** - * smb2_lock() - handler for smb2 file lock command - * @work: smb work containing lock command buffer - * - * Return: 0 on success, otherwise error - */ -int smb2_lock(struct ksmbd_work *work) -{ - struct smb2_lock_req *req = smb2_get_msg(work->request_buf); - struct smb2_lock_rsp *rsp = smb2_get_msg(work->response_buf); - struct smb2_lock_element *lock_ele; - struct ksmbd_file *fp = NULL; - struct file_lock *flock = NULL; - struct file *filp = NULL; - int lock_count; - int flags = 0; - int cmd = 0; - int err = -EIO, i, rc = 0; - u64 lock_start, lock_length; - struct ksmbd_lock *smb_lock = NULL, *cmp_lock, *tmp, *tmp2; - struct ksmbd_conn *conn; - int nolock = 0; - LIST_HEAD(lock_list); - LIST_HEAD(rollback_list); - int prior_lock = 0; - - ksmbd_debug(SMB, "Received lock request\n"); - fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); - if (!fp) { - ksmbd_debug(SMB, "Invalid file id for lock : %llu\n", req->VolatileFileId); - err = -ENOENT; - goto out2; - } - - filp = fp->filp; - lock_count = le16_to_cpu(req->LockCount); - lock_ele = req->locks; - - ksmbd_debug(SMB, "lock count is %d\n", lock_count); - if (!lock_count) { - err = -EINVAL; - goto out2; - } - - for (i = 0; i < lock_count; i++) { - flags = le32_to_cpu(lock_ele[i].Flags); - - flock = smb_flock_init(filp); - if (!flock) - goto out; - - cmd = smb2_set_flock_flags(flock, flags); - - lock_start = le64_to_cpu(lock_ele[i].Offset); - lock_length = le64_to_cpu(lock_ele[i].Length); - if (lock_start > U64_MAX - lock_length) { - pr_err("Invalid lock range requested\n"); - rsp->hdr.Status = STATUS_INVALID_LOCK_RANGE; - goto out; - } - - if (lock_start > OFFSET_MAX) - flock->fl_start = OFFSET_MAX; - else - flock->fl_start = lock_start; - - lock_length = le64_to_cpu(lock_ele[i].Length); - if (lock_length > OFFSET_MAX - flock->fl_start) - lock_length = OFFSET_MAX - flock->fl_start; - - flock->fl_end = flock->fl_start + lock_length; - - if (flock->fl_end < flock->fl_start) { - ksmbd_debug(SMB, - "the end offset(%llx) is smaller than the start offset(%llx)\n", - flock->fl_end, flock->fl_start); - rsp->hdr.Status = STATUS_INVALID_LOCK_RANGE; - goto out; - } - - /* Check conflict locks in one request */ - list_for_each_entry(cmp_lock, &lock_list, llist) { - if (cmp_lock->fl->fl_start <= flock->fl_start && - cmp_lock->fl->fl_end >= flock->fl_end) { - if (cmp_lock->fl->fl_type != F_UNLCK && - flock->fl_type != F_UNLCK) { - pr_err("conflict two locks in one request\n"); - err = -EINVAL; - goto out; - } - } - } - - smb_lock = smb2_lock_init(flock, cmd, flags, &lock_list); - if (!smb_lock) { - err = -EINVAL; - goto out; - } - } - - list_for_each_entry_safe(smb_lock, tmp, &lock_list, llist) { - if (smb_lock->cmd < 0) { - err = -EINVAL; - goto out; - } - - if (!(smb_lock->flags & SMB2_LOCKFLAG_MASK)) { - err = -EINVAL; - goto out; - } - - if ((prior_lock & (SMB2_LOCKFLAG_EXCLUSIVE | SMB2_LOCKFLAG_SHARED) && - smb_lock->flags & SMB2_LOCKFLAG_UNLOCK) || - (prior_lock == SMB2_LOCKFLAG_UNLOCK && - !(smb_lock->flags & SMB2_LOCKFLAG_UNLOCK))) { - err = -EINVAL; - goto out; - } - - prior_lock = smb_lock->flags; - - if (!(smb_lock->flags & SMB2_LOCKFLAG_UNLOCK) && - !(smb_lock->flags & SMB2_LOCKFLAG_FAIL_IMMEDIATELY)) - goto no_check_cl; - - nolock = 1; - /* check locks in connection list */ - down_read(&conn_list_lock); - list_for_each_entry(conn, &conn_list, conns_list) { - spin_lock(&conn->llist_lock); - list_for_each_entry_safe(cmp_lock, tmp2, &conn->lock_list, clist) { - if (file_inode(cmp_lock->fl->fl_file) != - file_inode(smb_lock->fl->fl_file)) - continue; - - if (smb_lock->fl->fl_type == F_UNLCK) { - if (cmp_lock->fl->fl_file == smb_lock->fl->fl_file && - cmp_lock->start == smb_lock->start && - cmp_lock->end == smb_lock->end && - !lock_defer_pending(cmp_lock->fl)) { - nolock = 0; - list_del(&cmp_lock->flist); - list_del(&cmp_lock->clist); - spin_unlock(&conn->llist_lock); - up_read(&conn_list_lock); - - locks_free_lock(cmp_lock->fl); - kfree(cmp_lock); - goto out_check_cl; - } - continue; - } - - if (cmp_lock->fl->fl_file == smb_lock->fl->fl_file) { - if (smb_lock->flags & SMB2_LOCKFLAG_SHARED) - continue; - } else { - if (cmp_lock->flags & SMB2_LOCKFLAG_SHARED) - continue; - } - - /* check zero byte lock range */ - if (cmp_lock->zero_len && !smb_lock->zero_len && - cmp_lock->start > smb_lock->start && - cmp_lock->start < smb_lock->end) { - spin_unlock(&conn->llist_lock); - up_read(&conn_list_lock); - pr_err("previous lock conflict with zero byte lock range\n"); - goto out; - } - - if (smb_lock->zero_len && !cmp_lock->zero_len && - smb_lock->start > cmp_lock->start && - smb_lock->start < cmp_lock->end) { - spin_unlock(&conn->llist_lock); - up_read(&conn_list_lock); - pr_err("current lock conflict with zero byte lock range\n"); - goto out; - } - - if (((cmp_lock->start <= smb_lock->start && - cmp_lock->end > smb_lock->start) || - (cmp_lock->start < smb_lock->end && - cmp_lock->end >= smb_lock->end)) && - !cmp_lock->zero_len && !smb_lock->zero_len) { - spin_unlock(&conn->llist_lock); - up_read(&conn_list_lock); - pr_err("Not allow lock operation on exclusive lock range\n"); - goto out; - } - } - spin_unlock(&conn->llist_lock); - } - up_read(&conn_list_lock); -out_check_cl: - if (smb_lock->fl->fl_type == F_UNLCK && nolock) { - pr_err("Try to unlock nolocked range\n"); - rsp->hdr.Status = STATUS_RANGE_NOT_LOCKED; - goto out; - } - -no_check_cl: - if (smb_lock->zero_len) { - err = 0; - goto skip; - } - - flock = smb_lock->fl; - list_del(&smb_lock->llist); -retry: - rc = vfs_lock_file(filp, smb_lock->cmd, flock, NULL); -skip: - if (flags & SMB2_LOCKFLAG_UNLOCK) { - if (!rc) { - ksmbd_debug(SMB, "File unlocked\n"); - } else if (rc == -ENOENT) { - rsp->hdr.Status = STATUS_NOT_LOCKED; - goto out; - } - locks_free_lock(flock); - kfree(smb_lock); - } else { - if (rc == FILE_LOCK_DEFERRED) { - void **argv; - - ksmbd_debug(SMB, - "would have to wait for getting lock\n"); - spin_lock(&work->conn->llist_lock); - list_add_tail(&smb_lock->clist, - &work->conn->lock_list); - spin_unlock(&work->conn->llist_lock); - list_add(&smb_lock->llist, &rollback_list); - - argv = kmalloc(sizeof(void *), GFP_KERNEL); - if (!argv) { - err = -ENOMEM; - goto out; - } - argv[0] = flock; - - rc = setup_async_work(work, - smb2_remove_blocked_lock, - argv); - if (rc) { - err = -ENOMEM; - goto out; - } - spin_lock(&fp->f_lock); - list_add(&work->fp_entry, &fp->blocked_works); - spin_unlock(&fp->f_lock); - - smb2_send_interim_resp(work, STATUS_PENDING); - - ksmbd_vfs_posix_lock_wait(flock); - - spin_lock(&work->conn->request_lock); - spin_lock(&fp->f_lock); - list_del(&work->fp_entry); - work->cancel_fn = NULL; - kfree(argv); - spin_unlock(&fp->f_lock); - spin_unlock(&work->conn->request_lock); - - if (work->state != KSMBD_WORK_ACTIVE) { - list_del(&smb_lock->llist); - spin_lock(&work->conn->llist_lock); - list_del(&smb_lock->clist); - spin_unlock(&work->conn->llist_lock); - locks_free_lock(flock); - - if (work->state == KSMBD_WORK_CANCELLED) { - rsp->hdr.Status = - STATUS_CANCELLED; - kfree(smb_lock); - smb2_send_interim_resp(work, - STATUS_CANCELLED); - work->send_no_response = 1; - goto out; - } - init_smb2_rsp_hdr(work); - smb2_set_err_rsp(work); - rsp->hdr.Status = - STATUS_RANGE_NOT_LOCKED; - kfree(smb_lock); - goto out2; - } - - list_del(&smb_lock->llist); - spin_lock(&work->conn->llist_lock); - list_del(&smb_lock->clist); - spin_unlock(&work->conn->llist_lock); - - goto retry; - } else if (!rc) { - spin_lock(&work->conn->llist_lock); - list_add_tail(&smb_lock->clist, - &work->conn->lock_list); - list_add_tail(&smb_lock->flist, - &fp->lock_list); - spin_unlock(&work->conn->llist_lock); - list_add(&smb_lock->llist, &rollback_list); - ksmbd_debug(SMB, "successful in taking lock\n"); - } else { - goto out; - } - } - } - - if (atomic_read(&fp->f_ci->op_count) > 1) - smb_break_all_oplock(work, fp); - - rsp->StructureSize = cpu_to_le16(4); - ksmbd_debug(SMB, "successful in taking lock\n"); - rsp->hdr.Status = STATUS_SUCCESS; - rsp->Reserved = 0; - inc_rfc1001_len(work->response_buf, 4); - ksmbd_fd_put(work, fp); - return 0; - -out: - list_for_each_entry_safe(smb_lock, tmp, &lock_list, llist) { - locks_free_lock(smb_lock->fl); - list_del(&smb_lock->llist); - kfree(smb_lock); - } - - list_for_each_entry_safe(smb_lock, tmp, &rollback_list, llist) { - struct file_lock *rlock = NULL; - - rlock = smb_flock_init(filp); - rlock->fl_type = F_UNLCK; - rlock->fl_start = smb_lock->start; - rlock->fl_end = smb_lock->end; - - rc = vfs_lock_file(filp, 0, rlock, NULL); - if (rc) - pr_err("rollback unlock fail : %d\n", rc); - - list_del(&smb_lock->llist); - spin_lock(&work->conn->llist_lock); - if (!list_empty(&smb_lock->flist)) - list_del(&smb_lock->flist); - list_del(&smb_lock->clist); - spin_unlock(&work->conn->llist_lock); - - locks_free_lock(smb_lock->fl); - locks_free_lock(rlock); - kfree(smb_lock); - } -out2: - ksmbd_debug(SMB, "failed in taking lock(flags : %x), err : %d\n", flags, err); - - if (!rsp->hdr.Status) { - if (err == -EINVAL) - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - else if (err == -ENOMEM) - rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; - else if (err == -ENOENT) - rsp->hdr.Status = STATUS_FILE_CLOSED; - else - rsp->hdr.Status = STATUS_LOCK_NOT_GRANTED; - } - - smb2_set_err_rsp(work); - ksmbd_fd_put(work, fp); - return err; -} - -static int fsctl_copychunk(struct ksmbd_work *work, - struct copychunk_ioctl_req *ci_req, - unsigned int cnt_code, - unsigned int input_count, - unsigned long long volatile_id, - unsigned long long persistent_id, - struct smb2_ioctl_rsp *rsp) -{ - struct copychunk_ioctl_rsp *ci_rsp; - struct ksmbd_file *src_fp = NULL, *dst_fp = NULL; - struct srv_copychunk *chunks; - unsigned int i, chunk_count, chunk_count_written = 0; - unsigned int chunk_size_written = 0; - loff_t total_size_written = 0; - int ret = 0; - - ci_rsp = (struct copychunk_ioctl_rsp *)&rsp->Buffer[0]; - - rsp->VolatileFileId = volatile_id; - rsp->PersistentFileId = persistent_id; - ci_rsp->ChunksWritten = - cpu_to_le32(ksmbd_server_side_copy_max_chunk_count()); - ci_rsp->ChunkBytesWritten = - cpu_to_le32(ksmbd_server_side_copy_max_chunk_size()); - ci_rsp->TotalBytesWritten = - cpu_to_le32(ksmbd_server_side_copy_max_total_size()); - - chunks = (struct srv_copychunk *)&ci_req->Chunks[0]; - chunk_count = le32_to_cpu(ci_req->ChunkCount); - if (chunk_count == 0) - goto out; - total_size_written = 0; - - /* verify the SRV_COPYCHUNK_COPY packet */ - if (chunk_count > ksmbd_server_side_copy_max_chunk_count() || - input_count < offsetof(struct copychunk_ioctl_req, Chunks) + - chunk_count * sizeof(struct srv_copychunk)) { - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - return -EINVAL; - } - - for (i = 0; i < chunk_count; i++) { - if (le32_to_cpu(chunks[i].Length) == 0 || - le32_to_cpu(chunks[i].Length) > ksmbd_server_side_copy_max_chunk_size()) - break; - total_size_written += le32_to_cpu(chunks[i].Length); - } - - if (i < chunk_count || - total_size_written > ksmbd_server_side_copy_max_total_size()) { - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - return -EINVAL; - } - - src_fp = ksmbd_lookup_foreign_fd(work, - le64_to_cpu(ci_req->ResumeKey[0])); - dst_fp = ksmbd_lookup_fd_slow(work, volatile_id, persistent_id); - ret = -EINVAL; - if (!src_fp || - src_fp->persistent_id != le64_to_cpu(ci_req->ResumeKey[1])) { - rsp->hdr.Status = STATUS_OBJECT_NAME_NOT_FOUND; - goto out; - } - - if (!dst_fp) { - rsp->hdr.Status = STATUS_FILE_CLOSED; - goto out; - } - - /* - * FILE_READ_DATA should only be included in - * the FSCTL_COPYCHUNK case - */ - if (cnt_code == FSCTL_COPYCHUNK && - !(dst_fp->daccess & (FILE_READ_DATA_LE | FILE_GENERIC_READ_LE))) { - rsp->hdr.Status = STATUS_ACCESS_DENIED; - goto out; - } - - ret = ksmbd_vfs_copy_file_ranges(work, src_fp, dst_fp, - chunks, chunk_count, - &chunk_count_written, - &chunk_size_written, - &total_size_written); - if (ret < 0) { - if (ret == -EACCES) - rsp->hdr.Status = STATUS_ACCESS_DENIED; - if (ret == -EAGAIN) - rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT; - else if (ret == -EBADF) - rsp->hdr.Status = STATUS_INVALID_HANDLE; - else if (ret == -EFBIG || ret == -ENOSPC) - rsp->hdr.Status = STATUS_DISK_FULL; - else if (ret == -EINVAL) - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - else if (ret == -EISDIR) - rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY; - else if (ret == -E2BIG) - rsp->hdr.Status = STATUS_INVALID_VIEW_SIZE; - else - rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR; - } - - ci_rsp->ChunksWritten = cpu_to_le32(chunk_count_written); - ci_rsp->ChunkBytesWritten = cpu_to_le32(chunk_size_written); - ci_rsp->TotalBytesWritten = cpu_to_le32(total_size_written); -out: - ksmbd_fd_put(work, src_fp); - ksmbd_fd_put(work, dst_fp); - return ret; -} - -static __be32 idev_ipv4_address(struct in_device *idev) -{ - __be32 addr = 0; - - struct in_ifaddr *ifa; - - rcu_read_lock(); - in_dev_for_each_ifa_rcu(ifa, idev) { - if (ifa->ifa_flags & IFA_F_SECONDARY) - continue; - - addr = ifa->ifa_address; - break; - } - rcu_read_unlock(); - return addr; -} - -static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn, - struct smb2_ioctl_rsp *rsp, - unsigned int out_buf_len) -{ - struct network_interface_info_ioctl_rsp *nii_rsp = NULL; - int nbytes = 0; - struct net_device *netdev; - struct sockaddr_storage_rsp *sockaddr_storage; - unsigned int flags; - unsigned long long speed; - - rtnl_lock(); - for_each_netdev(&init_net, netdev) { - bool ipv4_set = false; - - if (netdev->type == ARPHRD_LOOPBACK) - continue; - - flags = dev_get_flags(netdev); - if (!(flags & IFF_RUNNING)) - continue; -ipv6_retry: - if (out_buf_len < - nbytes + sizeof(struct network_interface_info_ioctl_rsp)) { - rtnl_unlock(); - return -ENOSPC; - } - - nii_rsp = (struct network_interface_info_ioctl_rsp *) - &rsp->Buffer[nbytes]; - nii_rsp->IfIndex = cpu_to_le32(netdev->ifindex); - - nii_rsp->Capability = 0; - if (netdev->real_num_tx_queues > 1) - nii_rsp->Capability |= cpu_to_le32(RSS_CAPABLE); - if (ksmbd_rdma_capable_netdev(netdev)) - nii_rsp->Capability |= cpu_to_le32(RDMA_CAPABLE); - - nii_rsp->Next = cpu_to_le32(152); - nii_rsp->Reserved = 0; - - if (netdev->ethtool_ops->get_link_ksettings) { - struct ethtool_link_ksettings cmd; - - netdev->ethtool_ops->get_link_ksettings(netdev, &cmd); - speed = cmd.base.speed; - } else { - ksmbd_debug(SMB, "%s %s\n", netdev->name, - "speed is unknown, defaulting to 1Gb/sec"); - speed = SPEED_1000; - } - - speed *= 1000000; - nii_rsp->LinkSpeed = cpu_to_le64(speed); - - sockaddr_storage = (struct sockaddr_storage_rsp *) - nii_rsp->SockAddr_Storage; - memset(sockaddr_storage, 0, 128); - - if (!ipv4_set) { - struct in_device *idev; - - sockaddr_storage->Family = cpu_to_le16(INTERNETWORK); - sockaddr_storage->addr4.Port = 0; - - idev = __in_dev_get_rtnl(netdev); - if (!idev) - continue; - sockaddr_storage->addr4.IPv4address = - idev_ipv4_address(idev); - nbytes += sizeof(struct network_interface_info_ioctl_rsp); - ipv4_set = true; - goto ipv6_retry; - } else { - struct inet6_dev *idev6; - struct inet6_ifaddr *ifa; - __u8 *ipv6_addr = sockaddr_storage->addr6.IPv6address; - - sockaddr_storage->Family = cpu_to_le16(INTERNETWORKV6); - sockaddr_storage->addr6.Port = 0; - sockaddr_storage->addr6.FlowInfo = 0; - - idev6 = __in6_dev_get(netdev); - if (!idev6) - continue; - - list_for_each_entry(ifa, &idev6->addr_list, if_list) { - if (ifa->flags & (IFA_F_TENTATIVE | - IFA_F_DEPRECATED)) - continue; - memcpy(ipv6_addr, ifa->addr.s6_addr, 16); - break; - } - sockaddr_storage->addr6.ScopeId = 0; - nbytes += sizeof(struct network_interface_info_ioctl_rsp); - } - } - rtnl_unlock(); - - /* zero if this is last one */ - if (nii_rsp) - nii_rsp->Next = 0; - - rsp->PersistentFileId = SMB2_NO_FID; - rsp->VolatileFileId = SMB2_NO_FID; - return nbytes; -} - -static int fsctl_validate_negotiate_info(struct ksmbd_conn *conn, - struct validate_negotiate_info_req *neg_req, - struct validate_negotiate_info_rsp *neg_rsp, - unsigned int in_buf_len) -{ - int ret = 0; - int dialect; - - if (in_buf_len < offsetof(struct validate_negotiate_info_req, Dialects) + - le16_to_cpu(neg_req->DialectCount) * sizeof(__le16)) - return -EINVAL; - - dialect = ksmbd_lookup_dialect_by_id(neg_req->Dialects, - neg_req->DialectCount); - if (dialect == BAD_PROT_ID || dialect != conn->dialect) { - ret = -EINVAL; - goto err_out; - } - - if (strncmp(neg_req->Guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE)) { - ret = -EINVAL; - goto err_out; - } - - if (le16_to_cpu(neg_req->SecurityMode) != conn->cli_sec_mode) { - ret = -EINVAL; - goto err_out; - } - - if (le32_to_cpu(neg_req->Capabilities) != conn->cli_cap) { - ret = -EINVAL; - goto err_out; - } - - neg_rsp->Capabilities = cpu_to_le32(conn->vals->capabilities); - memset(neg_rsp->Guid, 0, SMB2_CLIENT_GUID_SIZE); - neg_rsp->SecurityMode = cpu_to_le16(conn->srv_sec_mode); - neg_rsp->Dialect = cpu_to_le16(conn->dialect); -err_out: - return ret; -} - -static int fsctl_query_allocated_ranges(struct ksmbd_work *work, u64 id, - struct file_allocated_range_buffer *qar_req, - struct file_allocated_range_buffer *qar_rsp, - unsigned int in_count, unsigned int *out_count) -{ - struct ksmbd_file *fp; - loff_t start, length; - int ret = 0; - - *out_count = 0; - if (in_count == 0) - return -EINVAL; - - start = le64_to_cpu(qar_req->file_offset); - length = le64_to_cpu(qar_req->length); - - if (start < 0 || length < 0) - return -EINVAL; - - fp = ksmbd_lookup_fd_fast(work, id); - if (!fp) - return -ENOENT; - - ret = ksmbd_vfs_fqar_lseek(fp, start, length, - qar_rsp, in_count, out_count); - if (ret && ret != -E2BIG) - *out_count = 0; - - ksmbd_fd_put(work, fp); - return ret; -} - -static int fsctl_pipe_transceive(struct ksmbd_work *work, u64 id, - unsigned int out_buf_len, - struct smb2_ioctl_req *req, - struct smb2_ioctl_rsp *rsp) -{ - struct ksmbd_rpc_command *rpc_resp; - char *data_buf = (char *)&req->Buffer[0]; - int nbytes = 0; - - rpc_resp = ksmbd_rpc_ioctl(work->sess, id, data_buf, - le32_to_cpu(req->InputCount)); - if (rpc_resp) { - if (rpc_resp->flags == KSMBD_RPC_SOME_NOT_MAPPED) { - /* - * set STATUS_SOME_NOT_MAPPED response - * for unknown domain sid. - */ - rsp->hdr.Status = STATUS_SOME_NOT_MAPPED; - } else if (rpc_resp->flags == KSMBD_RPC_ENOTIMPLEMENTED) { - rsp->hdr.Status = STATUS_NOT_SUPPORTED; - goto out; - } else if (rpc_resp->flags != KSMBD_RPC_OK) { - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - goto out; - } - - nbytes = rpc_resp->payload_sz; - if (rpc_resp->payload_sz > out_buf_len) { - rsp->hdr.Status = STATUS_BUFFER_OVERFLOW; - nbytes = out_buf_len; - } - - if (!rpc_resp->payload_sz) { - rsp->hdr.Status = - STATUS_UNEXPECTED_IO_ERROR; - goto out; - } - - memcpy((char *)rsp->Buffer, rpc_resp->payload, nbytes); - } -out: - kvfree(rpc_resp); - return nbytes; -} - -static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id, - struct file_sparse *sparse) -{ - struct ksmbd_file *fp; - struct user_namespace *user_ns; - int ret = 0; - __le32 old_fattr; - - fp = ksmbd_lookup_fd_fast(work, id); - if (!fp) - return -ENOENT; - user_ns = file_mnt_user_ns(fp->filp); - - old_fattr = fp->f_ci->m_fattr; - if (sparse->SetSparse) - fp->f_ci->m_fattr |= FILE_ATTRIBUTE_SPARSE_FILE_LE; - else - fp->f_ci->m_fattr &= ~FILE_ATTRIBUTE_SPARSE_FILE_LE; - - if (fp->f_ci->m_fattr != old_fattr && - test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) { - struct xattr_dos_attrib da; - - ret = ksmbd_vfs_get_dos_attrib_xattr(user_ns, - fp->filp->f_path.dentry, &da); - if (ret <= 0) - goto out; - - da.attr = le32_to_cpu(fp->f_ci->m_fattr); - ret = ksmbd_vfs_set_dos_attrib_xattr(user_ns, - fp->filp->f_path.dentry, &da); - if (ret) - fp->f_ci->m_fattr = old_fattr; - } - -out: - ksmbd_fd_put(work, fp); - return ret; -} - -static int fsctl_request_resume_key(struct ksmbd_work *work, - struct smb2_ioctl_req *req, - struct resume_key_ioctl_rsp *key_rsp) -{ - struct ksmbd_file *fp; - - fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); - if (!fp) - return -ENOENT; - - memset(key_rsp, 0, sizeof(*key_rsp)); - key_rsp->ResumeKey[0] = req->VolatileFileId; - key_rsp->ResumeKey[1] = req->PersistentFileId; - ksmbd_fd_put(work, fp); - - return 0; -} - -/** - * smb2_ioctl() - handler for smb2 ioctl command - * @work: smb work containing ioctl command buffer - * - * Return: 0 on success, otherwise error - */ -int smb2_ioctl(struct ksmbd_work *work) -{ - struct smb2_ioctl_req *req; - struct smb2_ioctl_rsp *rsp; - unsigned int cnt_code, nbytes = 0, out_buf_len, in_buf_len; - u64 id = KSMBD_NO_FID; - struct ksmbd_conn *conn = work->conn; - int ret = 0; - - if (work->next_smb2_rcv_hdr_off) { - req = ksmbd_req_buf_next(work); - rsp = ksmbd_resp_buf_next(work); - if (!has_file_id(req->VolatileFileId)) { - ksmbd_debug(SMB, "Compound request set FID = %llu\n", - work->compound_fid); - id = work->compound_fid; - } - } else { - req = smb2_get_msg(work->request_buf); - rsp = smb2_get_msg(work->response_buf); - } - - if (!has_file_id(id)) - id = req->VolatileFileId; - - if (req->Flags != cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL)) { - rsp->hdr.Status = STATUS_NOT_SUPPORTED; - goto out; - } - - cnt_code = le32_to_cpu(req->CtlCode); - ret = smb2_calc_max_out_buf_len(work, 48, - le32_to_cpu(req->MaxOutputResponse)); - if (ret < 0) { - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - goto out; - } - out_buf_len = (unsigned int)ret; - in_buf_len = le32_to_cpu(req->InputCount); - - switch (cnt_code) { - case FSCTL_DFS_GET_REFERRALS: - case FSCTL_DFS_GET_REFERRALS_EX: - /* Not support DFS yet */ - rsp->hdr.Status = STATUS_FS_DRIVER_REQUIRED; - goto out; - case FSCTL_CREATE_OR_GET_OBJECT_ID: - { - struct file_object_buf_type1_ioctl_rsp *obj_buf; - - nbytes = sizeof(struct file_object_buf_type1_ioctl_rsp); - obj_buf = (struct file_object_buf_type1_ioctl_rsp *) - &rsp->Buffer[0]; - - /* - * TODO: This is dummy implementation to pass smbtorture - * Need to check correct response later - */ - memset(obj_buf->ObjectId, 0x0, 16); - memset(obj_buf->BirthVolumeId, 0x0, 16); - memset(obj_buf->BirthObjectId, 0x0, 16); - memset(obj_buf->DomainId, 0x0, 16); - - break; - } - case FSCTL_PIPE_TRANSCEIVE: - out_buf_len = min_t(u32, KSMBD_IPC_MAX_PAYLOAD, out_buf_len); - nbytes = fsctl_pipe_transceive(work, id, out_buf_len, req, rsp); - break; - case FSCTL_VALIDATE_NEGOTIATE_INFO: - if (conn->dialect < SMB30_PROT_ID) { - ret = -EOPNOTSUPP; - goto out; - } - - if (in_buf_len < offsetof(struct validate_negotiate_info_req, - Dialects)) { - ret = -EINVAL; - goto out; - } - - if (out_buf_len < sizeof(struct validate_negotiate_info_rsp)) { - ret = -EINVAL; - goto out; - } - - ret = fsctl_validate_negotiate_info(conn, - (struct validate_negotiate_info_req *)&req->Buffer[0], - (struct validate_negotiate_info_rsp *)&rsp->Buffer[0], - in_buf_len); - if (ret < 0) - goto out; - - nbytes = sizeof(struct validate_negotiate_info_rsp); - rsp->PersistentFileId = SMB2_NO_FID; - rsp->VolatileFileId = SMB2_NO_FID; - break; - case FSCTL_QUERY_NETWORK_INTERFACE_INFO: - ret = fsctl_query_iface_info_ioctl(conn, rsp, out_buf_len); - if (ret < 0) - goto out; - nbytes = ret; - break; - case FSCTL_REQUEST_RESUME_KEY: - if (out_buf_len < sizeof(struct resume_key_ioctl_rsp)) { - ret = -EINVAL; - goto out; - } - - ret = fsctl_request_resume_key(work, req, - (struct resume_key_ioctl_rsp *)&rsp->Buffer[0]); - if (ret < 0) - goto out; - rsp->PersistentFileId = req->PersistentFileId; - rsp->VolatileFileId = req->VolatileFileId; - nbytes = sizeof(struct resume_key_ioctl_rsp); - break; - case FSCTL_COPYCHUNK: - case FSCTL_COPYCHUNK_WRITE: - if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { - ksmbd_debug(SMB, - "User does not have write permission\n"); - ret = -EACCES; - goto out; - } - - if (in_buf_len < sizeof(struct copychunk_ioctl_req)) { - ret = -EINVAL; - goto out; - } - - if (out_buf_len < sizeof(struct copychunk_ioctl_rsp)) { - ret = -EINVAL; - goto out; - } - - nbytes = sizeof(struct copychunk_ioctl_rsp); - rsp->VolatileFileId = req->VolatileFileId; - rsp->PersistentFileId = req->PersistentFileId; - fsctl_copychunk(work, - (struct copychunk_ioctl_req *)&req->Buffer[0], - le32_to_cpu(req->CtlCode), - le32_to_cpu(req->InputCount), - req->VolatileFileId, - req->PersistentFileId, - rsp); - break; - case FSCTL_SET_SPARSE: - if (in_buf_len < sizeof(struct file_sparse)) { - ret = -EINVAL; - goto out; - } - - ret = fsctl_set_sparse(work, id, - (struct file_sparse *)&req->Buffer[0]); - if (ret < 0) - goto out; - break; - case FSCTL_SET_ZERO_DATA: - { - struct file_zero_data_information *zero_data; - struct ksmbd_file *fp; - loff_t off, len, bfz; - - if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { - ksmbd_debug(SMB, - "User does not have write permission\n"); - ret = -EACCES; - goto out; - } - - if (in_buf_len < sizeof(struct file_zero_data_information)) { - ret = -EINVAL; - goto out; - } - - zero_data = - (struct file_zero_data_information *)&req->Buffer[0]; - - off = le64_to_cpu(zero_data->FileOffset); - bfz = le64_to_cpu(zero_data->BeyondFinalZero); - if (off < 0 || bfz < 0 || off > bfz) { - ret = -EINVAL; - goto out; - } - - len = bfz - off; - if (len) { - fp = ksmbd_lookup_fd_fast(work, id); - if (!fp) { - ret = -ENOENT; - goto out; - } - - ret = ksmbd_vfs_zero_data(work, fp, off, len); - ksmbd_fd_put(work, fp); - if (ret < 0) - goto out; - } - break; - } - case FSCTL_QUERY_ALLOCATED_RANGES: - if (in_buf_len < sizeof(struct file_allocated_range_buffer)) { - ret = -EINVAL; - goto out; - } - - ret = fsctl_query_allocated_ranges(work, id, - (struct file_allocated_range_buffer *)&req->Buffer[0], - (struct file_allocated_range_buffer *)&rsp->Buffer[0], - out_buf_len / - sizeof(struct file_allocated_range_buffer), &nbytes); - if (ret == -E2BIG) { - rsp->hdr.Status = STATUS_BUFFER_OVERFLOW; - } else if (ret < 0) { - nbytes = 0; - goto out; - } - - nbytes *= sizeof(struct file_allocated_range_buffer); - break; - case FSCTL_GET_REPARSE_POINT: - { - struct reparse_data_buffer *reparse_ptr; - struct ksmbd_file *fp; - - reparse_ptr = (struct reparse_data_buffer *)&rsp->Buffer[0]; - fp = ksmbd_lookup_fd_fast(work, id); - if (!fp) { - pr_err("not found fp!!\n"); - ret = -ENOENT; - goto out; - } - - reparse_ptr->ReparseTag = - smb2_get_reparse_tag_special_file(file_inode(fp->filp)->i_mode); - reparse_ptr->ReparseDataLength = 0; - ksmbd_fd_put(work, fp); - nbytes = sizeof(struct reparse_data_buffer); - break; - } - case FSCTL_DUPLICATE_EXTENTS_TO_FILE: - { - struct ksmbd_file *fp_in, *fp_out = NULL; - struct duplicate_extents_to_file *dup_ext; - loff_t src_off, dst_off, length, cloned; - - if (in_buf_len < sizeof(struct duplicate_extents_to_file)) { - ret = -EINVAL; - goto out; - } - - dup_ext = (struct duplicate_extents_to_file *)&req->Buffer[0]; - - fp_in = ksmbd_lookup_fd_slow(work, dup_ext->VolatileFileHandle, - dup_ext->PersistentFileHandle); - if (!fp_in) { - pr_err("not found file handle in duplicate extent to file\n"); - ret = -ENOENT; - goto out; - } - - fp_out = ksmbd_lookup_fd_fast(work, id); - if (!fp_out) { - pr_err("not found fp\n"); - ret = -ENOENT; - goto dup_ext_out; - } - - src_off = le64_to_cpu(dup_ext->SourceFileOffset); - dst_off = le64_to_cpu(dup_ext->TargetFileOffset); - length = le64_to_cpu(dup_ext->ByteCount); - /* - * XXX: It is not clear if FSCTL_DUPLICATE_EXTENTS_TO_FILE - * should fall back to vfs_copy_file_range(). This could be - * beneficial when re-exporting nfs/smb mount, but note that - * this can result in partial copy that returns an error status. - * If/when FSCTL_DUPLICATE_EXTENTS_TO_FILE_EX is implemented, - * fall back to vfs_copy_file_range(), should be avoided when - * the flag DUPLICATE_EXTENTS_DATA_EX_SOURCE_ATOMIC is set. - */ - cloned = vfs_clone_file_range(fp_in->filp, src_off, - fp_out->filp, dst_off, length, 0); - if (cloned == -EXDEV || cloned == -EOPNOTSUPP) { - ret = -EOPNOTSUPP; - goto dup_ext_out; - } else if (cloned != length) { - cloned = vfs_copy_file_range(fp_in->filp, src_off, - fp_out->filp, dst_off, - length, 0); - if (cloned != length) { - if (cloned < 0) - ret = cloned; - else - ret = -EINVAL; - } - } - -dup_ext_out: - ksmbd_fd_put(work, fp_in); - ksmbd_fd_put(work, fp_out); - if (ret < 0) - goto out; - break; - } - default: - ksmbd_debug(SMB, "not implemented yet ioctl command 0x%x\n", - cnt_code); - ret = -EOPNOTSUPP; - goto out; - } - - rsp->CtlCode = cpu_to_le32(cnt_code); - rsp->InputCount = cpu_to_le32(0); - rsp->InputOffset = cpu_to_le32(112); - rsp->OutputOffset = cpu_to_le32(112); - rsp->OutputCount = cpu_to_le32(nbytes); - rsp->StructureSize = cpu_to_le16(49); - rsp->Reserved = cpu_to_le16(0); - rsp->Flags = cpu_to_le32(0); - rsp->Reserved2 = cpu_to_le32(0); - inc_rfc1001_len(work->response_buf, 48 + nbytes); - - return 0; - -out: - if (ret == -EACCES) - rsp->hdr.Status = STATUS_ACCESS_DENIED; - else if (ret == -ENOENT) - rsp->hdr.Status = STATUS_OBJECT_NAME_NOT_FOUND; - else if (ret == -EOPNOTSUPP) - rsp->hdr.Status = STATUS_NOT_SUPPORTED; - else if (ret == -ENOSPC) - rsp->hdr.Status = STATUS_BUFFER_TOO_SMALL; - else if (ret < 0 || rsp->hdr.Status == 0) - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - smb2_set_err_rsp(work); - return 0; -} - -/** - * smb20_oplock_break_ack() - handler for smb2.0 oplock break command - * @work: smb work containing oplock break command buffer - * - * Return: 0 - */ -static void smb20_oplock_break_ack(struct ksmbd_work *work) -{ - struct smb2_oplock_break *req = smb2_get_msg(work->request_buf); - struct smb2_oplock_break *rsp = smb2_get_msg(work->response_buf); - struct ksmbd_file *fp; - struct oplock_info *opinfo = NULL; - __le32 err = 0; - int ret = 0; - u64 volatile_id, persistent_id; - char req_oplevel = 0, rsp_oplevel = 0; - unsigned int oplock_change_type; - - volatile_id = req->VolatileFid; - persistent_id = req->PersistentFid; - req_oplevel = req->OplockLevel; - ksmbd_debug(OPLOCK, "v_id %llu, p_id %llu request oplock level %d\n", - volatile_id, persistent_id, req_oplevel); - - fp = ksmbd_lookup_fd_slow(work, volatile_id, persistent_id); - if (!fp) { - rsp->hdr.Status = STATUS_FILE_CLOSED; - smb2_set_err_rsp(work); - return; - } - - opinfo = opinfo_get(fp); - if (!opinfo) { - pr_err("unexpected null oplock_info\n"); - rsp->hdr.Status = STATUS_INVALID_OPLOCK_PROTOCOL; - smb2_set_err_rsp(work); - ksmbd_fd_put(work, fp); - return; - } - - if (opinfo->level == SMB2_OPLOCK_LEVEL_NONE) { - rsp->hdr.Status = STATUS_INVALID_OPLOCK_PROTOCOL; - goto err_out; - } - - if (opinfo->op_state == OPLOCK_STATE_NONE) { - ksmbd_debug(SMB, "unexpected oplock state 0x%x\n", opinfo->op_state); - rsp->hdr.Status = STATUS_UNSUCCESSFUL; - goto err_out; - } - - if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE || - opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) && - (req_oplevel != SMB2_OPLOCK_LEVEL_II && - req_oplevel != SMB2_OPLOCK_LEVEL_NONE)) { - err = STATUS_INVALID_OPLOCK_PROTOCOL; - oplock_change_type = OPLOCK_WRITE_TO_NONE; - } else if (opinfo->level == SMB2_OPLOCK_LEVEL_II && - req_oplevel != SMB2_OPLOCK_LEVEL_NONE) { - err = STATUS_INVALID_OPLOCK_PROTOCOL; - oplock_change_type = OPLOCK_READ_TO_NONE; - } else if (req_oplevel == SMB2_OPLOCK_LEVEL_II || - req_oplevel == SMB2_OPLOCK_LEVEL_NONE) { - err = STATUS_INVALID_DEVICE_STATE; - if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE || - opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) && - req_oplevel == SMB2_OPLOCK_LEVEL_II) { - oplock_change_type = OPLOCK_WRITE_TO_READ; - } else if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE || - opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) && - req_oplevel == SMB2_OPLOCK_LEVEL_NONE) { - oplock_change_type = OPLOCK_WRITE_TO_NONE; - } else if (opinfo->level == SMB2_OPLOCK_LEVEL_II && - req_oplevel == SMB2_OPLOCK_LEVEL_NONE) { - oplock_change_type = OPLOCK_READ_TO_NONE; - } else { - oplock_change_type = 0; - } - } else { - oplock_change_type = 0; - } - - switch (oplock_change_type) { - case OPLOCK_WRITE_TO_READ: - ret = opinfo_write_to_read(opinfo); - rsp_oplevel = SMB2_OPLOCK_LEVEL_II; - break; - case OPLOCK_WRITE_TO_NONE: - ret = opinfo_write_to_none(opinfo); - rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE; - break; - case OPLOCK_READ_TO_NONE: - ret = opinfo_read_to_none(opinfo); - rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE; - break; - default: - pr_err("unknown oplock change 0x%x -> 0x%x\n", - opinfo->level, rsp_oplevel); - } - - if (ret < 0) { - rsp->hdr.Status = err; - goto err_out; - } - - opinfo_put(opinfo); - ksmbd_fd_put(work, fp); - opinfo->op_state = OPLOCK_STATE_NONE; - wake_up_interruptible_all(&opinfo->oplock_q); - - rsp->StructureSize = cpu_to_le16(24); - rsp->OplockLevel = rsp_oplevel; - rsp->Reserved = 0; - rsp->Reserved2 = 0; - rsp->VolatileFid = volatile_id; - rsp->PersistentFid = persistent_id; - inc_rfc1001_len(work->response_buf, 24); - return; - -err_out: - opinfo->op_state = OPLOCK_STATE_NONE; - wake_up_interruptible_all(&opinfo->oplock_q); - - opinfo_put(opinfo); - ksmbd_fd_put(work, fp); - smb2_set_err_rsp(work); -} - -static int check_lease_state(struct lease *lease, __le32 req_state) -{ - if ((lease->new_state == - (SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE)) && - !(req_state & SMB2_LEASE_WRITE_CACHING_LE)) { - lease->new_state = req_state; - return 0; - } - - if (lease->new_state == req_state) - return 0; - - return 1; -} - -/** - * smb21_lease_break_ack() - handler for smb2.1 lease break command - * @work: smb work containing lease break command buffer - * - * Return: 0 - */ -static void smb21_lease_break_ack(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_lease_ack *req = smb2_get_msg(work->request_buf); - struct smb2_lease_ack *rsp = smb2_get_msg(work->response_buf); - struct oplock_info *opinfo; - __le32 err = 0; - int ret = 0; - unsigned int lease_change_type; - __le32 lease_state; - struct lease *lease; - - ksmbd_debug(OPLOCK, "smb21 lease break, lease state(0x%x)\n", - le32_to_cpu(req->LeaseState)); - opinfo = lookup_lease_in_table(conn, req->LeaseKey); - if (!opinfo) { - ksmbd_debug(OPLOCK, "file not opened\n"); - smb2_set_err_rsp(work); - rsp->hdr.Status = STATUS_UNSUCCESSFUL; - return; - } - lease = opinfo->o_lease; - - if (opinfo->op_state == OPLOCK_STATE_NONE) { - pr_err("unexpected lease break state 0x%x\n", - opinfo->op_state); - rsp->hdr.Status = STATUS_UNSUCCESSFUL; - goto err_out; - } - - if (check_lease_state(lease, req->LeaseState)) { - rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED; - ksmbd_debug(OPLOCK, - "req lease state: 0x%x, expected state: 0x%x\n", - req->LeaseState, lease->new_state); - goto err_out; - } - - if (!atomic_read(&opinfo->breaking_cnt)) { - rsp->hdr.Status = STATUS_UNSUCCESSFUL; - goto err_out; - } - - /* check for bad lease state */ - if (req->LeaseState & - (~(SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE))) { - err = STATUS_INVALID_OPLOCK_PROTOCOL; - if (lease->state & SMB2_LEASE_WRITE_CACHING_LE) - lease_change_type = OPLOCK_WRITE_TO_NONE; - else - lease_change_type = OPLOCK_READ_TO_NONE; - ksmbd_debug(OPLOCK, "handle bad lease state 0x%x -> 0x%x\n", - le32_to_cpu(lease->state), - le32_to_cpu(req->LeaseState)); - } else if (lease->state == SMB2_LEASE_READ_CACHING_LE && - req->LeaseState != SMB2_LEASE_NONE_LE) { - err = STATUS_INVALID_OPLOCK_PROTOCOL; - lease_change_type = OPLOCK_READ_TO_NONE; - ksmbd_debug(OPLOCK, "handle bad lease state 0x%x -> 0x%x\n", - le32_to_cpu(lease->state), - le32_to_cpu(req->LeaseState)); - } else { - /* valid lease state changes */ - err = STATUS_INVALID_DEVICE_STATE; - if (req->LeaseState == SMB2_LEASE_NONE_LE) { - if (lease->state & SMB2_LEASE_WRITE_CACHING_LE) - lease_change_type = OPLOCK_WRITE_TO_NONE; - else - lease_change_type = OPLOCK_READ_TO_NONE; - } else if (req->LeaseState & SMB2_LEASE_READ_CACHING_LE) { - if (lease->state & SMB2_LEASE_WRITE_CACHING_LE) - lease_change_type = OPLOCK_WRITE_TO_READ; - else - lease_change_type = OPLOCK_READ_HANDLE_TO_READ; - } else { - lease_change_type = 0; - } - } - - switch (lease_change_type) { - case OPLOCK_WRITE_TO_READ: - ret = opinfo_write_to_read(opinfo); - break; - case OPLOCK_READ_HANDLE_TO_READ: - ret = opinfo_read_handle_to_read(opinfo); - break; - case OPLOCK_WRITE_TO_NONE: - ret = opinfo_write_to_none(opinfo); - break; - case OPLOCK_READ_TO_NONE: - ret = opinfo_read_to_none(opinfo); - break; - default: - ksmbd_debug(OPLOCK, "unknown lease change 0x%x -> 0x%x\n", - le32_to_cpu(lease->state), - le32_to_cpu(req->LeaseState)); - } - - lease_state = lease->state; - opinfo->op_state = OPLOCK_STATE_NONE; - wake_up_interruptible_all(&opinfo->oplock_q); - atomic_dec(&opinfo->breaking_cnt); - wake_up_interruptible_all(&opinfo->oplock_brk); - opinfo_put(opinfo); - - if (ret < 0) { - rsp->hdr.Status = err; - goto err_out; - } - - rsp->StructureSize = cpu_to_le16(36); - rsp->Reserved = 0; - rsp->Flags = 0; - memcpy(rsp->LeaseKey, req->LeaseKey, 16); - rsp->LeaseState = lease_state; - rsp->LeaseDuration = 0; - inc_rfc1001_len(work->response_buf, 36); - return; - -err_out: - opinfo->op_state = OPLOCK_STATE_NONE; - wake_up_interruptible_all(&opinfo->oplock_q); - atomic_dec(&opinfo->breaking_cnt); - wake_up_interruptible_all(&opinfo->oplock_brk); - - opinfo_put(opinfo); - smb2_set_err_rsp(work); -} - -/** - * smb2_oplock_break() - dispatcher for smb2.0 and 2.1 oplock/lease break - * @work: smb work containing oplock/lease break command buffer - * - * Return: 0 - */ -int smb2_oplock_break(struct ksmbd_work *work) -{ - struct smb2_oplock_break *req = smb2_get_msg(work->request_buf); - struct smb2_oplock_break *rsp = smb2_get_msg(work->response_buf); - - switch (le16_to_cpu(req->StructureSize)) { - case OP_BREAK_STRUCT_SIZE_20: - smb20_oplock_break_ack(work); - break; - case OP_BREAK_STRUCT_SIZE_21: - smb21_lease_break_ack(work); - break; - default: - ksmbd_debug(OPLOCK, "invalid break cmd %d\n", - le16_to_cpu(req->StructureSize)); - rsp->hdr.Status = STATUS_INVALID_PARAMETER; - smb2_set_err_rsp(work); - } - - return 0; -} - -/** - * smb2_notify() - handler for smb2 notify request - * @work: smb work containing notify command buffer - * - * Return: 0 - */ -int smb2_notify(struct ksmbd_work *work) -{ - struct smb2_change_notify_req *req; - struct smb2_change_notify_rsp *rsp; - - WORK_BUFFERS(work, req, rsp); - - if (work->next_smb2_rcv_hdr_off && req->hdr.NextCommand) { - rsp->hdr.Status = STATUS_INTERNAL_ERROR; - smb2_set_err_rsp(work); - return 0; - } - - smb2_set_err_rsp(work); - rsp->hdr.Status = STATUS_NOT_IMPLEMENTED; - return 0; -} - -/** - * smb2_is_sign_req() - handler for checking packet signing status - * @work: smb work containing notify command buffer - * @command: SMB2 command id - * - * Return: true if packed is signed, false otherwise - */ -bool smb2_is_sign_req(struct ksmbd_work *work, unsigned int command) -{ - struct smb2_hdr *rcv_hdr2 = smb2_get_msg(work->request_buf); - - if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) && - command != SMB2_NEGOTIATE_HE && - command != SMB2_SESSION_SETUP_HE && - command != SMB2_OPLOCK_BREAK_HE) - return true; - - return false; -} - -/** - * smb2_check_sign_req() - handler for req packet sign processing - * @work: smb work containing notify command buffer - * - * Return: 1 on success, 0 otherwise - */ -int smb2_check_sign_req(struct ksmbd_work *work) -{ - struct smb2_hdr *hdr; - char signature_req[SMB2_SIGNATURE_SIZE]; - char signature[SMB2_HMACSHA256_SIZE]; - struct kvec iov[1]; - size_t len; - - hdr = smb2_get_msg(work->request_buf); - if (work->next_smb2_rcv_hdr_off) - hdr = ksmbd_req_buf_next(work); - - if (!hdr->NextCommand && !work->next_smb2_rcv_hdr_off) - len = get_rfc1002_len(work->request_buf); - else if (hdr->NextCommand) - len = le32_to_cpu(hdr->NextCommand); - else - len = get_rfc1002_len(work->request_buf) - - work->next_smb2_rcv_hdr_off; - - memcpy(signature_req, hdr->Signature, SMB2_SIGNATURE_SIZE); - memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE); - - iov[0].iov_base = (char *)&hdr->ProtocolId; - iov[0].iov_len = len; - - if (ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, 1, - signature)) - return 0; - - if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) { - pr_err("bad smb2 signature\n"); - return 0; - } - - return 1; -} - -/** - * smb2_set_sign_rsp() - handler for rsp packet sign processing - * @work: smb work containing notify command buffer - * - */ -void smb2_set_sign_rsp(struct ksmbd_work *work) -{ - struct smb2_hdr *hdr; - struct smb2_hdr *req_hdr; - char signature[SMB2_HMACSHA256_SIZE]; - struct kvec iov[2]; - size_t len; - int n_vec = 1; - - hdr = smb2_get_msg(work->response_buf); - if (work->next_smb2_rsp_hdr_off) - hdr = ksmbd_resp_buf_next(work); - - req_hdr = ksmbd_req_buf_next(work); - - if (!work->next_smb2_rsp_hdr_off) { - len = get_rfc1002_len(work->response_buf); - if (req_hdr->NextCommand) - len = ALIGN(len, 8); - } else { - len = get_rfc1002_len(work->response_buf) - - work->next_smb2_rsp_hdr_off; - len = ALIGN(len, 8); - } - - if (req_hdr->NextCommand) - hdr->NextCommand = cpu_to_le32(len); - - hdr->Flags |= SMB2_FLAGS_SIGNED; - memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE); - - iov[0].iov_base = (char *)&hdr->ProtocolId; - iov[0].iov_len = len; - - if (work->aux_payload_sz) { - iov[0].iov_len -= work->aux_payload_sz; - - iov[1].iov_base = work->aux_payload_buf; - iov[1].iov_len = work->aux_payload_sz; - n_vec++; - } - - if (!ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, n_vec, - signature)) - memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE); -} - -/** - * smb3_check_sign_req() - handler for req packet sign processing - * @work: smb work containing notify command buffer - * - * Return: 1 on success, 0 otherwise - */ -int smb3_check_sign_req(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - char *signing_key; - struct smb2_hdr *hdr; - struct channel *chann; - char signature_req[SMB2_SIGNATURE_SIZE]; - char signature[SMB2_CMACAES_SIZE]; - struct kvec iov[1]; - size_t len; - - hdr = smb2_get_msg(work->request_buf); - if (work->next_smb2_rcv_hdr_off) - hdr = ksmbd_req_buf_next(work); - - if (!hdr->NextCommand && !work->next_smb2_rcv_hdr_off) - len = get_rfc1002_len(work->request_buf); - else if (hdr->NextCommand) - len = le32_to_cpu(hdr->NextCommand); - else - len = get_rfc1002_len(work->request_buf) - - work->next_smb2_rcv_hdr_off; - - if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { - signing_key = work->sess->smb3signingkey; - } else { - chann = lookup_chann_list(work->sess, conn); - if (!chann) { - return 0; - } - signing_key = chann->smb3signingkey; - } - - if (!signing_key) { - pr_err("SMB3 signing key is not generated\n"); - return 0; - } - - memcpy(signature_req, hdr->Signature, SMB2_SIGNATURE_SIZE); - memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE); - iov[0].iov_base = (char *)&hdr->ProtocolId; - iov[0].iov_len = len; - - if (ksmbd_sign_smb3_pdu(conn, signing_key, iov, 1, signature)) - return 0; - - if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) { - pr_err("bad smb2 signature\n"); - return 0; - } - - return 1; -} - -/** - * smb3_set_sign_rsp() - handler for rsp packet sign processing - * @work: smb work containing notify command buffer - * - */ -void smb3_set_sign_rsp(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct smb2_hdr *req_hdr, *hdr; - struct channel *chann; - char signature[SMB2_CMACAES_SIZE]; - struct kvec iov[2]; - int n_vec = 1; - size_t len; - char *signing_key; - - hdr = smb2_get_msg(work->response_buf); - if (work->next_smb2_rsp_hdr_off) - hdr = ksmbd_resp_buf_next(work); - - req_hdr = ksmbd_req_buf_next(work); - - if (!work->next_smb2_rsp_hdr_off) { - len = get_rfc1002_len(work->response_buf); - if (req_hdr->NextCommand) - len = ALIGN(len, 8); - } else { - len = get_rfc1002_len(work->response_buf) - - work->next_smb2_rsp_hdr_off; - len = ALIGN(len, 8); - } - - if (conn->binding == false && - le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { - signing_key = work->sess->smb3signingkey; - } else { - chann = lookup_chann_list(work->sess, work->conn); - if (!chann) { - return; - } - signing_key = chann->smb3signingkey; - } - - if (!signing_key) - return; - - if (req_hdr->NextCommand) - hdr->NextCommand = cpu_to_le32(len); - - hdr->Flags |= SMB2_FLAGS_SIGNED; - memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE); - iov[0].iov_base = (char *)&hdr->ProtocolId; - iov[0].iov_len = len; - if (work->aux_payload_sz) { - iov[0].iov_len -= work->aux_payload_sz; - iov[1].iov_base = work->aux_payload_buf; - iov[1].iov_len = work->aux_payload_sz; - n_vec++; - } - - if (!ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec, signature)) - memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE); -} - -/** - * smb3_preauth_hash_rsp() - handler for computing preauth hash on response - * @work: smb work containing response buffer - * - */ -void smb3_preauth_hash_rsp(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct ksmbd_session *sess = work->sess; - struct smb2_hdr *req, *rsp; - - if (conn->dialect != SMB311_PROT_ID) - return; - - WORK_BUFFERS(work, req, rsp); - - if (le16_to_cpu(req->Command) == SMB2_NEGOTIATE_HE && - conn->preauth_info) - ksmbd_gen_preauth_integrity_hash(conn, work->response_buf, - conn->preauth_info->Preauth_HashValue); - - if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && sess) { - __u8 *hash_value; - - if (conn->binding) { - struct preauth_session *preauth_sess; - - preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id); - if (!preauth_sess) - return; - hash_value = preauth_sess->Preauth_HashValue; - } else { - hash_value = sess->Preauth_HashValue; - if (!hash_value) - return; - } - ksmbd_gen_preauth_integrity_hash(conn, work->response_buf, - hash_value); - } -} - -static void fill_transform_hdr(void *tr_buf, char *old_buf, __le16 cipher_type) -{ - struct smb2_transform_hdr *tr_hdr = tr_buf + 4; - struct smb2_hdr *hdr = smb2_get_msg(old_buf); - unsigned int orig_len = get_rfc1002_len(old_buf); - - /* tr_buf must be cleared by the caller */ - tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM; - tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len); - tr_hdr->Flags = cpu_to_le16(TRANSFORM_FLAG_ENCRYPTED); - if (cipher_type == SMB2_ENCRYPTION_AES128_GCM || - cipher_type == SMB2_ENCRYPTION_AES256_GCM) - get_random_bytes(&tr_hdr->Nonce, SMB3_AES_GCM_NONCE); - else - get_random_bytes(&tr_hdr->Nonce, SMB3_AES_CCM_NONCE); - memcpy(&tr_hdr->SessionId, &hdr->SessionId, 8); - inc_rfc1001_len(tr_buf, sizeof(struct smb2_transform_hdr)); - inc_rfc1001_len(tr_buf, orig_len); -} - -int smb3_encrypt_resp(struct ksmbd_work *work) -{ - char *buf = work->response_buf; - struct kvec iov[3]; - int rc = -ENOMEM; - int buf_size = 0, rq_nvec = 2 + (work->aux_payload_sz ? 1 : 0); - - if (ARRAY_SIZE(iov) < rq_nvec) - return -ENOMEM; - - work->tr_buf = kzalloc(sizeof(struct smb2_transform_hdr) + 4, GFP_KERNEL); - if (!work->tr_buf) - return rc; - - /* fill transform header */ - fill_transform_hdr(work->tr_buf, buf, work->conn->cipher_type); - - iov[0].iov_base = work->tr_buf; - iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4; - buf_size += iov[0].iov_len - 4; - - iov[1].iov_base = buf + 4; - iov[1].iov_len = get_rfc1002_len(buf); - if (work->aux_payload_sz) { - iov[1].iov_len = work->resp_hdr_sz - 4; - - iov[2].iov_base = work->aux_payload_buf; - iov[2].iov_len = work->aux_payload_sz; - buf_size += iov[2].iov_len; - } - buf_size += iov[1].iov_len; - work->resp_hdr_sz = iov[1].iov_len; - - rc = ksmbd_crypt_message(work, iov, rq_nvec, 1); - if (rc) - return rc; - - memmove(buf, iov[1].iov_base, iov[1].iov_len); - *(__be32 *)work->tr_buf = cpu_to_be32(buf_size); - - return rc; -} - -bool smb3_is_transform_hdr(void *buf) -{ - struct smb2_transform_hdr *trhdr = smb2_get_msg(buf); - - return trhdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM; -} - -int smb3_decrypt_req(struct ksmbd_work *work) -{ - struct ksmbd_session *sess; - char *buf = work->request_buf; - unsigned int pdu_length = get_rfc1002_len(buf); - struct kvec iov[2]; - int buf_data_size = pdu_length - sizeof(struct smb2_transform_hdr); - struct smb2_transform_hdr *tr_hdr = smb2_get_msg(buf); - int rc = 0; - - if (buf_data_size < sizeof(struct smb2_hdr)) { - pr_err("Transform message is too small (%u)\n", - pdu_length); - return -ECONNABORTED; - } - - if (buf_data_size < le32_to_cpu(tr_hdr->OriginalMessageSize)) { - pr_err("Transform message is broken\n"); - return -ECONNABORTED; - } - - sess = ksmbd_session_lookup_all(work->conn, le64_to_cpu(tr_hdr->SessionId)); - if (!sess) { - pr_err("invalid session id(%llx) in transform header\n", - le64_to_cpu(tr_hdr->SessionId)); - return -ECONNABORTED; - } - - iov[0].iov_base = buf; - iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4; - iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr) + 4; - iov[1].iov_len = buf_data_size; - rc = ksmbd_crypt_message(work, iov, 2, 0); - if (rc) - return rc; - - memmove(buf + 4, iov[1].iov_base, buf_data_size); - *(__be32 *)buf = cpu_to_be32(buf_data_size); - - return rc; -} - -bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - struct ksmbd_session *sess = work->sess; - struct smb2_hdr *rsp = smb2_get_msg(work->response_buf); - - if (conn->dialect < SMB30_PROT_ID) - return false; - - if (work->next_smb2_rcv_hdr_off) - rsp = ksmbd_resp_buf_next(work); - - if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && - sess->user && !user_guest(sess->user) && - rsp->Status == STATUS_SUCCESS) - return true; - return false; -} diff --git a/fs/ksmbd/smb2pdu.h b/fs/ksmbd/smb2pdu.h deleted file mode 100644 index dd10f8031606..000000000000 --- a/fs/ksmbd/smb2pdu.h +++ /dev/null @@ -1,536 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef _SMB2PDU_H -#define _SMB2PDU_H - -#include "ntlmssp.h" -#include "smbacl.h" - -/*Create Action Flags*/ -#define FILE_SUPERSEDED 0x00000000 -#define FILE_OPENED 0x00000001 -#define FILE_CREATED 0x00000002 -#define FILE_OVERWRITTEN 0x00000003 - -/* SMB2 Max Credits */ -#define SMB2_MAX_CREDITS 8192 - -/* BB FIXME - analyze following length BB */ -#define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */ - -#define SMB21_DEFAULT_IOSIZE (1024 * 1024) -#define SMB3_DEFAULT_TRANS_SIZE (1024 * 1024) -#define SMB3_MIN_IOSIZE (64 * 1024) -#define SMB3_MAX_IOSIZE (8 * 1024 * 1024) -#define SMB3_MAX_MSGSIZE (4 * 4096) - -/* - * Definitions for SMB2 Protocol Data Units (network frames) - * - * See MS-SMB2.PDF specification for protocol details. - * The Naming convention is the lower case version of the SMB2 - * command code name for the struct. Note that structures must be packed. - * - */ - -struct preauth_integrity_info { - /* PreAuth integrity Hash ID */ - __le16 Preauth_HashId; - /* PreAuth integrity Hash Value */ - __u8 Preauth_HashValue[SMB2_PREAUTH_HASH_SIZE]; -}; - -/* offset is sizeof smb2_negotiate_rsp but rounded up to 8 bytes. */ -#ifdef CONFIG_SMB_SERVER_KERBEROS5 -/* sizeof(struct smb2_negotiate_rsp) = - * header(64) + response(64) + GSS_LENGTH(96) + GSS_PADDING(0) - */ -#define OFFSET_OF_NEG_CONTEXT 0xe0 -#else -/* sizeof(struct smb2_negotiate_rsp) = - * header(64) + response(64) + GSS_LENGTH(74) + GSS_PADDING(6) - */ -#define OFFSET_OF_NEG_CONTEXT 0xd0 -#endif - -#define SMB2_SESSION_EXPIRED (0) -#define SMB2_SESSION_IN_PROGRESS BIT(0) -#define SMB2_SESSION_VALID BIT(1) - -#define SMB2_SESSION_TIMEOUT (10 * HZ) - -struct create_durable_req_v2 { - struct create_context ccontext; - __u8 Name[8]; - __le32 Timeout; - __le32 Flags; - __u8 Reserved[8]; - __u8 CreateGuid[16]; -} __packed; - -struct create_durable_reconn_req { - struct create_context ccontext; - __u8 Name[8]; - union { - __u8 Reserved[16]; - struct { - __u64 PersistentFileId; - __u64 VolatileFileId; - } Fid; - } Data; -} __packed; - -struct create_durable_reconn_v2_req { - struct create_context ccontext; - __u8 Name[8]; - struct { - __u64 PersistentFileId; - __u64 VolatileFileId; - } Fid; - __u8 CreateGuid[16]; - __le32 Flags; -} __packed; - -struct create_app_inst_id { - struct create_context ccontext; - __u8 Name[8]; - __u8 Reserved[8]; - __u8 AppInstanceId[16]; -} __packed; - -struct create_app_inst_id_vers { - struct create_context ccontext; - __u8 Name[8]; - __u8 Reserved[2]; - __u8 Padding[4]; - __le64 AppInstanceVersionHigh; - __le64 AppInstanceVersionLow; -} __packed; - -struct create_mxac_req { - struct create_context ccontext; - __u8 Name[8]; - __le64 Timestamp; -} __packed; - -struct create_alloc_size_req { - struct create_context ccontext; - __u8 Name[8]; - __le64 AllocationSize; -} __packed; - -struct create_durable_rsp { - struct create_context ccontext; - __u8 Name[8]; - union { - __u8 Reserved[8]; - __u64 data; - } Data; -} __packed; - -struct create_durable_v2_rsp { - struct create_context ccontext; - __u8 Name[8]; - __le32 Timeout; - __le32 Flags; -} __packed; - -struct create_mxac_rsp { - struct create_context ccontext; - __u8 Name[8]; - __le32 QueryStatus; - __le32 MaximalAccess; -} __packed; - -struct create_disk_id_rsp { - struct create_context ccontext; - __u8 Name[8]; - __le64 DiskFileId; - __le64 VolumeId; - __u8 Reserved[16]; -} __packed; - -/* equivalent of the contents of SMB3.1.1 POSIX open context response */ -struct create_posix_rsp { - struct create_context ccontext; - __u8 Name[16]; - __le32 nlink; - __le32 reparse_tag; - __le32 mode; - /* SidBuffer contain two sids(Domain sid(28), UNIX group sid(16)) */ - u8 SidBuffer[44]; -} __packed; - -struct smb2_buffer_desc_v1 { - __le64 offset; - __le32 token; - __le32 length; -} __packed; - -#define SMB2_0_IOCTL_IS_FSCTL 0x00000001 - -struct smb_sockaddr_in { - __be16 Port; - __be32 IPv4address; - __u8 Reserved[8]; -} __packed; - -struct smb_sockaddr_in6 { - __be16 Port; - __be32 FlowInfo; - __u8 IPv6address[16]; - __be32 ScopeId; -} __packed; - -#define INTERNETWORK 0x0002 -#define INTERNETWORKV6 0x0017 - -struct sockaddr_storage_rsp { - __le16 Family; - union { - struct smb_sockaddr_in addr4; - struct smb_sockaddr_in6 addr6; - }; -} __packed; - -#define RSS_CAPABLE 0x00000001 -#define RDMA_CAPABLE 0x00000002 - -struct network_interface_info_ioctl_rsp { - __le32 Next; /* next interface. zero if this is last one */ - __le32 IfIndex; - __le32 Capability; /* RSS or RDMA Capable */ - __le32 Reserved; - __le64 LinkSpeed; - char SockAddr_Storage[128]; -} __packed; - -struct file_object_buf_type1_ioctl_rsp { - __u8 ObjectId[16]; - __u8 BirthVolumeId[16]; - __u8 BirthObjectId[16]; - __u8 DomainId[16]; -} __packed; - -struct resume_key_ioctl_rsp { - __u64 ResumeKey[3]; - __le32 ContextLength; - __u8 Context[4]; /* ignored, Windows sets to 4 bytes of zero */ -} __packed; - -struct copychunk_ioctl_req { - __le64 ResumeKey[3]; - __le32 ChunkCount; - __le32 Reserved; - __u8 Chunks[1]; /* array of srv_copychunk */ -} __packed; - -struct srv_copychunk { - __le64 SourceOffset; - __le64 TargetOffset; - __le32 Length; - __le32 Reserved; -} __packed; - -struct copychunk_ioctl_rsp { - __le32 ChunksWritten; - __le32 ChunkBytesWritten; - __le32 TotalBytesWritten; -} __packed; - -struct file_sparse { - __u8 SetSparse; -} __packed; - -/* FILE Info response size */ -#define FILE_DIRECTORY_INFORMATION_SIZE 1 -#define FILE_FULL_DIRECTORY_INFORMATION_SIZE 2 -#define FILE_BOTH_DIRECTORY_INFORMATION_SIZE 3 -#define FILE_BASIC_INFORMATION_SIZE 40 -#define FILE_STANDARD_INFORMATION_SIZE 24 -#define FILE_INTERNAL_INFORMATION_SIZE 8 -#define FILE_EA_INFORMATION_SIZE 4 -#define FILE_ACCESS_INFORMATION_SIZE 4 -#define FILE_NAME_INFORMATION_SIZE 9 -#define FILE_RENAME_INFORMATION_SIZE 10 -#define FILE_LINK_INFORMATION_SIZE 11 -#define FILE_NAMES_INFORMATION_SIZE 12 -#define FILE_DISPOSITION_INFORMATION_SIZE 13 -#define FILE_POSITION_INFORMATION_SIZE 14 -#define FILE_FULL_EA_INFORMATION_SIZE 15 -#define FILE_MODE_INFORMATION_SIZE 4 -#define FILE_ALIGNMENT_INFORMATION_SIZE 4 -#define FILE_ALL_INFORMATION_SIZE 104 -#define FILE_ALLOCATION_INFORMATION_SIZE 19 -#define FILE_END_OF_FILE_INFORMATION_SIZE 20 -#define FILE_ALTERNATE_NAME_INFORMATION_SIZE 8 -#define FILE_STREAM_INFORMATION_SIZE 32 -#define FILE_PIPE_INFORMATION_SIZE 23 -#define FILE_PIPE_LOCAL_INFORMATION_SIZE 24 -#define FILE_PIPE_REMOTE_INFORMATION_SIZE 25 -#define FILE_MAILSLOT_QUERY_INFORMATION_SIZE 26 -#define FILE_MAILSLOT_SET_INFORMATION_SIZE 27 -#define FILE_COMPRESSION_INFORMATION_SIZE 16 -#define FILE_OBJECT_ID_INFORMATION_SIZE 29 -/* Number 30 not defined in documents */ -#define FILE_MOVE_CLUSTER_INFORMATION_SIZE 31 -#define FILE_QUOTA_INFORMATION_SIZE 32 -#define FILE_REPARSE_POINT_INFORMATION_SIZE 33 -#define FILE_NETWORK_OPEN_INFORMATION_SIZE 56 -#define FILE_ATTRIBUTE_TAG_INFORMATION_SIZE 8 - -/* FS Info response size */ -#define FS_DEVICE_INFORMATION_SIZE 8 -#define FS_ATTRIBUTE_INFORMATION_SIZE 16 -#define FS_VOLUME_INFORMATION_SIZE 24 -#define FS_SIZE_INFORMATION_SIZE 24 -#define FS_FULL_SIZE_INFORMATION_SIZE 32 -#define FS_SECTOR_SIZE_INFORMATION_SIZE 28 -#define FS_OBJECT_ID_INFORMATION_SIZE 64 -#define FS_CONTROL_INFORMATION_SIZE 48 -#define FS_POSIX_INFORMATION_SIZE 56 - -/* FS_ATTRIBUTE_File_System_Name */ -#define FS_TYPE_SUPPORT_SIZE 44 -struct fs_type_info { - char *fs_name; - long magic_number; -} __packed; - -/* - * PDU query infolevel structure definitions - * BB consider moving to a different header - */ - -struct smb2_file_access_info { - __le32 AccessFlags; -} __packed; - -struct smb2_file_alignment_info { - __le32 AlignmentRequirement; -} __packed; - -struct smb2_file_basic_info { /* data block encoding of response to level 18 */ - __le64 CreationTime; /* Beginning of FILE_BASIC_INFO equivalent */ - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le32 Attributes; - __u32 Pad1; /* End of FILE_BASIC_INFO_INFO equivalent */ -} __packed; - -struct smb2_file_alt_name_info { - __le32 FileNameLength; - char FileName[]; -} __packed; - -struct smb2_file_stream_info { - __le32 NextEntryOffset; - __le32 StreamNameLength; - __le64 StreamSize; - __le64 StreamAllocationSize; - char StreamName[]; -} __packed; - -struct smb2_file_ntwrk_info { - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 AllocationSize; - __le64 EndOfFile; - __le32 Attributes; - __le32 Reserved; -} __packed; - -struct smb2_file_standard_info { - __le64 AllocationSize; - __le64 EndOfFile; - __le32 NumberOfLinks; /* hard links */ - __u8 DeletePending; - __u8 Directory; - __le16 Reserved; -} __packed; /* level 18 Query */ - -struct smb2_file_ea_info { - __le32 EASize; -} __packed; - -struct smb2_file_alloc_info { - __le64 AllocationSize; -} __packed; - -struct smb2_file_disposition_info { - __u8 DeletePending; -} __packed; - -struct smb2_file_pos_info { - __le64 CurrentByteOffset; -} __packed; - -#define FILE_MODE_INFO_MASK cpu_to_le32(0x0000100e) - -struct smb2_file_mode_info { - __le32 Mode; -} __packed; - -#define COMPRESSION_FORMAT_NONE 0x0000 -#define COMPRESSION_FORMAT_LZNT1 0x0002 - -struct smb2_file_comp_info { - __le64 CompressedFileSize; - __le16 CompressionFormat; - __u8 CompressionUnitShift; - __u8 ChunkShift; - __u8 ClusterShift; - __u8 Reserved[3]; -} __packed; - -struct smb2_file_attr_tag_info { - __le32 FileAttributes; - __le32 ReparseTag; -} __packed; - -#define SL_RESTART_SCAN 0x00000001 -#define SL_RETURN_SINGLE_ENTRY 0x00000002 -#define SL_INDEX_SPECIFIED 0x00000004 - -struct smb2_ea_info_req { - __le32 NextEntryOffset; - __u8 EaNameLength; - char name[1]; -} __packed; /* level 15 Query */ - -struct smb2_ea_info { - __le32 NextEntryOffset; - __u8 Flags; - __u8 EaNameLength; - __le16 EaValueLength; - char name[1]; - /* optionally followed by value */ -} __packed; /* level 15 Query */ - -struct create_ea_buf_req { - struct create_context ccontext; - __u8 Name[8]; - struct smb2_ea_info ea; -} __packed; - -struct create_sd_buf_req { - struct create_context ccontext; - __u8 Name[8]; - struct smb_ntsd ntsd; -} __packed; - -struct smb2_posix_info { - __le32 NextEntryOffset; - __u32 Ignored; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 DosAttributes; - __le64 Inode; - __le32 DeviceId; - __le32 Zero; - /* beginning of POSIX Create Context Response */ - __le32 HardLinks; - __le32 ReparseTag; - __le32 Mode; - /* SidBuffer contain two sids (UNIX user sid(16), UNIX group sid(16)) */ - u8 SidBuffer[32]; - __le32 name_len; - u8 name[1]; - /* - * var sized owner SID - * var sized group SID - * le32 filenamelength - * u8 filename[] - */ -} __packed; - -/* functions */ -void init_smb2_1_server(struct ksmbd_conn *conn); -void init_smb3_0_server(struct ksmbd_conn *conn); -void init_smb3_02_server(struct ksmbd_conn *conn); -int init_smb3_11_server(struct ksmbd_conn *conn); - -void init_smb2_max_read_size(unsigned int sz); -void init_smb2_max_write_size(unsigned int sz); -void init_smb2_max_trans_size(unsigned int sz); -void init_smb2_max_credits(unsigned int sz); - -bool is_smb2_neg_cmd(struct ksmbd_work *work); -bool is_smb2_rsp(struct ksmbd_work *work); - -u16 get_smb2_cmd_val(struct ksmbd_work *work); -void set_smb2_rsp_status(struct ksmbd_work *work, __le32 err); -int init_smb2_rsp_hdr(struct ksmbd_work *work); -int smb2_allocate_rsp_buf(struct ksmbd_work *work); -bool is_chained_smb2_message(struct ksmbd_work *work); -int init_smb2_neg_rsp(struct ksmbd_work *work); -void smb2_set_err_rsp(struct ksmbd_work *work); -int smb2_check_user_session(struct ksmbd_work *work); -int smb2_get_ksmbd_tcon(struct ksmbd_work *work); -bool smb2_is_sign_req(struct ksmbd_work *work, unsigned int command); -int smb2_check_sign_req(struct ksmbd_work *work); -void smb2_set_sign_rsp(struct ksmbd_work *work); -int smb3_check_sign_req(struct ksmbd_work *work); -void smb3_set_sign_rsp(struct ksmbd_work *work); -int find_matching_smb2_dialect(int start_index, __le16 *cli_dialects, - __le16 dialects_count); -struct file_lock *smb_flock_init(struct file *f); -int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), - void **arg); -void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status); -struct channel *lookup_chann_list(struct ksmbd_session *sess, - struct ksmbd_conn *conn); -void smb3_preauth_hash_rsp(struct ksmbd_work *work); -bool smb3_is_transform_hdr(void *buf); -int smb3_decrypt_req(struct ksmbd_work *work); -int smb3_encrypt_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); -bool smb3_encryption_negotiated(struct ksmbd_conn *conn); - -/* smb2 misc functions */ -int ksmbd_smb2_check_message(struct ksmbd_work *work); - -/* smb2 command handlers */ -int smb2_handle_negotiate(struct ksmbd_work *work); -int smb2_negotiate_request(struct ksmbd_work *work); -int smb2_sess_setup(struct ksmbd_work *work); -int smb2_tree_connect(struct ksmbd_work *work); -int smb2_tree_disconnect(struct ksmbd_work *work); -int smb2_session_logoff(struct ksmbd_work *work); -int smb2_open(struct ksmbd_work *work); -int smb2_query_info(struct ksmbd_work *work); -int smb2_query_dir(struct ksmbd_work *work); -int smb2_close(struct ksmbd_work *work); -int smb2_echo(struct ksmbd_work *work); -int smb2_set_info(struct ksmbd_work *work); -int smb2_read(struct ksmbd_work *work); -int smb2_write(struct ksmbd_work *work); -int smb2_flush(struct ksmbd_work *work); -int smb2_cancel(struct ksmbd_work *work); -int smb2_lock(struct ksmbd_work *work); -int smb2_ioctl(struct ksmbd_work *work); -int smb2_oplock_break(struct ksmbd_work *work); -int smb2_notify(struct ksmbd_work *ksmbd_work); - -/* - * Get the body of the smb2 message excluding the 4 byte rfc1002 headers - * from request/response buffer. - */ -static inline void *smb2_get_msg(void *buf) -{ - return buf + 4; -} - -#endif /* _SMB2PDU_H */ diff --git a/fs/ksmbd/smb_common.c b/fs/ksmbd/smb_common.c deleted file mode 100644 index 05d7f3e910bf..000000000000 --- a/fs/ksmbd/smb_common.c +++ /dev/null @@ -1,797 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - * Copyright (C) 2018 Namjae Jeon <linkinjeon@kernel.org> - */ - -#include <linux/user_namespace.h> - -#include "smb_common.h" -#include "server.h" -#include "misc.h" -#include "smbstatus.h" -#include "connection.h" -#include "ksmbd_work.h" -#include "mgmt/user_session.h" -#include "mgmt/user_config.h" -#include "mgmt/tree_connect.h" -#include "mgmt/share_config.h" - -/*for shortname implementation */ -static const char basechars[43] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%"; -#define MANGLE_BASE (sizeof(basechars) / sizeof(char) - 1) -#define MAGIC_CHAR '~' -#define PERIOD '.' -#define mangle(V) ((char)(basechars[(V) % MANGLE_BASE])) - -struct smb_protocol { - int index; - char *name; - char *prot; - __u16 prot_id; -}; - -static struct smb_protocol smb1_protos[] = { - { - SMB21_PROT, - "\2SMB 2.1", - "SMB2_10", - SMB21_PROT_ID - }, - { - SMB2X_PROT, - "\2SMB 2.???", - "SMB2_22", - SMB2X_PROT_ID - }, -}; - -static struct smb_protocol smb2_protos[] = { - { - SMB21_PROT, - "\2SMB 2.1", - "SMB2_10", - SMB21_PROT_ID - }, - { - SMB30_PROT, - "\2SMB 3.0", - "SMB3_00", - SMB30_PROT_ID - }, - { - SMB302_PROT, - "\2SMB 3.02", - "SMB3_02", - SMB302_PROT_ID - }, - { - SMB311_PROT, - "\2SMB 3.1.1", - "SMB3_11", - SMB311_PROT_ID - }, -}; - -unsigned int ksmbd_server_side_copy_max_chunk_count(void) -{ - return 256; -} - -unsigned int ksmbd_server_side_copy_max_chunk_size(void) -{ - return (2U << 30) - 1; -} - -unsigned int ksmbd_server_side_copy_max_total_size(void) -{ - return (2U << 30) - 1; -} - -inline int ksmbd_min_protocol(void) -{ - return SMB21_PROT; -} - -inline int ksmbd_max_protocol(void) -{ - return SMB311_PROT; -} - -int ksmbd_lookup_protocol_idx(char *str) -{ - int offt = ARRAY_SIZE(smb1_protos) - 1; - int len = strlen(str); - - while (offt >= 0) { - if (!strncmp(str, smb1_protos[offt].prot, len)) { - ksmbd_debug(SMB, "selected %s dialect idx = %d\n", - smb1_protos[offt].prot, offt); - return smb1_protos[offt].index; - } - offt--; - } - - offt = ARRAY_SIZE(smb2_protos) - 1; - while (offt >= 0) { - if (!strncmp(str, smb2_protos[offt].prot, len)) { - ksmbd_debug(SMB, "selected %s dialect idx = %d\n", - smb2_protos[offt].prot, offt); - return smb2_protos[offt].index; - } - offt--; - } - return -1; -} - -/** - * ksmbd_verify_smb_message() - check for valid smb2 request header - * @work: smb work - * - * check for valid smb signature and packet direction(request/response) - * - * Return: 0 on success, otherwise -EINVAL - */ -int ksmbd_verify_smb_message(struct ksmbd_work *work) -{ - struct smb2_hdr *smb2_hdr = ksmbd_req_buf_next(work); - struct smb_hdr *hdr; - - if (smb2_hdr->ProtocolId == SMB2_PROTO_NUMBER) - return ksmbd_smb2_check_message(work); - - hdr = work->request_buf; - if (*(__le32 *)hdr->Protocol == SMB1_PROTO_NUMBER && - hdr->Command == SMB_COM_NEGOTIATE) { - work->conn->outstanding_credits++; - return 0; - } - - return -EINVAL; -} - -/** - * ksmbd_smb_request() - check for valid smb request type - * @conn: connection instance - * - * Return: true on success, otherwise false - */ -bool ksmbd_smb_request(struct ksmbd_conn *conn) -{ - __le32 *proto = (__le32 *)smb2_get_msg(conn->request_buf); - - if (*proto == SMB2_COMPRESSION_TRANSFORM_ID) { - pr_err_ratelimited("smb2 compression not support yet"); - return false; - } - - if (*proto != SMB1_PROTO_NUMBER && - *proto != SMB2_PROTO_NUMBER && - *proto != SMB2_TRANSFORM_PROTO_NUM) - return false; - - return true; -} - -static bool supported_protocol(int idx) -{ - if (idx == SMB2X_PROT && - (server_conf.min_protocol >= SMB21_PROT || - server_conf.max_protocol <= SMB311_PROT)) - return true; - - return (server_conf.min_protocol <= idx && - idx <= server_conf.max_protocol); -} - -static char *next_dialect(char *dialect, int *next_off, int bcount) -{ - dialect = dialect + *next_off; - *next_off = strnlen(dialect, bcount); - if (dialect[*next_off] != '\0') - return NULL; - return dialect; -} - -static int ksmbd_lookup_dialect_by_name(char *cli_dialects, __le16 byte_count) -{ - int i, seq_num, bcount, next; - char *dialect; - - for (i = ARRAY_SIZE(smb1_protos) - 1; i >= 0; i--) { - seq_num = 0; - next = 0; - dialect = cli_dialects; - bcount = le16_to_cpu(byte_count); - do { - dialect = next_dialect(dialect, &next, bcount); - if (!dialect) - break; - ksmbd_debug(SMB, "client requested dialect %s\n", - dialect); - if (!strcmp(dialect, smb1_protos[i].name)) { - if (supported_protocol(smb1_protos[i].index)) { - ksmbd_debug(SMB, - "selected %s dialect\n", - smb1_protos[i].name); - if (smb1_protos[i].index == SMB1_PROT) - return seq_num; - return smb1_protos[i].prot_id; - } - } - seq_num++; - bcount -= (++next); - } while (bcount > 0); - } - - return BAD_PROT_ID; -} - -int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count) -{ - int i; - int count; - - for (i = ARRAY_SIZE(smb2_protos) - 1; i >= 0; i--) { - count = le16_to_cpu(dialects_count); - while (--count >= 0) { - ksmbd_debug(SMB, "client requested dialect 0x%x\n", - le16_to_cpu(cli_dialects[count])); - if (le16_to_cpu(cli_dialects[count]) != - smb2_protos[i].prot_id) - continue; - - if (supported_protocol(smb2_protos[i].index)) { - ksmbd_debug(SMB, "selected %s dialect\n", - smb2_protos[i].name); - return smb2_protos[i].prot_id; - } - } - } - - return BAD_PROT_ID; -} - -static int ksmbd_negotiate_smb_dialect(void *buf) -{ - int smb_buf_length = get_rfc1002_len(buf); - __le32 proto = ((struct smb2_hdr *)smb2_get_msg(buf))->ProtocolId; - - if (proto == SMB2_PROTO_NUMBER) { - struct smb2_negotiate_req *req; - int smb2_neg_size = - offsetof(struct smb2_negotiate_req, Dialects); - - req = (struct smb2_negotiate_req *)smb2_get_msg(buf); - if (smb2_neg_size > smb_buf_length) - goto err_out; - - if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) > - smb_buf_length) - goto err_out; - - return ksmbd_lookup_dialect_by_id(req->Dialects, - req->DialectCount); - } - - proto = *(__le32 *)((struct smb_hdr *)buf)->Protocol; - if (proto == SMB1_PROTO_NUMBER) { - struct smb_negotiate_req *req; - - req = (struct smb_negotiate_req *)buf; - if (le16_to_cpu(req->ByteCount) < 2) - goto err_out; - - if (offsetof(struct smb_negotiate_req, DialectsArray) - 4 + - le16_to_cpu(req->ByteCount) > smb_buf_length) { - goto err_out; - } - - return ksmbd_lookup_dialect_by_name(req->DialectsArray, - req->ByteCount); - } - -err_out: - return BAD_PROT_ID; -} - -#define SMB_COM_NEGOTIATE_EX 0x0 - -/** - * get_smb1_cmd_val() - get smb command value from smb header - * @work: smb work containing smb header - * - * Return: smb command value - */ -static u16 get_smb1_cmd_val(struct ksmbd_work *work) -{ - return SMB_COM_NEGOTIATE_EX; -} - -/** - * init_smb1_rsp_hdr() - initialize smb negotiate response header - * @work: smb work containing smb request - * - * Return: 0 on success, otherwise -EINVAL - */ -static int init_smb1_rsp_hdr(struct ksmbd_work *work) -{ - struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf; - struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf; - - /* - * Remove 4 byte direct TCP header. - */ - *(__be32 *)work->response_buf = - cpu_to_be32(sizeof(struct smb_hdr) - 4); - - rsp_hdr->Command = SMB_COM_NEGOTIATE; - *(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER; - rsp_hdr->Flags = SMBFLG_RESPONSE; - rsp_hdr->Flags2 = SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS | - SMBFLG2_EXT_SEC | SMBFLG2_IS_LONG_NAME; - rsp_hdr->Pid = rcv_hdr->Pid; - rsp_hdr->Mid = rcv_hdr->Mid; - return 0; -} - -/** - * smb1_check_user_session() - check for valid session for a user - * @work: smb work containing smb request buffer - * - * Return: 0 on success, otherwise error - */ -static int smb1_check_user_session(struct ksmbd_work *work) -{ - unsigned int cmd = work->conn->ops->get_cmd_val(work); - - if (cmd == SMB_COM_NEGOTIATE_EX) - return 0; - - return -EINVAL; -} - -/** - * smb1_allocate_rsp_buf() - allocate response buffer for a command - * @work: smb work containing smb request - * - * Return: 0 on success, otherwise -ENOMEM - */ -static int smb1_allocate_rsp_buf(struct ksmbd_work *work) -{ - work->response_buf = kmalloc(MAX_CIFS_SMALL_BUFFER_SIZE, - GFP_KERNEL | __GFP_ZERO); - work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE; - - if (!work->response_buf) { - pr_err("Failed to allocate %u bytes buffer\n", - MAX_CIFS_SMALL_BUFFER_SIZE); - return -ENOMEM; - } - - return 0; -} - -static struct smb_version_ops smb1_server_ops = { - .get_cmd_val = get_smb1_cmd_val, - .init_rsp_hdr = init_smb1_rsp_hdr, - .allocate_rsp_buf = smb1_allocate_rsp_buf, - .check_user_session = smb1_check_user_session, -}; - -static int smb1_negotiate(struct ksmbd_work *work) -{ - return ksmbd_smb_negotiate_common(work, SMB_COM_NEGOTIATE); -} - -static struct smb_version_cmds smb1_server_cmds[1] = { - [SMB_COM_NEGOTIATE_EX] = { .proc = smb1_negotiate, }, -}; - -static void init_smb1_server(struct ksmbd_conn *conn) -{ - conn->ops = &smb1_server_ops; - conn->cmds = smb1_server_cmds; - conn->max_cmds = ARRAY_SIZE(smb1_server_cmds); -} - -void ksmbd_init_smb_server(struct ksmbd_work *work) -{ - struct ksmbd_conn *conn = work->conn; - __le32 proto; - - if (conn->need_neg == false) - return; - - proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol; - if (proto == SMB1_PROTO_NUMBER) - init_smb1_server(conn); - else - init_smb3_11_server(conn); -} - -int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level, - struct ksmbd_file *dir, - struct ksmbd_dir_info *d_info, - char *search_pattern, - int (*fn)(struct ksmbd_conn *, int, - struct ksmbd_dir_info *, - struct ksmbd_kstat *)) -{ - int i, rc = 0; - struct ksmbd_conn *conn = work->conn; - struct user_namespace *user_ns = file_mnt_user_ns(dir->filp); - - for (i = 0; i < 2; i++) { - struct kstat kstat; - struct ksmbd_kstat ksmbd_kstat; - struct dentry *dentry; - - if (!dir->dot_dotdot[i]) { /* fill dot entry info */ - if (i == 0) { - d_info->name = "."; - d_info->name_len = 1; - dentry = dir->filp->f_path.dentry; - } else { - d_info->name = ".."; - d_info->name_len = 2; - dentry = dir->filp->f_path.dentry->d_parent; - } - - if (!match_pattern(d_info->name, d_info->name_len, - search_pattern)) { - dir->dot_dotdot[i] = 1; - continue; - } - - ksmbd_kstat.kstat = &kstat; - ksmbd_vfs_fill_dentry_attrs(work, - user_ns, - dentry, - &ksmbd_kstat); - rc = fn(conn, info_level, d_info, &ksmbd_kstat); - if (rc) - break; - if (d_info->out_buf_len <= 0) - break; - - dir->dot_dotdot[i] = 1; - if (d_info->flags & SMB2_RETURN_SINGLE_ENTRY) { - d_info->out_buf_len = 0; - break; - } - } - } - - return rc; -} - -/** - * ksmbd_extract_shortname() - get shortname from long filename - * @conn: connection instance - * @longname: source long filename - * @shortname: destination short filename - * - * Return: shortname length or 0 when source long name is '.' or '..' - * TODO: Though this function comforms the restriction of 8.3 Filename spec, - * but the result is different with Windows 7's one. need to check. - */ -int ksmbd_extract_shortname(struct ksmbd_conn *conn, const char *longname, - char *shortname) -{ - const char *p; - char base[9], extension[4]; - char out[13] = {0}; - int baselen = 0; - int extlen = 0, len = 0; - unsigned int csum = 0; - const unsigned char *ptr; - bool dot_present = true; - - p = longname; - if ((*p == '.') || (!(strcmp(p, "..")))) { - /*no mangling required */ - return 0; - } - - p = strrchr(longname, '.'); - if (p == longname) { /*name starts with a dot*/ - strscpy(extension, "___", strlen("___")); - } else { - if (p) { - p++; - while (*p && extlen < 3) { - if (*p != '.') - extension[extlen++] = toupper(*p); - p++; - } - extension[extlen] = '\0'; - } else { - dot_present = false; - } - } - - p = longname; - if (*p == '.') { - p++; - longname++; - } - while (*p && (baselen < 5)) { - if (*p != '.') - base[baselen++] = toupper(*p); - p++; - } - - base[baselen] = MAGIC_CHAR; - memcpy(out, base, baselen + 1); - - ptr = longname; - len = strlen(longname); - for (; len > 0; len--, ptr++) - csum += *ptr; - - csum = csum % (MANGLE_BASE * MANGLE_BASE); - out[baselen + 1] = mangle(csum / MANGLE_BASE); - out[baselen + 2] = mangle(csum); - out[baselen + 3] = PERIOD; - - if (dot_present) - memcpy(&out[baselen + 4], extension, 4); - else - out[baselen + 4] = '\0'; - smbConvertToUTF16((__le16 *)shortname, out, PATH_MAX, - conn->local_nls, 0); - len = strlen(out) * 2; - return len; -} - -static int __smb2_negotiate(struct ksmbd_conn *conn) -{ - return (conn->dialect >= SMB20_PROT_ID && - conn->dialect <= SMB311_PROT_ID); -} - -static int smb_handle_negotiate(struct ksmbd_work *work) -{ - struct smb_negotiate_rsp *neg_rsp = work->response_buf; - - ksmbd_debug(SMB, "Unsupported SMB1 protocol\n"); - - /* Add 2 byte bcc and 2 byte DialectIndex. */ - inc_rfc1001_len(work->response_buf, 4); - neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS; - - neg_rsp->hdr.WordCount = 1; - neg_rsp->DialectIndex = cpu_to_le16(work->conn->dialect); - neg_rsp->ByteCount = 0; - return 0; -} - -int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command) -{ - struct ksmbd_conn *conn = work->conn; - int ret; - - conn->dialect = - ksmbd_negotiate_smb_dialect(work->request_buf); - ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect); - - if (command == SMB2_NEGOTIATE_HE) { - ret = smb2_handle_negotiate(work); - return ret; - } - - if (command == SMB_COM_NEGOTIATE) { - if (__smb2_negotiate(conn)) { - init_smb3_11_server(conn); - init_smb2_neg_rsp(work); - ksmbd_debug(SMB, "Upgrade to SMB2 negotiation\n"); - return 0; - } - return smb_handle_negotiate(work); - } - - pr_err("Unknown SMB negotiation command: %u\n", command); - return -EINVAL; -} - -enum SHARED_MODE_ERRORS { - SHARE_DELETE_ERROR, - SHARE_READ_ERROR, - SHARE_WRITE_ERROR, - FILE_READ_ERROR, - FILE_WRITE_ERROR, - FILE_DELETE_ERROR, -}; - -static const char * const shared_mode_errors[] = { - "Current access mode does not permit SHARE_DELETE", - "Current access mode does not permit SHARE_READ", - "Current access mode does not permit SHARE_WRITE", - "Desired access mode does not permit FILE_READ", - "Desired access mode does not permit FILE_WRITE", - "Desired access mode does not permit FILE_DELETE", -}; - -static void smb_shared_mode_error(int error, struct ksmbd_file *prev_fp, - struct ksmbd_file *curr_fp) -{ - ksmbd_debug(SMB, "%s\n", shared_mode_errors[error]); - ksmbd_debug(SMB, "Current mode: 0x%x Desired mode: 0x%x\n", - prev_fp->saccess, curr_fp->daccess); -} - -int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp) -{ - int rc = 0; - struct ksmbd_file *prev_fp; - - /* - * Lookup fp in master fp list, and check desired access and - * shared mode between previous open and current open. - */ - read_lock(&curr_fp->f_ci->m_lock); - list_for_each_entry(prev_fp, &curr_fp->f_ci->m_fp_list, node) { - if (file_inode(filp) != file_inode(prev_fp->filp)) - continue; - - if (filp == prev_fp->filp) - continue; - - if (ksmbd_stream_fd(prev_fp) && ksmbd_stream_fd(curr_fp)) - if (strcmp(prev_fp->stream.name, curr_fp->stream.name)) - continue; - - if (prev_fp->attrib_only != curr_fp->attrib_only) - continue; - - if (!(prev_fp->saccess & FILE_SHARE_DELETE_LE) && - curr_fp->daccess & FILE_DELETE_LE) { - smb_shared_mode_error(SHARE_DELETE_ERROR, - prev_fp, - curr_fp); - rc = -EPERM; - break; - } - - /* - * Only check FILE_SHARE_DELETE if stream opened and - * normal file opened. - */ - if (ksmbd_stream_fd(prev_fp) && !ksmbd_stream_fd(curr_fp)) - continue; - - if (!(prev_fp->saccess & FILE_SHARE_READ_LE) && - curr_fp->daccess & (FILE_EXECUTE_LE | FILE_READ_DATA_LE)) { - smb_shared_mode_error(SHARE_READ_ERROR, - prev_fp, - curr_fp); - rc = -EPERM; - break; - } - - if (!(prev_fp->saccess & FILE_SHARE_WRITE_LE) && - curr_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE)) { - smb_shared_mode_error(SHARE_WRITE_ERROR, - prev_fp, - curr_fp); - rc = -EPERM; - break; - } - - if (prev_fp->daccess & (FILE_EXECUTE_LE | FILE_READ_DATA_LE) && - !(curr_fp->saccess & FILE_SHARE_READ_LE)) { - smb_shared_mode_error(FILE_READ_ERROR, - prev_fp, - curr_fp); - rc = -EPERM; - break; - } - - if (prev_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE) && - !(curr_fp->saccess & FILE_SHARE_WRITE_LE)) { - smb_shared_mode_error(FILE_WRITE_ERROR, - prev_fp, - curr_fp); - rc = -EPERM; - break; - } - - if (prev_fp->daccess & FILE_DELETE_LE && - !(curr_fp->saccess & FILE_SHARE_DELETE_LE)) { - smb_shared_mode_error(FILE_DELETE_ERROR, - prev_fp, - curr_fp); - rc = -EPERM; - break; - } - } - read_unlock(&curr_fp->f_ci->m_lock); - - return rc; -} - -bool is_asterisk(char *p) -{ - return p && p[0] == '*'; -} - -int ksmbd_override_fsids(struct ksmbd_work *work) -{ - struct ksmbd_session *sess = work->sess; - struct ksmbd_share_config *share = work->tcon->share_conf; - struct cred *cred; - struct group_info *gi; - unsigned int uid; - unsigned int gid; - - uid = user_uid(sess->user); - gid = user_gid(sess->user); - if (share->force_uid != KSMBD_SHARE_INVALID_UID) - uid = share->force_uid; - if (share->force_gid != KSMBD_SHARE_INVALID_GID) - gid = share->force_gid; - - cred = prepare_kernel_cred(NULL); - if (!cred) - return -ENOMEM; - - cred->fsuid = make_kuid(&init_user_ns, uid); - cred->fsgid = make_kgid(&init_user_ns, gid); - - gi = groups_alloc(0); - if (!gi) { - abort_creds(cred); - return -ENOMEM; - } - set_groups(cred, gi); - put_group_info(gi); - - if (!uid_eq(cred->fsuid, GLOBAL_ROOT_UID)) - cred->cap_effective = cap_drop_fs_set(cred->cap_effective); - - WARN_ON(work->saved_cred); - work->saved_cred = override_creds(cred); - if (!work->saved_cred) { - abort_creds(cred); - return -EINVAL; - } - return 0; -} - -void ksmbd_revert_fsids(struct ksmbd_work *work) -{ - const struct cred *cred; - - WARN_ON(!work->saved_cred); - - cred = current_cred(); - revert_creds(work->saved_cred); - put_cred(cred); - work->saved_cred = NULL; -} - -__le32 smb_map_generic_desired_access(__le32 daccess) -{ - if (daccess & FILE_GENERIC_READ_LE) { - daccess |= cpu_to_le32(GENERIC_READ_FLAGS); - daccess &= ~FILE_GENERIC_READ_LE; - } - - if (daccess & FILE_GENERIC_WRITE_LE) { - daccess |= cpu_to_le32(GENERIC_WRITE_FLAGS); - daccess &= ~FILE_GENERIC_WRITE_LE; - } - - if (daccess & FILE_GENERIC_EXECUTE_LE) { - daccess |= cpu_to_le32(GENERIC_EXECUTE_FLAGS); - daccess &= ~FILE_GENERIC_EXECUTE_LE; - } - - if (daccess & FILE_GENERIC_ALL_LE) { - daccess |= cpu_to_le32(GENERIC_ALL_FLAGS); - daccess &= ~FILE_GENERIC_ALL_LE; - } - - return daccess; -} diff --git a/fs/ksmbd/smb_common.h b/fs/ksmbd/smb_common.h deleted file mode 100644 index 78c44978a906..000000000000 --- a/fs/ksmbd/smb_common.h +++ /dev/null @@ -1,468 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __SMB_COMMON_H__ -#define __SMB_COMMON_H__ - -#include <linux/kernel.h> - -#include "glob.h" -#include "nterr.h" -#include "../smbfs_common/smb2pdu.h" -#include "smb2pdu.h" - -/* ksmbd's Specific ERRNO */ -#define ESHARE 50000 - -#define SMB1_PROT 0 -#define SMB2_PROT 1 -#define SMB21_PROT 2 -/* multi-protocol negotiate request */ -#define SMB2X_PROT 3 -#define SMB30_PROT 4 -#define SMB302_PROT 5 -#define SMB311_PROT 6 -#define BAD_PROT 0xFFFF - -#define SMB1_VERSION_STRING "1.0" -#define SMB20_VERSION_STRING "2.0" -#define SMB21_VERSION_STRING "2.1" -#define SMB30_VERSION_STRING "3.0" -#define SMB302_VERSION_STRING "3.02" -#define SMB311_VERSION_STRING "3.1.1" - -#define SMB_ECHO_INTERVAL (60 * HZ) - -#define CIFS_DEFAULT_IOSIZE (64 * 1024) -#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */ - -#define MAX_STREAM_PROT_LEN 0x00FFFFFF - -/* Responses when opening a file. */ -#define F_SUPERSEDED 0 -#define F_OPENED 1 -#define F_CREATED 2 -#define F_OVERWRITTEN 3 - -/* - * File Attribute flags - */ -#define ATTR_POSIX_SEMANTICS 0x01000000 -#define ATTR_BACKUP_SEMANTICS 0x02000000 -#define ATTR_DELETE_ON_CLOSE 0x04000000 -#define ATTR_SEQUENTIAL_SCAN 0x08000000 -#define ATTR_RANDOM_ACCESS 0x10000000 -#define ATTR_NO_BUFFERING 0x20000000 -#define ATTR_WRITE_THROUGH 0x80000000 - -/* List of FileSystemAttributes - see 2.5.1 of MS-FSCC */ -#define FILE_SUPPORTS_SPARSE_VDL 0x10000000 /* faster nonsparse extend */ -#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 /* allow ioctl dup extents */ -#define FILE_SUPPORT_INTEGRITY_STREAMS 0x04000000 -#define FILE_SUPPORTS_USN_JOURNAL 0x02000000 -#define FILE_SUPPORTS_OPEN_BY_FILE_ID 0x01000000 -#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000 -#define FILE_SUPPORTS_HARD_LINKS 0x00400000 -#define FILE_SUPPORTS_TRANSACTIONS 0x00200000 -#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000 -#define FILE_READ_ONLY_VOLUME 0x00080000 -#define FILE_NAMED_STREAMS 0x00040000 -#define FILE_SUPPORTS_ENCRYPTION 0x00020000 -#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 -#define FILE_VOLUME_IS_COMPRESSED 0x00008000 -#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 -#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 -#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 -#define FILE_VOLUME_QUOTAS 0x00000020 -#define FILE_FILE_COMPRESSION 0x00000010 -#define FILE_PERSISTENT_ACLS 0x00000008 -#define FILE_UNICODE_ON_DISK 0x00000004 -#define FILE_CASE_PRESERVED_NAMES 0x00000002 -#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 - -#define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ -#define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ -#define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ -#define FILE_READ_EA 0x00000008 /* Extended attributes associated */ -/* with the file can be read */ -#define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ -/* with the file can be written */ -#define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ -/* the file using system paging I/O */ -#define FILE_DELETE_CHILD 0x00000040 -#define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ -/* file can be read */ -#define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ -/* file can be written */ -#define DELETE 0x00010000 /* The file can be deleted */ -#define READ_CONTROL 0x00020000 /* The access control list and */ -/* ownership associated with the */ -/* file can be read */ -#define WRITE_DAC 0x00040000 /* The access control list and */ -/* ownership associated with the */ -/* file can be written. */ -#define WRITE_OWNER 0x00080000 /* Ownership information associated */ -/* with the file can be written */ -#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ -/* synchronize with the completion */ -/* of an input/output request */ -#define GENERIC_ALL 0x10000000 -#define GENERIC_EXECUTE 0x20000000 -#define GENERIC_WRITE 0x40000000 -#define GENERIC_READ 0x80000000 -/* In summary - Relevant file */ -/* access flags from CIFS are */ -/* file_read_data, file_write_data */ -/* file_execute, file_read_attributes*/ -/* write_dac, and delete. */ - -#define SET_FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA \ - | FILE_READ_ATTRIBUTES \ - | DELETE | READ_CONTROL | WRITE_DAC \ - | WRITE_OWNER | SYNCHRONIZE) -#define SET_FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \ - | FILE_WRITE_EA \ - | FILE_DELETE_CHILD \ - | FILE_WRITE_ATTRIBUTES \ - | DELETE | READ_CONTROL | WRITE_DAC \ - | WRITE_OWNER | SYNCHRONIZE) -#define SET_FILE_EXEC_RIGHTS (FILE_READ_EA | FILE_WRITE_EA | FILE_EXECUTE \ - | FILE_READ_ATTRIBUTES \ - | FILE_WRITE_ATTRIBUTES \ - | DELETE | READ_CONTROL | WRITE_DAC \ - | WRITE_OWNER | SYNCHRONIZE) - -#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \ - | READ_CONTROL | SYNCHRONIZE) - -/* generic flags for file open */ -#define GENERIC_READ_FLAGS (READ_CONTROL | FILE_READ_DATA | \ - FILE_READ_ATTRIBUTES | \ - FILE_READ_EA | SYNCHRONIZE) - -#define GENERIC_WRITE_FLAGS (READ_CONTROL | FILE_WRITE_DATA | \ - FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | \ - FILE_APPEND_DATA | SYNCHRONIZE) - -#define GENERIC_EXECUTE_FLAGS (READ_CONTROL | FILE_EXECUTE | \ - FILE_READ_ATTRIBUTES | SYNCHRONIZE) - -#define GENERIC_ALL_FLAGS (DELETE | READ_CONTROL | WRITE_DAC | \ - WRITE_OWNER | SYNCHRONIZE | FILE_READ_DATA | \ - FILE_WRITE_DATA | FILE_APPEND_DATA | \ - FILE_READ_EA | FILE_WRITE_EA | \ - FILE_EXECUTE | FILE_DELETE_CHILD | \ - FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES) - -#define SMB1_PROTO_NUMBER cpu_to_le32(0x424d53ff) -#define SMB_COM_NEGOTIATE 0x72 -#define SMB1_CLIENT_GUID_SIZE (16) - -#define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */ - -#define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40) -#define SMBFLG2_EXT_SEC cpu_to_le16(0x800) -#define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000) -#define SMBFLG2_UNICODE cpu_to_le16(0x8000) - -struct smb_hdr { - __be32 smb_buf_length; - __u8 Protocol[4]; - __u8 Command; - union { - struct { - __u8 ErrorClass; - __u8 Reserved; - __le16 Error; - } __packed DosError; - __le32 CifsError; - } __packed Status; - __u8 Flags; - __le16 Flags2; /* note: le */ - __le16 PidHigh; - union { - struct { - __le32 SequenceNumber; /* le */ - __u32 Reserved; /* zero */ - } __packed Sequence; - __u8 SecuritySignature[8]; /* le */ - } __packed Signature; - __u8 pad[2]; - __le16 Tid; - __le16 Pid; - __le16 Uid; - __le16 Mid; - __u8 WordCount; -} __packed; - -struct smb_negotiate_req { - struct smb_hdr hdr; /* wct = 0 */ - __le16 ByteCount; - unsigned char DialectsArray[1]; -} __packed; - -struct smb_negotiate_rsp { - struct smb_hdr hdr; /* wct = 17 */ - __le16 DialectIndex; /* 0xFFFF = no dialect acceptable */ - __le16 ByteCount; -} __packed; - -struct filesystem_attribute_info { - __le32 Attributes; - __le32 MaxPathNameComponentLength; - __le32 FileSystemNameLen; - __le16 FileSystemName[1]; /* do not have to save this - get subset? */ -} __packed; - -struct filesystem_device_info { - __le32 DeviceType; - __le32 DeviceCharacteristics; -} __packed; /* device info level 0x104 */ - -struct filesystem_vol_info { - __le64 VolumeCreationTime; - __le32 SerialNumber; - __le32 VolumeLabelSize; - __le16 Reserved; - __le16 VolumeLabel[1]; -} __packed; - -struct filesystem_info { - __le64 TotalAllocationUnits; - __le64 FreeAllocationUnits; - __le32 SectorsPerAllocationUnit; - __le32 BytesPerSector; -} __packed; /* size info, level 0x103 */ - -#define EXTENDED_INFO_MAGIC 0x43667364 /* Cfsd */ -#define STRING_LENGTH 28 - -struct fs_extended_info { - __le32 magic; - __le32 version; - __le32 release; - __u64 rel_date; - char version_string[STRING_LENGTH]; -} __packed; - -struct object_id_info { - char objid[16]; - struct fs_extended_info extended_info; -} __packed; - -struct file_directory_info { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - char FileName[1]; -} __packed; /* level 0x101 FF resp data */ - -struct file_names_info { - __le32 NextEntryOffset; - __u32 FileIndex; - __le32 FileNameLength; - char FileName[1]; -} __packed; /* level 0xc FF resp data */ - -struct file_full_directory_info { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; - char FileName[1]; -} __packed; /* level 0x102 FF resp */ - -struct file_both_directory_info { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; /* length of the xattrs */ - __u8 ShortNameLength; - __u8 Reserved; - __u8 ShortName[24]; - char FileName[1]; -} __packed; /* level 0x104 FFrsp data */ - -struct file_id_both_directory_info { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; /* length of the xattrs */ - __u8 ShortNameLength; - __u8 Reserved; - __u8 ShortName[24]; - __le16 Reserved2; - __le64 UniqueId; - char FileName[1]; -} __packed; - -struct file_id_full_dir_info { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; /* EA size */ - __le32 Reserved; - __le64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ - char FileName[1]; -} __packed; /* level 0x105 FF rsp data */ - -struct smb_version_values { - char *version_string; - __u16 protocol_id; - __le16 lock_cmd; - __u32 capabilities; - __u32 max_read_size; - __u32 max_write_size; - __u32 max_trans_size; - __u32 max_credits; - __u32 large_lock_type; - __u32 exclusive_lock_type; - __u32 shared_lock_type; - __u32 unlock_lock_type; - size_t header_size; - size_t max_header_size; - size_t read_rsp_size; - unsigned int cap_unix; - unsigned int cap_nt_find; - unsigned int cap_large_files; - __u16 signing_enabled; - __u16 signing_required; - size_t create_lease_size; - size_t create_durable_size; - size_t create_durable_v2_size; - size_t create_mxac_size; - size_t create_disk_id_size; - size_t create_posix_size; -}; - -struct filesystem_posix_info { - /* For undefined recommended transfer size return -1 in that field */ - __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ - __le32 BlockSize; - /* The next three fields are in terms of the block size. - * (above). If block size is unknown, 4096 would be a - * reasonable block size for a server to report. - * Note that returning the blocks/blocksavail removes need - * to make a second call (to QFSInfo level 0x103 to get this info. - * UserBlockAvail is typically less than or equal to BlocksAvail, - * if no distinction is made return the same value in each - */ - __le64 TotalBlocks; - __le64 BlocksAvail; /* bfree */ - __le64 UserBlocksAvail; /* bavail */ - /* For undefined Node fields or FSID return -1 */ - __le64 TotalFileNodes; - __le64 FreeFileNodes; - __le64 FileSysIdentifier; /* fsid */ - /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */ - /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */ -} __packed; - -struct smb_version_ops { - u16 (*get_cmd_val)(struct ksmbd_work *swork); - int (*init_rsp_hdr)(struct ksmbd_work *swork); - void (*set_rsp_status)(struct ksmbd_work *swork, __le32 err); - int (*allocate_rsp_buf)(struct ksmbd_work *work); - int (*set_rsp_credits)(struct ksmbd_work *work); - int (*check_user_session)(struct ksmbd_work *work); - int (*get_ksmbd_tcon)(struct ksmbd_work *work); - bool (*is_sign_req)(struct ksmbd_work *work, unsigned int command); - int (*check_sign_req)(struct ksmbd_work *work); - void (*set_sign_rsp)(struct ksmbd_work *work); - int (*generate_signingkey)(struct ksmbd_session *sess, struct ksmbd_conn *conn); - int (*generate_encryptionkey)(struct ksmbd_conn *conn, struct ksmbd_session *sess); - bool (*is_transform_hdr)(void *buf); - int (*decrypt_req)(struct ksmbd_work *work); - int (*encrypt_resp)(struct ksmbd_work *work); -}; - -struct smb_version_cmds { - int (*proc)(struct ksmbd_work *swork); -}; - -int ksmbd_min_protocol(void); -int ksmbd_max_protocol(void); - -int ksmbd_lookup_protocol_idx(char *str); - -int ksmbd_verify_smb_message(struct ksmbd_work *work); -bool ksmbd_smb_request(struct ksmbd_conn *conn); - -int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count); - -void ksmbd_init_smb_server(struct ksmbd_work *work); - -struct ksmbd_kstat; -int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, - int info_level, - struct ksmbd_file *dir, - struct ksmbd_dir_info *d_info, - char *search_pattern, - int (*fn)(struct ksmbd_conn *, - int, - struct ksmbd_dir_info *, - struct ksmbd_kstat *)); - -int ksmbd_extract_shortname(struct ksmbd_conn *conn, - const char *longname, - char *shortname); - -int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command); - -int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp); -int ksmbd_override_fsids(struct ksmbd_work *work); -void ksmbd_revert_fsids(struct ksmbd_work *work); - -unsigned int ksmbd_server_side_copy_max_chunk_count(void); -unsigned int ksmbd_server_side_copy_max_chunk_size(void); -unsigned int ksmbd_server_side_copy_max_total_size(void); -bool is_asterisk(char *p); -__le32 smb_map_generic_desired_access(__le32 daccess); - -static inline unsigned int get_rfc1002_len(void *buf) -{ - return be32_to_cpu(*((__be32 *)buf)) & 0xffffff; -} - -static inline void inc_rfc1001_len(void *buf, int count) -{ - be32_add_cpu((__be32 *)buf, count); -} -#endif /* __SMB_COMMON_H__ */ diff --git a/fs/ksmbd/smbacl.c b/fs/ksmbd/smbacl.c deleted file mode 100644 index b05ff9b146b5..000000000000 --- a/fs/ksmbd/smbacl.c +++ /dev/null @@ -1,1436 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1+ -/* - * Copyright (C) International Business Machines Corp., 2007,2008 - * Author(s): Steve French (sfrench@us.ibm.com) - * Copyright (C) 2020 Samsung Electronics Co., Ltd. - * Author(s): Namjae Jeon <linkinjeon@kernel.org> - */ - -#include <linux/fs.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/mnt_idmapping.h> - -#include "smbacl.h" -#include "smb_common.h" -#include "server.h" -#include "misc.h" -#include "mgmt/share_config.h" - -static const struct smb_sid domain = {1, 4, {0, 0, 0, 0, 0, 5}, - {cpu_to_le32(21), cpu_to_le32(1), cpu_to_le32(2), cpu_to_le32(3), - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; - -/* security id for everyone/world system group */ -static const struct smb_sid creator_owner = { - 1, 1, {0, 0, 0, 0, 0, 3}, {0} }; -/* security id for everyone/world system group */ -static const struct smb_sid creator_group = { - 1, 1, {0, 0, 0, 0, 0, 3}, {cpu_to_le32(1)} }; - -/* security id for everyone/world system group */ -static const struct smb_sid sid_everyone = { - 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; -/* security id for Authenticated Users system group */ -static const struct smb_sid sid_authusers = { - 1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11)} }; - -/* S-1-22-1 Unmapped Unix users */ -static const struct smb_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22}, - {cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; - -/* S-1-22-2 Unmapped Unix groups */ -static const struct smb_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22}, - {cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; - -/* - * See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx - */ - -/* S-1-5-88 MS NFS and Apple style UID/GID/mode */ - -/* S-1-5-88-1 Unix uid */ -static const struct smb_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5}, - {cpu_to_le32(88), - cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; - -/* S-1-5-88-2 Unix gid */ -static const struct smb_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5}, - {cpu_to_le32(88), - cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; - -/* S-1-5-88-3 Unix mode */ -static const struct smb_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5}, - {cpu_to_le32(88), - cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; - -/* - * if the two SIDs (roughly equivalent to a UUID for a user or group) are - * the same returns zero, if they do not match returns non-zero. - */ -int compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid) -{ - int i; - int num_subauth, num_sat, num_saw; - - if (!ctsid || !cwsid) - return 1; - - /* compare the revision */ - if (ctsid->revision != cwsid->revision) { - if (ctsid->revision > cwsid->revision) - return 1; - else - return -1; - } - - /* compare all of the six auth values */ - for (i = 0; i < NUM_AUTHS; ++i) { - if (ctsid->authority[i] != cwsid->authority[i]) { - if (ctsid->authority[i] > cwsid->authority[i]) - return 1; - else - return -1; - } - } - - /* compare all of the subauth values if any */ - num_sat = ctsid->num_subauth; - num_saw = cwsid->num_subauth; - num_subauth = num_sat < num_saw ? num_sat : num_saw; - if (num_subauth) { - for (i = 0; i < num_subauth; ++i) { - if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { - if (le32_to_cpu(ctsid->sub_auth[i]) > - le32_to_cpu(cwsid->sub_auth[i])) - return 1; - else - return -1; - } - } - } - - return 0; /* sids compare/match */ -} - -static void smb_copy_sid(struct smb_sid *dst, const struct smb_sid *src) -{ - int i; - - dst->revision = src->revision; - dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES); - for (i = 0; i < NUM_AUTHS; ++i) - dst->authority[i] = src->authority[i]; - for (i = 0; i < dst->num_subauth; ++i) - dst->sub_auth[i] = src->sub_auth[i]; -} - -/* - * change posix mode to reflect permissions - * pmode is the existing mode (we only want to overwrite part of this - * bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007 - */ -static umode_t access_flags_to_mode(struct smb_fattr *fattr, __le32 ace_flags, - int type) -{ - __u32 flags = le32_to_cpu(ace_flags); - umode_t mode = 0; - - if (flags & GENERIC_ALL) { - mode = 0777; - ksmbd_debug(SMB, "all perms\n"); - return mode; - } - - if ((flags & GENERIC_READ) || (flags & FILE_READ_RIGHTS)) - mode = 0444; - if ((flags & GENERIC_WRITE) || (flags & FILE_WRITE_RIGHTS)) { - mode |= 0222; - if (S_ISDIR(fattr->cf_mode)) - mode |= 0111; - } - if ((flags & GENERIC_EXECUTE) || (flags & FILE_EXEC_RIGHTS)) - mode |= 0111; - - if (type == ACCESS_DENIED_ACE_TYPE || type == ACCESS_DENIED_OBJECT_ACE_TYPE) - mode = ~mode; - - ksmbd_debug(SMB, "access flags 0x%x mode now %04o\n", flags, mode); - - return mode; -} - -/* - * Generate access flags to reflect permissions mode is the existing mode. - * This function is called for every ACE in the DACL whose SID matches - * with either owner or group or everyone. - */ -static void mode_to_access_flags(umode_t mode, umode_t bits_to_use, - __u32 *pace_flags) -{ - /* reset access mask */ - *pace_flags = 0x0; - - /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */ - mode &= bits_to_use; - - /* - * check for R/W/X UGO since we do not know whose flags - * is this but we have cleared all the bits sans RWX for - * either user or group or other as per bits_to_use - */ - if (mode & 0444) - *pace_flags |= SET_FILE_READ_RIGHTS; - if (mode & 0222) - *pace_flags |= FILE_WRITE_RIGHTS; - if (mode & 0111) - *pace_flags |= SET_FILE_EXEC_RIGHTS; - - ksmbd_debug(SMB, "mode: %o, access flags now 0x%x\n", - mode, *pace_flags); -} - -static __u16 fill_ace_for_sid(struct smb_ace *pntace, - const struct smb_sid *psid, int type, int flags, - umode_t mode, umode_t bits) -{ - int i; - __u16 size = 0; - __u32 access_req = 0; - - pntace->type = type; - pntace->flags = flags; - mode_to_access_flags(mode, bits, &access_req); - if (!access_req) - access_req = SET_MINIMUM_RIGHTS; - pntace->access_req = cpu_to_le32(access_req); - - pntace->sid.revision = psid->revision; - pntace->sid.num_subauth = psid->num_subauth; - for (i = 0; i < NUM_AUTHS; i++) - pntace->sid.authority[i] = psid->authority[i]; - for (i = 0; i < psid->num_subauth; i++) - pntace->sid.sub_auth[i] = psid->sub_auth[i]; - - size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4); - pntace->size = cpu_to_le16(size); - - return size; -} - -void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid) -{ - switch (sidtype) { - case SIDOWNER: - smb_copy_sid(ssid, &server_conf.domain_sid); - break; - case SIDUNIX_USER: - smb_copy_sid(ssid, &sid_unix_users); - break; - case SIDUNIX_GROUP: - smb_copy_sid(ssid, &sid_unix_groups); - break; - case SIDCREATOR_OWNER: - smb_copy_sid(ssid, &creator_owner); - return; - case SIDCREATOR_GROUP: - smb_copy_sid(ssid, &creator_group); - return; - case SIDNFS_USER: - smb_copy_sid(ssid, &sid_unix_NFS_users); - break; - case SIDNFS_GROUP: - smb_copy_sid(ssid, &sid_unix_NFS_groups); - break; - case SIDNFS_MODE: - smb_copy_sid(ssid, &sid_unix_NFS_mode); - break; - default: - return; - } - - /* RID */ - ssid->sub_auth[ssid->num_subauth] = cpu_to_le32(cid); - ssid->num_subauth++; -} - -static int sid_to_id(struct user_namespace *user_ns, - struct smb_sid *psid, uint sidtype, - struct smb_fattr *fattr) -{ - int rc = -EINVAL; - - /* - * If we have too many subauthorities, then something is really wrong. - * Just return an error. - */ - if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) { - pr_err("%s: %u subauthorities is too many!\n", - __func__, psid->num_subauth); - return -EIO; - } - - if (sidtype == SIDOWNER) { - kuid_t uid; - uid_t id; - - id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]); - uid = KUIDT_INIT(id); - uid = from_vfsuid(user_ns, &init_user_ns, VFSUIDT_INIT(uid)); - if (uid_valid(uid)) { - fattr->cf_uid = uid; - rc = 0; - } - } else { - kgid_t gid; - gid_t id; - - id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]); - gid = KGIDT_INIT(id); - gid = from_vfsgid(user_ns, &init_user_ns, VFSGIDT_INIT(gid)); - if (gid_valid(gid)) { - fattr->cf_gid = gid; - rc = 0; - } - } - - return rc; -} - -void posix_state_to_acl(struct posix_acl_state *state, - struct posix_acl_entry *pace) -{ - int i; - - pace->e_tag = ACL_USER_OBJ; - pace->e_perm = state->owner.allow; - for (i = 0; i < state->users->n; i++) { - pace++; - pace->e_tag = ACL_USER; - pace->e_uid = state->users->aces[i].uid; - pace->e_perm = state->users->aces[i].perms.allow; - } - - pace++; - pace->e_tag = ACL_GROUP_OBJ; - pace->e_perm = state->group.allow; - - for (i = 0; i < state->groups->n; i++) { - pace++; - pace->e_tag = ACL_GROUP; - pace->e_gid = state->groups->aces[i].gid; - pace->e_perm = state->groups->aces[i].perms.allow; - } - - if (state->users->n || state->groups->n) { - pace++; - pace->e_tag = ACL_MASK; - pace->e_perm = state->mask.allow; - } - - pace++; - pace->e_tag = ACL_OTHER; - pace->e_perm = state->other.allow; -} - -int init_acl_state(struct posix_acl_state *state, int cnt) -{ - int alloc; - - memset(state, 0, sizeof(struct posix_acl_state)); - /* - * In the worst case, each individual acl could be for a distinct - * named user or group, but we don't know which, so we allocate - * enough space for either: - */ - alloc = sizeof(struct posix_ace_state_array) - + cnt * sizeof(struct posix_user_ace_state); - state->users = kzalloc(alloc, GFP_KERNEL); - if (!state->users) - return -ENOMEM; - state->groups = kzalloc(alloc, GFP_KERNEL); - if (!state->groups) { - kfree(state->users); - return -ENOMEM; - } - return 0; -} - -void free_acl_state(struct posix_acl_state *state) -{ - kfree(state->users); - kfree(state->groups); -} - -static void parse_dacl(struct user_namespace *user_ns, - struct smb_acl *pdacl, char *end_of_acl, - struct smb_sid *pownersid, struct smb_sid *pgrpsid, - struct smb_fattr *fattr) -{ - int i, ret; - int num_aces = 0; - unsigned int acl_size; - char *acl_base; - struct smb_ace **ppace; - struct posix_acl_entry *cf_pace, *cf_pdace; - struct posix_acl_state acl_state, default_acl_state; - umode_t mode = 0, acl_mode; - bool owner_found = false, group_found = false, others_found = false; - - if (!pdacl) - return; - - /* validate that we do not go past end of acl */ - if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) || - end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { - pr_err("ACL too small to parse DACL\n"); - return; - } - - ksmbd_debug(SMB, "DACL revision %d size %d num aces %d\n", - le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), - le32_to_cpu(pdacl->num_aces)); - - acl_base = (char *)pdacl; - acl_size = sizeof(struct smb_acl); - - num_aces = le32_to_cpu(pdacl->num_aces); - if (num_aces <= 0) - return; - - if (num_aces > ULONG_MAX / sizeof(struct smb_ace *)) - return; - - ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *), GFP_KERNEL); - if (!ppace) - return; - - ret = init_acl_state(&acl_state, num_aces); - if (ret) - return; - ret = init_acl_state(&default_acl_state, num_aces); - if (ret) { - free_acl_state(&acl_state); - return; - } - - /* - * reset rwx permissions for user/group/other. - * Also, if num_aces is 0 i.e. DACL has no ACEs, - * user/group/other have no permissions - */ - for (i = 0; i < num_aces; ++i) { - if (end_of_acl - acl_base < acl_size) - break; - - ppace[i] = (struct smb_ace *)(acl_base + acl_size); - acl_base = (char *)ppace[i]; - acl_size = offsetof(struct smb_ace, sid) + - offsetof(struct smb_sid, sub_auth); - - if (end_of_acl - acl_base < acl_size || - ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || - (end_of_acl - acl_base < - acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) || - (le16_to_cpu(ppace[i]->size) < - acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) - break; - - acl_size = le16_to_cpu(ppace[i]->size); - ppace[i]->access_req = - smb_map_generic_desired_access(ppace[i]->access_req); - - if (!(compare_sids(&ppace[i]->sid, &sid_unix_NFS_mode))) { - fattr->cf_mode = - le32_to_cpu(ppace[i]->sid.sub_auth[2]); - break; - } else if (!compare_sids(&ppace[i]->sid, pownersid)) { - acl_mode = access_flags_to_mode(fattr, - ppace[i]->access_req, - ppace[i]->type); - acl_mode &= 0700; - - if (!owner_found) { - mode &= ~(0700); - mode |= acl_mode; - } - owner_found = true; - } else if (!compare_sids(&ppace[i]->sid, pgrpsid) || - ppace[i]->sid.sub_auth[ppace[i]->sid.num_subauth - 1] == - DOMAIN_USER_RID_LE) { - acl_mode = access_flags_to_mode(fattr, - ppace[i]->access_req, - ppace[i]->type); - acl_mode &= 0070; - if (!group_found) { - mode &= ~(0070); - mode |= acl_mode; - } - group_found = true; - } else if (!compare_sids(&ppace[i]->sid, &sid_everyone)) { - acl_mode = access_flags_to_mode(fattr, - ppace[i]->access_req, - ppace[i]->type); - acl_mode &= 0007; - if (!others_found) { - mode &= ~(0007); - mode |= acl_mode; - } - others_found = true; - } else if (!compare_sids(&ppace[i]->sid, &creator_owner)) { - continue; - } else if (!compare_sids(&ppace[i]->sid, &creator_group)) { - continue; - } else if (!compare_sids(&ppace[i]->sid, &sid_authusers)) { - continue; - } else { - struct smb_fattr temp_fattr; - - acl_mode = access_flags_to_mode(fattr, ppace[i]->access_req, - ppace[i]->type); - temp_fattr.cf_uid = INVALID_UID; - ret = sid_to_id(user_ns, &ppace[i]->sid, SIDOWNER, &temp_fattr); - if (ret || uid_eq(temp_fattr.cf_uid, INVALID_UID)) { - pr_err("%s: Error %d mapping Owner SID to uid\n", - __func__, ret); - continue; - } - - acl_state.owner.allow = ((acl_mode & 0700) >> 6) | 0004; - acl_state.users->aces[acl_state.users->n].uid = - temp_fattr.cf_uid; - acl_state.users->aces[acl_state.users->n++].perms.allow = - ((acl_mode & 0700) >> 6) | 0004; - default_acl_state.owner.allow = ((acl_mode & 0700) >> 6) | 0004; - default_acl_state.users->aces[default_acl_state.users->n].uid = - temp_fattr.cf_uid; - default_acl_state.users->aces[default_acl_state.users->n++].perms.allow = - ((acl_mode & 0700) >> 6) | 0004; - } - } - kfree(ppace); - - if (owner_found) { - /* The owner must be set to at least read-only. */ - acl_state.owner.allow = ((mode & 0700) >> 6) | 0004; - acl_state.users->aces[acl_state.users->n].uid = fattr->cf_uid; - acl_state.users->aces[acl_state.users->n++].perms.allow = - ((mode & 0700) >> 6) | 0004; - default_acl_state.owner.allow = ((mode & 0700) >> 6) | 0004; - default_acl_state.users->aces[default_acl_state.users->n].uid = - fattr->cf_uid; - default_acl_state.users->aces[default_acl_state.users->n++].perms.allow = - ((mode & 0700) >> 6) | 0004; - } - - if (group_found) { - acl_state.group.allow = (mode & 0070) >> 3; - acl_state.groups->aces[acl_state.groups->n].gid = - fattr->cf_gid; - acl_state.groups->aces[acl_state.groups->n++].perms.allow = - (mode & 0070) >> 3; - default_acl_state.group.allow = (mode & 0070) >> 3; - default_acl_state.groups->aces[default_acl_state.groups->n].gid = - fattr->cf_gid; - default_acl_state.groups->aces[default_acl_state.groups->n++].perms.allow = - (mode & 0070) >> 3; - } - - if (others_found) { - fattr->cf_mode &= ~(0007); - fattr->cf_mode |= mode & 0007; - - acl_state.other.allow = mode & 0007; - default_acl_state.other.allow = mode & 0007; - } - - if (acl_state.users->n || acl_state.groups->n) { - acl_state.mask.allow = 0x07; - - if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { - fattr->cf_acls = - posix_acl_alloc(acl_state.users->n + - acl_state.groups->n + 4, GFP_KERNEL); - if (fattr->cf_acls) { - cf_pace = fattr->cf_acls->a_entries; - posix_state_to_acl(&acl_state, cf_pace); - } - } - } - - if (default_acl_state.users->n || default_acl_state.groups->n) { - default_acl_state.mask.allow = 0x07; - - if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { - fattr->cf_dacls = - posix_acl_alloc(default_acl_state.users->n + - default_acl_state.groups->n + 4, GFP_KERNEL); - if (fattr->cf_dacls) { - cf_pdace = fattr->cf_dacls->a_entries; - posix_state_to_acl(&default_acl_state, cf_pdace); - } - } - } - free_acl_state(&acl_state); - free_acl_state(&default_acl_state); -} - -static void set_posix_acl_entries_dacl(struct user_namespace *user_ns, - struct smb_ace *pndace, - struct smb_fattr *fattr, u32 *num_aces, - u16 *size, u32 nt_aces_num) -{ - struct posix_acl_entry *pace; - struct smb_sid *sid; - struct smb_ace *ntace; - int i, j; - - if (!fattr->cf_acls) - goto posix_default_acl; - - pace = fattr->cf_acls->a_entries; - for (i = 0; i < fattr->cf_acls->a_count; i++, pace++) { - int flags = 0; - - sid = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); - if (!sid) - break; - - if (pace->e_tag == ACL_USER) { - uid_t uid; - unsigned int sid_type = SIDOWNER; - - uid = posix_acl_uid_translate(user_ns, pace); - if (!uid) - sid_type = SIDUNIX_USER; - id_to_sid(uid, sid_type, sid); - } else if (pace->e_tag == ACL_GROUP) { - gid_t gid; - - gid = posix_acl_gid_translate(user_ns, pace); - id_to_sid(gid, SIDUNIX_GROUP, sid); - } else if (pace->e_tag == ACL_OTHER && !nt_aces_num) { - smb_copy_sid(sid, &sid_everyone); - } else { - kfree(sid); - continue; - } - ntace = pndace; - for (j = 0; j < nt_aces_num; j++) { - if (ntace->sid.sub_auth[ntace->sid.num_subauth - 1] == - sid->sub_auth[sid->num_subauth - 1]) - goto pass_same_sid; - ntace = (struct smb_ace *)((char *)ntace + - le16_to_cpu(ntace->size)); - } - - if (S_ISDIR(fattr->cf_mode) && pace->e_tag == ACL_OTHER) - flags = 0x03; - - ntace = (struct smb_ace *)((char *)pndace + *size); - *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags, - pace->e_perm, 0777); - (*num_aces)++; - if (pace->e_tag == ACL_USER) - ntace->access_req |= - FILE_DELETE_LE | FILE_DELETE_CHILD_LE; - - if (S_ISDIR(fattr->cf_mode) && - (pace->e_tag == ACL_USER || pace->e_tag == ACL_GROUP)) { - ntace = (struct smb_ace *)((char *)pndace + *size); - *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, - 0x03, pace->e_perm, 0777); - (*num_aces)++; - if (pace->e_tag == ACL_USER) - ntace->access_req |= - FILE_DELETE_LE | FILE_DELETE_CHILD_LE; - } - -pass_same_sid: - kfree(sid); - } - - if (nt_aces_num) - return; - -posix_default_acl: - if (!fattr->cf_dacls) - return; - - pace = fattr->cf_dacls->a_entries; - for (i = 0; i < fattr->cf_dacls->a_count; i++, pace++) { - sid = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); - if (!sid) - break; - - if (pace->e_tag == ACL_USER) { - uid_t uid; - - uid = posix_acl_uid_translate(user_ns, pace); - id_to_sid(uid, SIDCREATOR_OWNER, sid); - } else if (pace->e_tag == ACL_GROUP) { - gid_t gid; - - gid = posix_acl_gid_translate(user_ns, pace); - id_to_sid(gid, SIDCREATOR_GROUP, sid); - } else { - kfree(sid); - continue; - } - - ntace = (struct smb_ace *)((char *)pndace + *size); - *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b, - pace->e_perm, 0777); - (*num_aces)++; - if (pace->e_tag == ACL_USER) - ntace->access_req |= - FILE_DELETE_LE | FILE_DELETE_CHILD_LE; - kfree(sid); - } -} - -static void set_ntacl_dacl(struct user_namespace *user_ns, - struct smb_acl *pndacl, - struct smb_acl *nt_dacl, - unsigned int aces_size, - const struct smb_sid *pownersid, - const struct smb_sid *pgrpsid, - struct smb_fattr *fattr) -{ - struct smb_ace *ntace, *pndace; - int nt_num_aces = le32_to_cpu(nt_dacl->num_aces), num_aces = 0; - unsigned short size = 0; - int i; - - pndace = (struct smb_ace *)((char *)pndacl + sizeof(struct smb_acl)); - if (nt_num_aces) { - ntace = (struct smb_ace *)((char *)nt_dacl + sizeof(struct smb_acl)); - for (i = 0; i < nt_num_aces; i++) { - unsigned short nt_ace_size; - - if (offsetof(struct smb_ace, access_req) > aces_size) - break; - - nt_ace_size = le16_to_cpu(ntace->size); - if (nt_ace_size > aces_size) - break; - - memcpy((char *)pndace + size, ntace, nt_ace_size); - size += nt_ace_size; - aces_size -= nt_ace_size; - ntace = (struct smb_ace *)((char *)ntace + nt_ace_size); - num_aces++; - } - } - - set_posix_acl_entries_dacl(user_ns, pndace, fattr, - &num_aces, &size, nt_num_aces); - pndacl->num_aces = cpu_to_le32(num_aces); - pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size); -} - -static void set_mode_dacl(struct user_namespace *user_ns, - struct smb_acl *pndacl, struct smb_fattr *fattr) -{ - struct smb_ace *pace, *pndace; - u32 num_aces = 0; - u16 size = 0, ace_size = 0; - uid_t uid; - const struct smb_sid *sid; - - pace = pndace = (struct smb_ace *)((char *)pndacl + sizeof(struct smb_acl)); - - if (fattr->cf_acls) { - set_posix_acl_entries_dacl(user_ns, pndace, fattr, - &num_aces, &size, num_aces); - goto out; - } - - /* owner RID */ - uid = from_kuid(&init_user_ns, fattr->cf_uid); - if (uid) - sid = &server_conf.domain_sid; - else - sid = &sid_unix_users; - ace_size = fill_ace_for_sid(pace, sid, ACCESS_ALLOWED, 0, - fattr->cf_mode, 0700); - pace->sid.sub_auth[pace->sid.num_subauth++] = cpu_to_le32(uid); - pace->size = cpu_to_le16(ace_size + 4); - size += le16_to_cpu(pace->size); - pace = (struct smb_ace *)((char *)pndace + size); - - /* Group RID */ - ace_size = fill_ace_for_sid(pace, &sid_unix_groups, - ACCESS_ALLOWED, 0, fattr->cf_mode, 0070); - pace->sid.sub_auth[pace->sid.num_subauth++] = - cpu_to_le32(from_kgid(&init_user_ns, fattr->cf_gid)); - pace->size = cpu_to_le16(ace_size + 4); - size += le16_to_cpu(pace->size); - pace = (struct smb_ace *)((char *)pndace + size); - num_aces = 3; - - if (S_ISDIR(fattr->cf_mode)) { - pace = (struct smb_ace *)((char *)pndace + size); - - /* creator owner */ - size += fill_ace_for_sid(pace, &creator_owner, ACCESS_ALLOWED, - 0x0b, fattr->cf_mode, 0700); - pace = (struct smb_ace *)((char *)pndace + size); - - /* creator group */ - size += fill_ace_for_sid(pace, &creator_group, ACCESS_ALLOWED, - 0x0b, fattr->cf_mode, 0070); - pace = (struct smb_ace *)((char *)pndace + size); - num_aces = 5; - } - - /* other */ - size += fill_ace_for_sid(pace, &sid_everyone, ACCESS_ALLOWED, 0, - fattr->cf_mode, 0007); - -out: - pndacl->num_aces = cpu_to_le32(num_aces); - pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size); -} - -static int parse_sid(struct smb_sid *psid, char *end_of_acl) -{ - /* - * validate that we do not go past end of ACL - sid must be at least 8 - * bytes long (assuming no sub-auths - e.g. the null SID - */ - if (end_of_acl < (char *)psid + 8) { - pr_err("ACL too small to parse SID %p\n", psid); - return -EINVAL; - } - - return 0; -} - -/* Convert CIFS ACL to POSIX form */ -int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd, - int acl_len, struct smb_fattr *fattr) -{ - int rc = 0; - struct smb_sid *owner_sid_ptr, *group_sid_ptr; - struct smb_acl *dacl_ptr; /* no need for SACL ptr */ - char *end_of_acl = ((char *)pntsd) + acl_len; - __u32 dacloffset; - int pntsd_type; - - if (!pntsd) - return -EIO; - - if (acl_len < sizeof(struct smb_ntsd)) - return -EINVAL; - - owner_sid_ptr = (struct smb_sid *)((char *)pntsd + - le32_to_cpu(pntsd->osidoffset)); - group_sid_ptr = (struct smb_sid *)((char *)pntsd + - le32_to_cpu(pntsd->gsidoffset)); - dacloffset = le32_to_cpu(pntsd->dacloffset); - dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); - ksmbd_debug(SMB, - "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n", - pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), - le32_to_cpu(pntsd->gsidoffset), - le32_to_cpu(pntsd->sacloffset), dacloffset); - - pntsd_type = le16_to_cpu(pntsd->type); - if (!(pntsd_type & DACL_PRESENT)) { - ksmbd_debug(SMB, "DACL_PRESENT in DACL type is not set\n"); - return rc; - } - - pntsd->type = cpu_to_le16(DACL_PRESENT); - - if (pntsd->osidoffset) { - rc = parse_sid(owner_sid_ptr, end_of_acl); - if (rc) { - pr_err("%s: Error %d parsing Owner SID\n", __func__, rc); - return rc; - } - - rc = sid_to_id(user_ns, owner_sid_ptr, SIDOWNER, fattr); - if (rc) { - pr_err("%s: Error %d mapping Owner SID to uid\n", - __func__, rc); - owner_sid_ptr = NULL; - } - } - - if (pntsd->gsidoffset) { - rc = parse_sid(group_sid_ptr, end_of_acl); - if (rc) { - pr_err("%s: Error %d mapping Owner SID to gid\n", - __func__, rc); - return rc; - } - rc = sid_to_id(user_ns, group_sid_ptr, SIDUNIX_GROUP, fattr); - if (rc) { - pr_err("%s: Error %d mapping Group SID to gid\n", - __func__, rc); - group_sid_ptr = NULL; - } - } - - if ((pntsd_type & (DACL_AUTO_INHERITED | DACL_AUTO_INHERIT_REQ)) == - (DACL_AUTO_INHERITED | DACL_AUTO_INHERIT_REQ)) - pntsd->type |= cpu_to_le16(DACL_AUTO_INHERITED); - if (pntsd_type & DACL_PROTECTED) - pntsd->type |= cpu_to_le16(DACL_PROTECTED); - - if (dacloffset) { - parse_dacl(user_ns, dacl_ptr, end_of_acl, - owner_sid_ptr, group_sid_ptr, fattr); - } - - return 0; -} - -/* Convert permission bits from mode to equivalent CIFS ACL */ -int build_sec_desc(struct user_namespace *user_ns, - struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, - int ppntsd_size, int addition_info, __u32 *secdesclen, - struct smb_fattr *fattr) -{ - int rc = 0; - __u32 offset; - struct smb_sid *owner_sid_ptr, *group_sid_ptr; - struct smb_sid *nowner_sid_ptr, *ngroup_sid_ptr; - struct smb_acl *dacl_ptr = NULL; /* no need for SACL ptr */ - uid_t uid; - gid_t gid; - unsigned int sid_type = SIDOWNER; - - nowner_sid_ptr = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); - if (!nowner_sid_ptr) - return -ENOMEM; - - uid = from_kuid(&init_user_ns, fattr->cf_uid); - if (!uid) - sid_type = SIDUNIX_USER; - id_to_sid(uid, sid_type, nowner_sid_ptr); - - ngroup_sid_ptr = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); - if (!ngroup_sid_ptr) { - kfree(nowner_sid_ptr); - return -ENOMEM; - } - - gid = from_kgid(&init_user_ns, fattr->cf_gid); - id_to_sid(gid, SIDUNIX_GROUP, ngroup_sid_ptr); - - offset = sizeof(struct smb_ntsd); - pntsd->sacloffset = 0; - pntsd->revision = cpu_to_le16(1); - pntsd->type = cpu_to_le16(SELF_RELATIVE); - if (ppntsd) - pntsd->type |= ppntsd->type; - - if (addition_info & OWNER_SECINFO) { - pntsd->osidoffset = cpu_to_le32(offset); - owner_sid_ptr = (struct smb_sid *)((char *)pntsd + offset); - smb_copy_sid(owner_sid_ptr, nowner_sid_ptr); - offset += 1 + 1 + 6 + (nowner_sid_ptr->num_subauth * 4); - } - - if (addition_info & GROUP_SECINFO) { - pntsd->gsidoffset = cpu_to_le32(offset); - group_sid_ptr = (struct smb_sid *)((char *)pntsd + offset); - smb_copy_sid(group_sid_ptr, ngroup_sid_ptr); - offset += 1 + 1 + 6 + (ngroup_sid_ptr->num_subauth * 4); - } - - if (addition_info & DACL_SECINFO) { - pntsd->type |= cpu_to_le16(DACL_PRESENT); - dacl_ptr = (struct smb_acl *)((char *)pntsd + offset); - dacl_ptr->revision = cpu_to_le16(2); - dacl_ptr->size = cpu_to_le16(sizeof(struct smb_acl)); - dacl_ptr->num_aces = 0; - - if (!ppntsd) { - set_mode_dacl(user_ns, dacl_ptr, fattr); - } else { - struct smb_acl *ppdacl_ptr; - unsigned int dacl_offset = le32_to_cpu(ppntsd->dacloffset); - int ppdacl_size, ntacl_size = ppntsd_size - dacl_offset; - - if (!dacl_offset || - (dacl_offset + sizeof(struct smb_acl) > ppntsd_size)) - goto out; - - ppdacl_ptr = (struct smb_acl *)((char *)ppntsd + dacl_offset); - ppdacl_size = le16_to_cpu(ppdacl_ptr->size); - if (ppdacl_size > ntacl_size || - ppdacl_size < sizeof(struct smb_acl)) - goto out; - - set_ntacl_dacl(user_ns, dacl_ptr, ppdacl_ptr, - ntacl_size - sizeof(struct smb_acl), - nowner_sid_ptr, ngroup_sid_ptr, - fattr); - } - pntsd->dacloffset = cpu_to_le32(offset); - offset += le16_to_cpu(dacl_ptr->size); - } - -out: - kfree(nowner_sid_ptr); - kfree(ngroup_sid_ptr); - *secdesclen = offset; - return rc; -} - -static void smb_set_ace(struct smb_ace *ace, const struct smb_sid *sid, u8 type, - u8 flags, __le32 access_req) -{ - ace->type = type; - ace->flags = flags; - ace->access_req = access_req; - smb_copy_sid(&ace->sid, sid); - ace->size = cpu_to_le16(1 + 1 + 2 + 4 + 1 + 1 + 6 + (sid->num_subauth * 4)); -} - -int smb_inherit_dacl(struct ksmbd_conn *conn, - const struct path *path, - unsigned int uid, unsigned int gid) -{ - const struct smb_sid *psid, *creator = NULL; - struct smb_ace *parent_aces, *aces; - struct smb_acl *parent_pdacl; - struct smb_ntsd *parent_pntsd = NULL; - struct smb_sid owner_sid, group_sid; - struct dentry *parent = path->dentry->d_parent; - struct user_namespace *user_ns = mnt_user_ns(path->mnt); - int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0, pdacl_size; - int rc = 0, num_aces, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size; - char *aces_base; - bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode); - - pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns, - parent, &parent_pntsd); - if (pntsd_size <= 0) - return -ENOENT; - dacloffset = le32_to_cpu(parent_pntsd->dacloffset); - if (!dacloffset || (dacloffset + sizeof(struct smb_acl) > pntsd_size)) { - rc = -EINVAL; - goto free_parent_pntsd; - } - - parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset); - acl_len = pntsd_size - dacloffset; - num_aces = le32_to_cpu(parent_pdacl->num_aces); - pntsd_type = le16_to_cpu(parent_pntsd->type); - pdacl_size = le16_to_cpu(parent_pdacl->size); - - if (pdacl_size > acl_len || pdacl_size < sizeof(struct smb_acl)) { - rc = -EINVAL; - goto free_parent_pntsd; - } - - aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, GFP_KERNEL); - if (!aces_base) { - rc = -ENOMEM; - goto free_parent_pntsd; - } - - aces = (struct smb_ace *)aces_base; - parent_aces = (struct smb_ace *)((char *)parent_pdacl + - sizeof(struct smb_acl)); - aces_size = acl_len - sizeof(struct smb_acl); - - if (pntsd_type & DACL_AUTO_INHERITED) - inherited_flags = INHERITED_ACE; - - for (i = 0; i < num_aces; i++) { - int pace_size; - - if (offsetof(struct smb_ace, access_req) > aces_size) - break; - - pace_size = le16_to_cpu(parent_aces->size); - if (pace_size > aces_size) - break; - - aces_size -= pace_size; - - flags = parent_aces->flags; - if (!smb_inherit_flags(flags, is_dir)) - goto pass; - if (is_dir) { - flags &= ~(INHERIT_ONLY_ACE | INHERITED_ACE); - if (!(flags & CONTAINER_INHERIT_ACE)) - flags |= INHERIT_ONLY_ACE; - if (flags & NO_PROPAGATE_INHERIT_ACE) - flags = 0; - } else { - flags = 0; - } - - if (!compare_sids(&creator_owner, &parent_aces->sid)) { - creator = &creator_owner; - id_to_sid(uid, SIDOWNER, &owner_sid); - psid = &owner_sid; - } else if (!compare_sids(&creator_group, &parent_aces->sid)) { - creator = &creator_group; - id_to_sid(gid, SIDUNIX_GROUP, &group_sid); - psid = &group_sid; - } else { - creator = NULL; - psid = &parent_aces->sid; - } - - if (is_dir && creator && flags & CONTAINER_INHERIT_ACE) { - smb_set_ace(aces, psid, parent_aces->type, inherited_flags, - parent_aces->access_req); - nt_size += le16_to_cpu(aces->size); - ace_cnt++; - aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size)); - flags |= INHERIT_ONLY_ACE; - psid = creator; - } else if (is_dir && !(parent_aces->flags & NO_PROPAGATE_INHERIT_ACE)) { - psid = &parent_aces->sid; - } - - smb_set_ace(aces, psid, parent_aces->type, flags | inherited_flags, - parent_aces->access_req); - nt_size += le16_to_cpu(aces->size); - aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size)); - ace_cnt++; -pass: - parent_aces = (struct smb_ace *)((char *)parent_aces + pace_size); - } - - if (nt_size > 0) { - struct smb_ntsd *pntsd; - struct smb_acl *pdacl; - struct smb_sid *powner_sid = NULL, *pgroup_sid = NULL; - int powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size; - - if (parent_pntsd->osidoffset) { - powner_sid = (struct smb_sid *)((char *)parent_pntsd + - le32_to_cpu(parent_pntsd->osidoffset)); - powner_sid_size = 1 + 1 + 6 + (powner_sid->num_subauth * 4); - } - if (parent_pntsd->gsidoffset) { - pgroup_sid = (struct smb_sid *)((char *)parent_pntsd + - le32_to_cpu(parent_pntsd->gsidoffset)); - pgroup_sid_size = 1 + 1 + 6 + (pgroup_sid->num_subauth * 4); - } - - pntsd = kzalloc(sizeof(struct smb_ntsd) + powner_sid_size + - pgroup_sid_size + sizeof(struct smb_acl) + - nt_size, GFP_KERNEL); - if (!pntsd) { - rc = -ENOMEM; - goto free_aces_base; - } - - pntsd->revision = cpu_to_le16(1); - pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PRESENT); - if (le16_to_cpu(parent_pntsd->type) & DACL_AUTO_INHERITED) - pntsd->type |= cpu_to_le16(DACL_AUTO_INHERITED); - pntsd_size = sizeof(struct smb_ntsd); - pntsd->osidoffset = parent_pntsd->osidoffset; - pntsd->gsidoffset = parent_pntsd->gsidoffset; - pntsd->dacloffset = parent_pntsd->dacloffset; - - if (pntsd->osidoffset) { - struct smb_sid *owner_sid = (struct smb_sid *)((char *)pntsd + - le32_to_cpu(pntsd->osidoffset)); - memcpy(owner_sid, powner_sid, powner_sid_size); - pntsd_size += powner_sid_size; - } - - if (pntsd->gsidoffset) { - struct smb_sid *group_sid = (struct smb_sid *)((char *)pntsd + - le32_to_cpu(pntsd->gsidoffset)); - memcpy(group_sid, pgroup_sid, pgroup_sid_size); - pntsd_size += pgroup_sid_size; - } - - if (pntsd->dacloffset) { - struct smb_ace *pace; - - pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset)); - pdacl->revision = cpu_to_le16(2); - pdacl->size = cpu_to_le16(sizeof(struct smb_acl) + nt_size); - pdacl->num_aces = cpu_to_le32(ace_cnt); - pace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); - memcpy(pace, aces_base, nt_size); - pntsd_size += sizeof(struct smb_acl) + nt_size; - } - - ksmbd_vfs_set_sd_xattr(conn, user_ns, - path->dentry, pntsd, pntsd_size); - kfree(pntsd); - } - -free_aces_base: - kfree(aces_base); -free_parent_pntsd: - kfree(parent_pntsd); - return rc; -} - -bool smb_inherit_flags(int flags, bool is_dir) -{ - if (!is_dir) - return (flags & OBJECT_INHERIT_ACE) != 0; - - if (flags & OBJECT_INHERIT_ACE && !(flags & NO_PROPAGATE_INHERIT_ACE)) - return true; - - if (flags & CONTAINER_INHERIT_ACE) - return true; - return false; -} - -int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, - __le32 *pdaccess, int uid) -{ - struct user_namespace *user_ns = mnt_user_ns(path->mnt); - struct smb_ntsd *pntsd = NULL; - struct smb_acl *pdacl; - struct posix_acl *posix_acls; - int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset; - struct smb_sid sid; - int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE); - struct smb_ace *ace; - int i, found = 0; - unsigned int access_bits = 0; - struct smb_ace *others_ace = NULL; - struct posix_acl_entry *pa_entry; - unsigned int sid_type = SIDOWNER; - unsigned short ace_size; - - ksmbd_debug(SMB, "check permission using windows acl\n"); - pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns, - path->dentry, &pntsd); - if (pntsd_size <= 0 || !pntsd) - goto err_out; - - dacl_offset = le32_to_cpu(pntsd->dacloffset); - if (!dacl_offset || - (dacl_offset + sizeof(struct smb_acl) > pntsd_size)) - goto err_out; - - pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset)); - acl_size = pntsd_size - dacl_offset; - pdacl_size = le16_to_cpu(pdacl->size); - - if (pdacl_size > acl_size || pdacl_size < sizeof(struct smb_acl)) - goto err_out; - - if (!pdacl->num_aces) { - if (!(pdacl_size - sizeof(struct smb_acl)) && - *pdaccess & ~(FILE_READ_CONTROL_LE | FILE_WRITE_DAC_LE)) { - rc = -EACCES; - goto err_out; - } - goto err_out; - } - - if (*pdaccess & FILE_MAXIMAL_ACCESS_LE) { - granted = READ_CONTROL | WRITE_DAC | FILE_READ_ATTRIBUTES | - DELETE; - - ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); - aces_size = acl_size - sizeof(struct smb_acl); - for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) { - if (offsetof(struct smb_ace, access_req) > aces_size) - break; - ace_size = le16_to_cpu(ace->size); - if (ace_size > aces_size) - break; - aces_size -= ace_size; - granted |= le32_to_cpu(ace->access_req); - ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size)); - } - - if (!pdacl->num_aces) - granted = GENERIC_ALL_FLAGS; - } - - if (!uid) - sid_type = SIDUNIX_USER; - id_to_sid(uid, sid_type, &sid); - - ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); - aces_size = acl_size - sizeof(struct smb_acl); - for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) { - if (offsetof(struct smb_ace, access_req) > aces_size) - break; - ace_size = le16_to_cpu(ace->size); - if (ace_size > aces_size) - break; - aces_size -= ace_size; - - if (!compare_sids(&sid, &ace->sid) || - !compare_sids(&sid_unix_NFS_mode, &ace->sid)) { - found = 1; - break; - } - if (!compare_sids(&sid_everyone, &ace->sid)) - others_ace = ace; - - ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size)); - } - - if (*pdaccess & FILE_MAXIMAL_ACCESS_LE && found) { - granted = READ_CONTROL | WRITE_DAC | FILE_READ_ATTRIBUTES | - DELETE; - - granted |= le32_to_cpu(ace->access_req); - - if (!pdacl->num_aces) - granted = GENERIC_ALL_FLAGS; - } - - if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { - posix_acls = get_acl(d_inode(path->dentry), ACL_TYPE_ACCESS); - if (posix_acls && !found) { - unsigned int id = -1; - - pa_entry = posix_acls->a_entries; - for (i = 0; i < posix_acls->a_count; i++, pa_entry++) { - if (pa_entry->e_tag == ACL_USER) - id = posix_acl_uid_translate(user_ns, pa_entry); - else if (pa_entry->e_tag == ACL_GROUP) - id = posix_acl_gid_translate(user_ns, pa_entry); - else - continue; - - if (id == uid) { - mode_to_access_flags(pa_entry->e_perm, - 0777, - &access_bits); - if (!access_bits) - access_bits = - SET_MINIMUM_RIGHTS; - posix_acl_release(posix_acls); - goto check_access_bits; - } - } - } - if (posix_acls) - posix_acl_release(posix_acls); - } - - if (!found) { - if (others_ace) { - ace = others_ace; - } else { - ksmbd_debug(SMB, "Can't find corresponding sid\n"); - rc = -EACCES; - goto err_out; - } - } - - switch (ace->type) { - case ACCESS_ALLOWED_ACE_TYPE: - access_bits = le32_to_cpu(ace->access_req); - break; - case ACCESS_DENIED_ACE_TYPE: - case ACCESS_DENIED_CALLBACK_ACE_TYPE: - access_bits = le32_to_cpu(~ace->access_req); - break; - } - -check_access_bits: - if (granted & - ~(access_bits | FILE_READ_ATTRIBUTES | READ_CONTROL | WRITE_DAC | DELETE)) { - ksmbd_debug(SMB, "Access denied with winACL, granted : %x, access_req : %x\n", - granted, le32_to_cpu(ace->access_req)); - rc = -EACCES; - goto err_out; - } - - *pdaccess = cpu_to_le32(granted); -err_out: - kfree(pntsd); - return rc; -} - -int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, - const struct path *path, struct smb_ntsd *pntsd, int ntsd_len, - bool type_check) -{ - int rc; - struct smb_fattr fattr = {{0}}; - struct inode *inode = d_inode(path->dentry); - struct user_namespace *user_ns = mnt_user_ns(path->mnt); - struct iattr newattrs; - - fattr.cf_uid = INVALID_UID; - fattr.cf_gid = INVALID_GID; - fattr.cf_mode = inode->i_mode; - - rc = parse_sec_desc(user_ns, pntsd, ntsd_len, &fattr); - if (rc) - goto out; - - newattrs.ia_valid = ATTR_CTIME; - if (!uid_eq(fattr.cf_uid, INVALID_UID)) { - newattrs.ia_valid |= ATTR_UID; - newattrs.ia_uid = fattr.cf_uid; - } - if (!gid_eq(fattr.cf_gid, INVALID_GID)) { - newattrs.ia_valid |= ATTR_GID; - newattrs.ia_gid = fattr.cf_gid; - } - newattrs.ia_valid |= ATTR_MODE; - newattrs.ia_mode = (inode->i_mode & ~0777) | (fattr.cf_mode & 0777); - - ksmbd_vfs_remove_acl_xattrs(user_ns, path->dentry); - /* Update posix acls */ - if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) { - rc = set_posix_acl(user_ns, inode, - ACL_TYPE_ACCESS, fattr.cf_acls); - if (rc < 0) - ksmbd_debug(SMB, - "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", - rc); - if (S_ISDIR(inode->i_mode) && fattr.cf_dacls) { - rc = set_posix_acl(user_ns, inode, - ACL_TYPE_DEFAULT, fattr.cf_dacls); - if (rc) - ksmbd_debug(SMB, - "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", - rc); - } - } - - inode_lock(inode); - rc = notify_change(user_ns, path->dentry, &newattrs, NULL); - inode_unlock(inode); - if (rc) - goto out; - - /* Check it only calling from SD BUFFER context */ - if (type_check && !(le16_to_cpu(pntsd->type) & DACL_PRESENT)) - goto out; - - if (test_share_config_flag(tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) { - /* Update WinACL in xattr */ - ksmbd_vfs_remove_sd_xattrs(user_ns, path->dentry); - ksmbd_vfs_set_sd_xattr(conn, user_ns, - path->dentry, pntsd, ntsd_len); - } - -out: - posix_acl_release(fattr.cf_acls); - posix_acl_release(fattr.cf_dacls); - mark_inode_dirty(inode); - return rc; -} - -void ksmbd_init_domain(u32 *sub_auth) -{ - int i; - - memcpy(&server_conf.domain_sid, &domain, sizeof(struct smb_sid)); - for (i = 0; i < 3; ++i) - server_conf.domain_sid.sub_auth[i + 1] = cpu_to_le32(sub_auth[i]); -} diff --git a/fs/ksmbd/smbacl.h b/fs/ksmbd/smbacl.h deleted file mode 100644 index 618f2e0236b3..000000000000 --- a/fs/ksmbd/smbacl.h +++ /dev/null @@ -1,238 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (c) International Business Machines Corp., 2007 - * Author(s): Steve French (sfrench@us.ibm.com) - * Modified by Namjae Jeon (linkinjeon@kernel.org) - */ - -#ifndef _SMBACL_H -#define _SMBACL_H - -#include <linux/fs.h> -#include <linux/namei.h> -#include <linux/posix_acl.h> -#include <linux/mnt_idmapping.h> - -#include "mgmt/tree_connect.h" - -#define NUM_AUTHS (6) /* number of authority fields */ -#define SID_MAX_SUB_AUTHORITIES (15) /* max number of sub authority fields */ - -/* - * ACE types - see MS-DTYP 2.4.4.1 - */ -enum { - ACCESS_ALLOWED, - ACCESS_DENIED, -}; - -/* - * Security ID types - */ -enum { - SIDOWNER = 1, - SIDGROUP, - SIDCREATOR_OWNER, - SIDCREATOR_GROUP, - SIDUNIX_USER, - SIDUNIX_GROUP, - SIDNFS_USER, - SIDNFS_GROUP, - SIDNFS_MODE, -}; - -/* Revision for ACLs */ -#define SD_REVISION 1 - -/* Control flags for Security Descriptor */ -#define OWNER_DEFAULTED 0x0001 -#define GROUP_DEFAULTED 0x0002 -#define DACL_PRESENT 0x0004 -#define DACL_DEFAULTED 0x0008 -#define SACL_PRESENT 0x0010 -#define SACL_DEFAULTED 0x0020 -#define DACL_TRUSTED 0x0040 -#define SERVER_SECURITY 0x0080 -#define DACL_AUTO_INHERIT_REQ 0x0100 -#define SACL_AUTO_INHERIT_REQ 0x0200 -#define DACL_AUTO_INHERITED 0x0400 -#define SACL_AUTO_INHERITED 0x0800 -#define DACL_PROTECTED 0x1000 -#define SACL_PROTECTED 0x2000 -#define RM_CONTROL_VALID 0x4000 -#define SELF_RELATIVE 0x8000 - -/* ACE types - see MS-DTYP 2.4.4.1 */ -#define ACCESS_ALLOWED_ACE_TYPE 0x00 -#define ACCESS_DENIED_ACE_TYPE 0x01 -#define SYSTEM_AUDIT_ACE_TYPE 0x02 -#define SYSTEM_ALARM_ACE_TYPE 0x03 -#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE 0x04 -#define ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05 -#define ACCESS_DENIED_OBJECT_ACE_TYPE 0x06 -#define SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x07 -#define SYSTEM_ALARM_OBJECT_ACE_TYPE 0x08 -#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE 0x09 -#define ACCESS_DENIED_CALLBACK_ACE_TYPE 0x0A -#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE 0x0B -#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE 0x0C -#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE 0x0D -#define SYSTEM_ALARM_CALLBACK_ACE_TYPE 0x0E /* Reserved */ -#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE 0x0F -#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 0x10 /* reserved */ -#define SYSTEM_MANDATORY_LABEL_ACE_TYPE 0x11 -#define SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE 0x12 -#define SYSTEM_SCOPED_POLICY_ID_ACE_TYPE 0x13 - -/* ACE flags */ -#define OBJECT_INHERIT_ACE 0x01 -#define CONTAINER_INHERIT_ACE 0x02 -#define NO_PROPAGATE_INHERIT_ACE 0x04 -#define INHERIT_ONLY_ACE 0x08 -#define INHERITED_ACE 0x10 -#define SUCCESSFUL_ACCESS_ACE_FLAG 0x40 -#define FAILED_ACCESS_ACE_FLAG 0x80 - -/* - * Maximum size of a string representation of a SID: - * - * The fields are unsigned values in decimal. So: - * - * u8: max 3 bytes in decimal - * u32: max 10 bytes in decimal - * - * "S-" + 3 bytes for version field + 15 for authority field + NULL terminator - * - * For authority field, max is when all 6 values are non-zero and it must be - * represented in hex. So "-0x" + 12 hex digits. - * - * Add 11 bytes for each subauthority field (10 bytes each + 1 for '-') - */ -#define SID_STRING_BASE_SIZE (2 + 3 + 15 + 1) -#define SID_STRING_SUBAUTH_SIZE (11) /* size of a single subauth string */ - -#define DOMAIN_USER_RID_LE cpu_to_le32(513) - -struct ksmbd_conn; - -struct smb_ntsd { - __le16 revision; /* revision level */ - __le16 type; - __le32 osidoffset; - __le32 gsidoffset; - __le32 sacloffset; - __le32 dacloffset; -} __packed; - -struct smb_sid { - __u8 revision; /* revision level */ - __u8 num_subauth; - __u8 authority[NUM_AUTHS]; - __le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */ -} __packed; - -/* size of a struct cifs_sid, sans sub_auth array */ -#define CIFS_SID_BASE_SIZE (1 + 1 + NUM_AUTHS) - -struct smb_acl { - __le16 revision; /* revision level */ - __le16 size; - __le32 num_aces; -} __packed; - -struct smb_ace { - __u8 type; - __u8 flags; - __le16 size; - __le32 access_req; - struct smb_sid sid; /* ie UUID of user or group who gets these perms */ -} __packed; - -struct smb_fattr { - kuid_t cf_uid; - kgid_t cf_gid; - umode_t cf_mode; - __le32 daccess; - struct posix_acl *cf_acls; - struct posix_acl *cf_dacls; -}; - -struct posix_ace_state { - u32 allow; - u32 deny; -}; - -struct posix_user_ace_state { - union { - kuid_t uid; - kgid_t gid; - }; - struct posix_ace_state perms; -}; - -struct posix_ace_state_array { - int n; - struct posix_user_ace_state aces[]; -}; - -/* - * while processing the nfsv4 ace, this maintains the partial permissions - * calculated so far: - */ - -struct posix_acl_state { - struct posix_ace_state owner; - struct posix_ace_state group; - struct posix_ace_state other; - struct posix_ace_state everyone; - struct posix_ace_state mask; /* deny unused in this case */ - struct posix_ace_state_array *users; - struct posix_ace_state_array *groups; -}; - -int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd, - int acl_len, struct smb_fattr *fattr); -int build_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd, - struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info, - __u32 *secdesclen, struct smb_fattr *fattr); -int init_acl_state(struct posix_acl_state *state, int cnt); -void free_acl_state(struct posix_acl_state *state); -void posix_state_to_acl(struct posix_acl_state *state, - struct posix_acl_entry *pace); -int compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid); -bool smb_inherit_flags(int flags, bool is_dir); -int smb_inherit_dacl(struct ksmbd_conn *conn, const struct path *path, - unsigned int uid, unsigned int gid); -int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, - __le32 *pdaccess, int uid); -int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, - const struct path *path, struct smb_ntsd *pntsd, int ntsd_len, - bool type_check); -void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid); -void ksmbd_init_domain(u32 *sub_auth); - -static inline uid_t posix_acl_uid_translate(struct user_namespace *mnt_userns, - struct posix_acl_entry *pace) -{ - vfsuid_t vfsuid; - - /* If this is an idmapped mount, apply the idmapping. */ - vfsuid = make_vfsuid(mnt_userns, &init_user_ns, pace->e_uid); - - /* Translate the kuid into a userspace id ksmbd would see. */ - return from_kuid(&init_user_ns, vfsuid_into_kuid(vfsuid)); -} - -static inline gid_t posix_acl_gid_translate(struct user_namespace *mnt_userns, - struct posix_acl_entry *pace) -{ - vfsgid_t vfsgid; - - /* If this is an idmapped mount, apply the idmapping. */ - vfsgid = make_vfsgid(mnt_userns, &init_user_ns, pace->e_gid); - - /* Translate the kgid into a userspace id ksmbd would see. */ - return from_kgid(&init_user_ns, vfsgid_into_kgid(vfsgid)); -} - -#endif /* _SMBACL_H */ diff --git a/fs/ksmbd/smbfsctl.h b/fs/ksmbd/smbfsctl.h deleted file mode 100644 index b98418aae20c..000000000000 --- a/fs/ksmbd/smbfsctl.h +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * fs/cifs/smbfsctl.h: SMB, CIFS, SMB2 FSCTL definitions - * - * Copyright (c) International Business Machines Corp., 2002,2009 - * Author(s): Steve French (sfrench@us.ibm.com) - */ - -/* IOCTL information */ -/* - * List of ioctl/fsctl function codes that are or could be useful in the - * future to remote clients like cifs or SMB2 client. There is probably - * a slightly larger set of fsctls that NTFS local filesystem could handle, - * including the seven below that we do not have struct definitions for. - * Even with protocol definitions for most of these now available, we still - * need to do some experimentation to identify which are practical to do - * remotely. Some of the following, such as the encryption/compression ones - * could be invoked from tools via a specialized hook into the VFS rather - * than via the standard vfs entry points - */ - -#ifndef __KSMBD_SMBFSCTL_H -#define __KSMBD_SMBFSCTL_H - -#define FSCTL_DFS_GET_REFERRALS 0x00060194 -#define FSCTL_DFS_GET_REFERRALS_EX 0x000601B0 -#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000 -#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004 -#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008 -#define FSCTL_LOCK_VOLUME 0x00090018 -#define FSCTL_UNLOCK_VOLUME 0x0009001C -#define FSCTL_IS_PATHNAME_VALID 0x0009002C /* BB add struct */ -#define FSCTL_GET_COMPRESSION 0x0009003C /* BB add struct */ -#define FSCTL_SET_COMPRESSION 0x0009C040 /* BB add struct */ -#define FSCTL_QUERY_FAT_BPB 0x00090058 /* BB add struct */ -/* Verify the next FSCTL number, we had it as 0x00090090 before */ -#define FSCTL_FILESYSTEM_GET_STATS 0x00090060 /* BB add struct */ -#define FSCTL_GET_NTFS_VOLUME_DATA 0x00090064 /* BB add struct */ -#define FSCTL_GET_RETRIEVAL_POINTERS 0x00090073 /* BB add struct */ -#define FSCTL_IS_VOLUME_DIRTY 0x00090078 /* BB add struct */ -#define FSCTL_ALLOW_EXTENDED_DASD_IO 0x00090083 /* BB add struct */ -#define FSCTL_REQUEST_FILTER_OPLOCK 0x0009008C -#define FSCTL_FIND_FILES_BY_SID 0x0009008F /* BB add struct */ -#define FSCTL_SET_OBJECT_ID 0x00090098 /* BB add struct */ -#define FSCTL_GET_OBJECT_ID 0x0009009C /* BB add struct */ -#define FSCTL_DELETE_OBJECT_ID 0x000900A0 /* BB add struct */ -#define FSCTL_SET_REPARSE_POINT 0x000900A4 /* BB add struct */ -#define FSCTL_GET_REPARSE_POINT 0x000900A8 /* BB add struct */ -#define FSCTL_DELETE_REPARSE_POINT 0x000900AC /* BB add struct */ -#define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */ -#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */ -#define FSCTL_SET_SPARSE 0x000900C4 /* BB add struct */ -#define FSCTL_SET_ZERO_DATA 0x000980C8 /* BB add struct */ -#define FSCTL_SET_ENCRYPTION 0x000900D7 /* BB add struct */ -#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB /* BB add struct */ -#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF /* BB add struct */ -#define FSCTL_READ_RAW_ENCRYPTED 0x000900E3 /* BB add struct */ -#define FSCTL_READ_FILE_USN_DATA 0x000900EB /* BB add struct */ -#define FSCTL_WRITE_USN_CLOSE_RECORD 0x000900EF /* BB add struct */ -#define FSCTL_SIS_COPYFILE 0x00090100 /* BB add struct */ -#define FSCTL_RECALL_FILE 0x00090117 /* BB add struct */ -#define FSCTL_QUERY_SPARING_INFO 0x00090138 /* BB add struct */ -#define FSCTL_SET_ZERO_ON_DEALLOC 0x00090194 /* BB add struct */ -#define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */ -#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF /* BB add struct */ -#define FSCTL_SET_DEFECT_MANAGEMENT 0x00098134 /* BB add struct */ -#define FSCTL_DUPLICATE_EXTENTS_TO_FILE 0x00098344 -#define FSCTL_SIS_LINK_FILES 0x0009C104 -#define FSCTL_PIPE_PEEK 0x0011400C /* BB add struct */ -#define FSCTL_PIPE_TRANSCEIVE 0x0011C017 /* BB add struct */ -/* strange that the number for this op is not sequential with previous op */ -#define FSCTL_PIPE_WAIT 0x00110018 /* BB add struct */ -#define FSCTL_REQUEST_RESUME_KEY 0x00140078 -#define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */ -#define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */ -#define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 -#define FSCTL_QUERY_NETWORK_INTERFACE_INFO 0x001401FC -#define FSCTL_COPYCHUNK 0x001440F2 -#define FSCTL_COPYCHUNK_WRITE 0x001480F2 - -#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 -#define IO_REPARSE_TAG_HSM 0xC0000004 -#define IO_REPARSE_TAG_SIS 0x80000007 - -/* WSL reparse tags */ -#define IO_REPARSE_TAG_LX_SYMLINK_LE cpu_to_le32(0xA000001D) -#define IO_REPARSE_TAG_AF_UNIX_LE cpu_to_le32(0x80000023) -#define IO_REPARSE_TAG_LX_FIFO_LE cpu_to_le32(0x80000024) -#define IO_REPARSE_TAG_LX_CHR_LE cpu_to_le32(0x80000025) -#define IO_REPARSE_TAG_LX_BLK_LE cpu_to_le32(0x80000026) -#endif /* __KSMBD_SMBFSCTL_H */ diff --git a/fs/ksmbd/smbstatus.h b/fs/ksmbd/smbstatus.h deleted file mode 100644 index 108a8b6ed24a..000000000000 --- a/fs/ksmbd/smbstatus.h +++ /dev/null @@ -1,1822 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * fs/cifs/smb2status.h - * - * SMB2 Status code (network error) definitions - * Definitions are from MS-ERREF - * - * Copyright (c) International Business Machines Corp., 2009,2011 - * Author(s): Steve French (sfrench@us.ibm.com) - */ - -/* - * 0 1 2 3 4 5 6 7 8 9 0 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F - * SEV C N <-------Facility--------> <------Error Status Code------> - * - * C is set if "customer defined" error, N bit is reserved and MBZ - */ - -#define STATUS_SEVERITY_SUCCESS cpu_to_le32(0x0000) -#define STATUS_SEVERITY_INFORMATIONAL cpu_to_le32(0x0001) -#define STATUS_SEVERITY_WARNING cpu_to_le32(0x0002) -#define STATUS_SEVERITY_ERROR cpu_to_le32(0x0003) - -struct ntstatus { - /* Facility is the high 12 bits of the following field */ - __le32 Facility; /* low 2 bits Severity, next is Customer, then rsrvd */ - __le32 Code; -}; - -#define STATUS_SUCCESS 0x00000000 -#define STATUS_WAIT_0 cpu_to_le32(0x00000000) -#define STATUS_WAIT_1 cpu_to_le32(0x00000001) -#define STATUS_WAIT_2 cpu_to_le32(0x00000002) -#define STATUS_WAIT_3 cpu_to_le32(0x00000003) -#define STATUS_WAIT_63 cpu_to_le32(0x0000003F) -#define STATUS_ABANDONED cpu_to_le32(0x00000080) -#define STATUS_ABANDONED_WAIT_0 cpu_to_le32(0x00000080) -#define STATUS_ABANDONED_WAIT_63 cpu_to_le32(0x000000BF) -#define STATUS_USER_APC cpu_to_le32(0x000000C0) -#define STATUS_KERNEL_APC cpu_to_le32(0x00000100) -#define STATUS_ALERTED cpu_to_le32(0x00000101) -#define STATUS_TIMEOUT cpu_to_le32(0x00000102) -#define STATUS_PENDING cpu_to_le32(0x00000103) -#define STATUS_REPARSE cpu_to_le32(0x00000104) -#define STATUS_MORE_ENTRIES cpu_to_le32(0x00000105) -#define STATUS_NOT_ALL_ASSIGNED cpu_to_le32(0x00000106) -#define STATUS_SOME_NOT_MAPPED cpu_to_le32(0x00000107) -#define STATUS_OPLOCK_BREAK_IN_PROGRESS cpu_to_le32(0x00000108) -#define STATUS_VOLUME_MOUNTED cpu_to_le32(0x00000109) -#define STATUS_RXACT_COMMITTED cpu_to_le32(0x0000010A) -#define STATUS_NOTIFY_CLEANUP cpu_to_le32(0x0000010B) -#define STATUS_NOTIFY_ENUM_DIR cpu_to_le32(0x0000010C) -#define STATUS_NO_QUOTAS_FOR_ACCOUNT cpu_to_le32(0x0000010D) -#define STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED cpu_to_le32(0x0000010E) -#define STATUS_PAGE_FAULT_TRANSITION cpu_to_le32(0x00000110) -#define STATUS_PAGE_FAULT_DEMAND_ZERO cpu_to_le32(0x00000111) -#define STATUS_PAGE_FAULT_COPY_ON_WRITE cpu_to_le32(0x00000112) -#define STATUS_PAGE_FAULT_GUARD_PAGE cpu_to_le32(0x00000113) -#define STATUS_PAGE_FAULT_PAGING_FILE cpu_to_le32(0x00000114) -#define STATUS_CACHE_PAGE_LOCKED cpu_to_le32(0x00000115) -#define STATUS_CRASH_DUMP cpu_to_le32(0x00000116) -#define STATUS_BUFFER_ALL_ZEROS cpu_to_le32(0x00000117) -#define STATUS_REPARSE_OBJECT cpu_to_le32(0x00000118) -#define STATUS_RESOURCE_REQUIREMENTS_CHANGED cpu_to_le32(0x00000119) -#define STATUS_TRANSLATION_COMPLETE cpu_to_le32(0x00000120) -#define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY cpu_to_le32(0x00000121) -#define STATUS_NOTHING_TO_TERMINATE cpu_to_le32(0x00000122) -#define STATUS_PROCESS_NOT_IN_JOB cpu_to_le32(0x00000123) -#define STATUS_PROCESS_IN_JOB cpu_to_le32(0x00000124) -#define STATUS_VOLSNAP_HIBERNATE_READY cpu_to_le32(0x00000125) -#define STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY cpu_to_le32(0x00000126) -#define STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED cpu_to_le32(0x00000127) -#define STATUS_INTERRUPT_STILL_CONNECTED cpu_to_le32(0x00000128) -#define STATUS_PROCESS_CLONED cpu_to_le32(0x00000129) -#define STATUS_FILE_LOCKED_WITH_ONLY_READERS cpu_to_le32(0x0000012A) -#define STATUS_FILE_LOCKED_WITH_WRITERS cpu_to_le32(0x0000012B) -#define STATUS_RESOURCEMANAGER_READ_ONLY cpu_to_le32(0x00000202) -#define STATUS_WAIT_FOR_OPLOCK cpu_to_le32(0x00000367) -#define DBG_EXCEPTION_HANDLED cpu_to_le32(0x00010001) -#define DBG_CONTINUE cpu_to_le32(0x00010002) -#define STATUS_FLT_IO_COMPLETE cpu_to_le32(0x001C0001) -#define STATUS_OBJECT_NAME_EXISTS cpu_to_le32(0x40000000) -#define STATUS_THREAD_WAS_SUSPENDED cpu_to_le32(0x40000001) -#define STATUS_WORKING_SET_LIMIT_RANGE cpu_to_le32(0x40000002) -#define STATUS_IMAGE_NOT_AT_BASE cpu_to_le32(0x40000003) -#define STATUS_RXACT_STATE_CREATED cpu_to_le32(0x40000004) -#define STATUS_SEGMENT_NOTIFICATION cpu_to_le32(0x40000005) -#define STATUS_LOCAL_USER_SESSION_KEY cpu_to_le32(0x40000006) -#define STATUS_BAD_CURRENT_DIRECTORY cpu_to_le32(0x40000007) -#define STATUS_SERIAL_MORE_WRITES cpu_to_le32(0x40000008) -#define STATUS_REGISTRY_RECOVERED cpu_to_le32(0x40000009) -#define STATUS_FT_READ_RECOVERY_FROM_BACKUP cpu_to_le32(0x4000000A) -#define STATUS_FT_WRITE_RECOVERY cpu_to_le32(0x4000000B) -#define STATUS_SERIAL_COUNTER_TIMEOUT cpu_to_le32(0x4000000C) -#define STATUS_NULL_LM_PASSWORD cpu_to_le32(0x4000000D) -#define STATUS_IMAGE_MACHINE_TYPE_MISMATCH cpu_to_le32(0x4000000E) -#define STATUS_RECEIVE_PARTIAL cpu_to_le32(0x4000000F) -#define STATUS_RECEIVE_EXPEDITED cpu_to_le32(0x40000010) -#define STATUS_RECEIVE_PARTIAL_EXPEDITED cpu_to_le32(0x40000011) -#define STATUS_EVENT_DONE cpu_to_le32(0x40000012) -#define STATUS_EVENT_PENDING cpu_to_le32(0x40000013) -#define STATUS_CHECKING_FILE_SYSTEM cpu_to_le32(0x40000014) -#define STATUS_FATAL_APP_EXIT cpu_to_le32(0x40000015) -#define STATUS_PREDEFINED_HANDLE cpu_to_le32(0x40000016) -#define STATUS_WAS_UNLOCKED cpu_to_le32(0x40000017) -#define STATUS_SERVICE_NOTIFICATION cpu_to_le32(0x40000018) -#define STATUS_WAS_LOCKED cpu_to_le32(0x40000019) -#define STATUS_LOG_HARD_ERROR cpu_to_le32(0x4000001A) -#define STATUS_ALREADY_WIN32 cpu_to_le32(0x4000001B) -#define STATUS_WX86_UNSIMULATE cpu_to_le32(0x4000001C) -#define STATUS_WX86_CONTINUE cpu_to_le32(0x4000001D) -#define STATUS_WX86_SINGLE_STEP cpu_to_le32(0x4000001E) -#define STATUS_WX86_BREAKPOINT cpu_to_le32(0x4000001F) -#define STATUS_WX86_EXCEPTION_CONTINUE cpu_to_le32(0x40000020) -#define STATUS_WX86_EXCEPTION_LASTCHANCE cpu_to_le32(0x40000021) -#define STATUS_WX86_EXCEPTION_CHAIN cpu_to_le32(0x40000022) -#define STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE cpu_to_le32(0x40000023) -#define STATUS_NO_YIELD_PERFORMED cpu_to_le32(0x40000024) -#define STATUS_TIMER_RESUME_IGNORED cpu_to_le32(0x40000025) -#define STATUS_ARBITRATION_UNHANDLED cpu_to_le32(0x40000026) -#define STATUS_CARDBUS_NOT_SUPPORTED cpu_to_le32(0x40000027) -#define STATUS_WX86_CREATEWX86TIB cpu_to_le32(0x40000028) -#define STATUS_MP_PROCESSOR_MISMATCH cpu_to_le32(0x40000029) -#define STATUS_HIBERNATED cpu_to_le32(0x4000002A) -#define STATUS_RESUME_HIBERNATION cpu_to_le32(0x4000002B) -#define STATUS_FIRMWARE_UPDATED cpu_to_le32(0x4000002C) -#define STATUS_DRIVERS_LEAKING_LOCKED_PAGES cpu_to_le32(0x4000002D) -#define STATUS_MESSAGE_RETRIEVED cpu_to_le32(0x4000002E) -#define STATUS_SYSTEM_POWERSTATE_TRANSITION cpu_to_le32(0x4000002F) -#define STATUS_ALPC_CHECK_COMPLETION_LIST cpu_to_le32(0x40000030) -#define STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION cpu_to_le32(0x40000031) -#define STATUS_ACCESS_AUDIT_BY_POLICY cpu_to_le32(0x40000032) -#define STATUS_ABANDON_HIBERFILE cpu_to_le32(0x40000033) -#define STATUS_BIZRULES_NOT_ENABLED cpu_to_le32(0x40000034) -#define STATUS_WAKE_SYSTEM cpu_to_le32(0x40000294) -#define STATUS_DS_SHUTTING_DOWN cpu_to_le32(0x40000370) -#define DBG_REPLY_LATER cpu_to_le32(0x40010001) -#define DBG_UNABLE_TO_PROVIDE_HANDLE cpu_to_le32(0x40010002) -#define DBG_TERMINATE_THREAD cpu_to_le32(0x40010003) -#define DBG_TERMINATE_PROCESS cpu_to_le32(0x40010004) -#define DBG_CONTROL_C cpu_to_le32(0x40010005) -#define DBG_PRINTEXCEPTION_C cpu_to_le32(0x40010006) -#define DBG_RIPEXCEPTION cpu_to_le32(0x40010007) -#define DBG_CONTROL_BREAK cpu_to_le32(0x40010008) -#define DBG_COMMAND_EXCEPTION cpu_to_le32(0x40010009) -#define RPC_NT_UUID_LOCAL_ONLY cpu_to_le32(0x40020056) -#define RPC_NT_SEND_INCOMPLETE cpu_to_le32(0x400200AF) -#define STATUS_CTX_CDM_CONNECT cpu_to_le32(0x400A0004) -#define STATUS_CTX_CDM_DISCONNECT cpu_to_le32(0x400A0005) -#define STATUS_SXS_RELEASE_ACTIVATION_CONTEXT cpu_to_le32(0x4015000D) -#define STATUS_RECOVERY_NOT_NEEDED cpu_to_le32(0x40190034) -#define STATUS_RM_ALREADY_STARTED cpu_to_le32(0x40190035) -#define STATUS_LOG_NO_RESTART cpu_to_le32(0x401A000C) -#define STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST cpu_to_le32(0x401B00EC) -#define STATUS_GRAPHICS_PARTIAL_DATA_POPULATED cpu_to_le32(0x401E000A) -#define STATUS_GRAPHICS_DRIVER_MISMATCH cpu_to_le32(0x401E0117) -#define STATUS_GRAPHICS_MODE_NOT_PINNED cpu_to_le32(0x401E0307) -#define STATUS_GRAPHICS_NO_PREFERRED_MODE cpu_to_le32(0x401E031E) -#define STATUS_GRAPHICS_DATASET_IS_EMPTY cpu_to_le32(0x401E034B) -#define STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET cpu_to_le32(0x401E034C) -#define STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED \ - cpu_to_le32(0x401E0351) -#define STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS cpu_to_le32(0x401E042F) -#define STATUS_GRAPHICS_LEADLINK_START_DEFERRED cpu_to_le32(0x401E0437) -#define STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY cpu_to_le32(0x401E0439) -#define STATUS_GRAPHICS_START_DEFERRED cpu_to_le32(0x401E043A) -#define STATUS_NDIS_INDICATION_REQUIRED cpu_to_le32(0x40230001) -#define STATUS_GUARD_PAGE_VIOLATION cpu_to_le32(0x80000001) -#define STATUS_DATATYPE_MISALIGNMENT cpu_to_le32(0x80000002) -#define STATUS_BREAKPOINT cpu_to_le32(0x80000003) -#define STATUS_SINGLE_STEP cpu_to_le32(0x80000004) -#define STATUS_BUFFER_OVERFLOW cpu_to_le32(0x80000005) -#define STATUS_NO_MORE_FILES cpu_to_le32(0x80000006) -#define STATUS_WAKE_SYSTEM_DEBUGGER cpu_to_le32(0x80000007) -#define STATUS_HANDLES_CLOSED cpu_to_le32(0x8000000A) -#define STATUS_NO_INHERITANCE cpu_to_le32(0x8000000B) -#define STATUS_GUID_SUBSTITUTION_MADE cpu_to_le32(0x8000000C) -#define STATUS_PARTIAL_COPY cpu_to_le32(0x8000000D) -#define STATUS_DEVICE_PAPER_EMPTY cpu_to_le32(0x8000000E) -#define STATUS_DEVICE_POWERED_OFF cpu_to_le32(0x8000000F) -#define STATUS_DEVICE_OFF_LINE cpu_to_le32(0x80000010) -#define STATUS_DEVICE_BUSY cpu_to_le32(0x80000011) -#define STATUS_NO_MORE_EAS cpu_to_le32(0x80000012) -#define STATUS_INVALID_EA_NAME cpu_to_le32(0x80000013) -#define STATUS_EA_LIST_INCONSISTENT cpu_to_le32(0x80000014) -#define STATUS_INVALID_EA_FLAG cpu_to_le32(0x80000015) -#define STATUS_VERIFY_REQUIRED cpu_to_le32(0x80000016) -#define STATUS_EXTRANEOUS_INFORMATION cpu_to_le32(0x80000017) -#define STATUS_RXACT_COMMIT_NECESSARY cpu_to_le32(0x80000018) -#define STATUS_NO_MORE_ENTRIES cpu_to_le32(0x8000001A) -#define STATUS_FILEMARK_DETECTED cpu_to_le32(0x8000001B) -#define STATUS_MEDIA_CHANGED cpu_to_le32(0x8000001C) -#define STATUS_BUS_RESET cpu_to_le32(0x8000001D) -#define STATUS_END_OF_MEDIA cpu_to_le32(0x8000001E) -#define STATUS_BEGINNING_OF_MEDIA cpu_to_le32(0x8000001F) -#define STATUS_MEDIA_CHECK cpu_to_le32(0x80000020) -#define STATUS_SETMARK_DETECTED cpu_to_le32(0x80000021) -#define STATUS_NO_DATA_DETECTED cpu_to_le32(0x80000022) -#define STATUS_REDIRECTOR_HAS_OPEN_HANDLES cpu_to_le32(0x80000023) -#define STATUS_SERVER_HAS_OPEN_HANDLES cpu_to_le32(0x80000024) -#define STATUS_ALREADY_DISCONNECTED cpu_to_le32(0x80000025) -#define STATUS_LONGJUMP cpu_to_le32(0x80000026) -#define STATUS_CLEANER_CARTRIDGE_INSTALLED cpu_to_le32(0x80000027) -#define STATUS_PLUGPLAY_QUERY_VETOED cpu_to_le32(0x80000028) -#define STATUS_UNWIND_CONSOLIDATE cpu_to_le32(0x80000029) -#define STATUS_REGISTRY_HIVE_RECOVERED cpu_to_le32(0x8000002A) -#define STATUS_DLL_MIGHT_BE_INSECURE cpu_to_le32(0x8000002B) -#define STATUS_DLL_MIGHT_BE_INCOMPATIBLE cpu_to_le32(0x8000002C) -#define STATUS_STOPPED_ON_SYMLINK cpu_to_le32(0x8000002D) -#define STATUS_DEVICE_REQUIRES_CLEANING cpu_to_le32(0x80000288) -#define STATUS_DEVICE_DOOR_OPEN cpu_to_le32(0x80000289) -#define STATUS_DATA_LOST_REPAIR cpu_to_le32(0x80000803) -#define DBG_EXCEPTION_NOT_HANDLED cpu_to_le32(0x80010001) -#define STATUS_CLUSTER_NODE_ALREADY_UP cpu_to_le32(0x80130001) -#define STATUS_CLUSTER_NODE_ALREADY_DOWN cpu_to_le32(0x80130002) -#define STATUS_CLUSTER_NETWORK_ALREADY_ONLINE cpu_to_le32(0x80130003) -#define STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE cpu_to_le32(0x80130004) -#define STATUS_CLUSTER_NODE_ALREADY_MEMBER cpu_to_le32(0x80130005) -#define STATUS_COULD_NOT_RESIZE_LOG cpu_to_le32(0x80190009) -#define STATUS_NO_TXF_METADATA cpu_to_le32(0x80190029) -#define STATUS_CANT_RECOVER_WITH_HANDLE_OPEN cpu_to_le32(0x80190031) -#define STATUS_TXF_METADATA_ALREADY_PRESENT cpu_to_le32(0x80190041) -#define STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET cpu_to_le32(0x80190042) -#define STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED \ - cpu_to_le32(0x801B00EB) -#define STATUS_FLT_BUFFER_TOO_SMALL cpu_to_le32(0x801C0001) -#define STATUS_FVE_PARTIAL_METADATA cpu_to_le32(0x80210001) -#define STATUS_UNSUCCESSFUL cpu_to_le32(0xC0000001) -#define STATUS_NOT_IMPLEMENTED cpu_to_le32(0xC0000002) -#define STATUS_INVALID_INFO_CLASS cpu_to_le32(0xC0000003) -#define STATUS_INFO_LENGTH_MISMATCH cpu_to_le32(0xC0000004) -#define STATUS_ACCESS_VIOLATION cpu_to_le32(0xC0000005) -#define STATUS_IN_PAGE_ERROR cpu_to_le32(0xC0000006) -#define STATUS_PAGEFILE_QUOTA cpu_to_le32(0xC0000007) -#define STATUS_INVALID_HANDLE cpu_to_le32(0xC0000008) -#define STATUS_BAD_INITIAL_STACK cpu_to_le32(0xC0000009) -#define STATUS_BAD_INITIAL_PC cpu_to_le32(0xC000000A) -#define STATUS_INVALID_CID cpu_to_le32(0xC000000B) -#define STATUS_TIMER_NOT_CANCELED cpu_to_le32(0xC000000C) -#define STATUS_INVALID_PARAMETER cpu_to_le32(0xC000000D) -#define STATUS_NO_SUCH_DEVICE cpu_to_le32(0xC000000E) -#define STATUS_NO_SUCH_FILE cpu_to_le32(0xC000000F) -#define STATUS_INVALID_DEVICE_REQUEST cpu_to_le32(0xC0000010) -#define STATUS_END_OF_FILE cpu_to_le32(0xC0000011) -#define STATUS_WRONG_VOLUME cpu_to_le32(0xC0000012) -#define STATUS_NO_MEDIA_IN_DEVICE cpu_to_le32(0xC0000013) -#define STATUS_UNRECOGNIZED_MEDIA cpu_to_le32(0xC0000014) -#define STATUS_NONEXISTENT_SECTOR cpu_to_le32(0xC0000015) -#define STATUS_MORE_PROCESSING_REQUIRED cpu_to_le32(0xC0000016) -#define STATUS_NO_MEMORY cpu_to_le32(0xC0000017) -#define STATUS_CONFLICTING_ADDRESSES cpu_to_le32(0xC0000018) -#define STATUS_NOT_MAPPED_VIEW cpu_to_le32(0xC0000019) -#define STATUS_UNABLE_TO_FREE_VM cpu_to_le32(0xC000001A) -#define STATUS_UNABLE_TO_DELETE_SECTION cpu_to_le32(0xC000001B) -#define STATUS_INVALID_SYSTEM_SERVICE cpu_to_le32(0xC000001C) -#define STATUS_ILLEGAL_INSTRUCTION cpu_to_le32(0xC000001D) -#define STATUS_INVALID_LOCK_SEQUENCE cpu_to_le32(0xC000001E) -#define STATUS_INVALID_VIEW_SIZE cpu_to_le32(0xC000001F) -#define STATUS_INVALID_FILE_FOR_SECTION cpu_to_le32(0xC0000020) -#define STATUS_ALREADY_COMMITTED cpu_to_le32(0xC0000021) -#define STATUS_ACCESS_DENIED cpu_to_le32(0xC0000022) -#define STATUS_BUFFER_TOO_SMALL cpu_to_le32(0xC0000023) -#define STATUS_OBJECT_TYPE_MISMATCH cpu_to_le32(0xC0000024) -#define STATUS_NONCONTINUABLE_EXCEPTION cpu_to_le32(0xC0000025) -#define STATUS_INVALID_DISPOSITION cpu_to_le32(0xC0000026) -#define STATUS_UNWIND cpu_to_le32(0xC0000027) -#define STATUS_BAD_STACK cpu_to_le32(0xC0000028) -#define STATUS_INVALID_UNWIND_TARGET cpu_to_le32(0xC0000029) -#define STATUS_NOT_LOCKED cpu_to_le32(0xC000002A) -#define STATUS_PARITY_ERROR cpu_to_le32(0xC000002B) -#define STATUS_UNABLE_TO_DECOMMIT_VM cpu_to_le32(0xC000002C) -#define STATUS_NOT_COMMITTED cpu_to_le32(0xC000002D) -#define STATUS_INVALID_PORT_ATTRIBUTES cpu_to_le32(0xC000002E) -#define STATUS_PORT_MESSAGE_TOO_LONG cpu_to_le32(0xC000002F) -#define STATUS_INVALID_PARAMETER_MIX cpu_to_le32(0xC0000030) -#define STATUS_INVALID_QUOTA_LOWER cpu_to_le32(0xC0000031) -#define STATUS_DISK_CORRUPT_ERROR cpu_to_le32(0xC0000032) -#define STATUS_OBJECT_NAME_INVALID cpu_to_le32(0xC0000033) -#define STATUS_OBJECT_NAME_NOT_FOUND cpu_to_le32(0xC0000034) -#define STATUS_OBJECT_NAME_COLLISION cpu_to_le32(0xC0000035) -#define STATUS_PORT_DISCONNECTED cpu_to_le32(0xC0000037) -#define STATUS_DEVICE_ALREADY_ATTACHED cpu_to_le32(0xC0000038) -#define STATUS_OBJECT_PATH_INVALID cpu_to_le32(0xC0000039) -#define STATUS_OBJECT_PATH_NOT_FOUND cpu_to_le32(0xC000003A) -#define STATUS_OBJECT_PATH_SYNTAX_BAD cpu_to_le32(0xC000003B) -#define STATUS_DATA_OVERRUN cpu_to_le32(0xC000003C) -#define STATUS_DATA_LATE_ERROR cpu_to_le32(0xC000003D) -#define STATUS_DATA_ERROR cpu_to_le32(0xC000003E) -#define STATUS_CRC_ERROR cpu_to_le32(0xC000003F) -#define STATUS_SECTION_TOO_BIG cpu_to_le32(0xC0000040) -#define STATUS_PORT_CONNECTION_REFUSED cpu_to_le32(0xC0000041) -#define STATUS_INVALID_PORT_HANDLE cpu_to_le32(0xC0000042) -#define STATUS_SHARING_VIOLATION cpu_to_le32(0xC0000043) -#define STATUS_QUOTA_EXCEEDED cpu_to_le32(0xC0000044) -#define STATUS_INVALID_PAGE_PROTECTION cpu_to_le32(0xC0000045) -#define STATUS_MUTANT_NOT_OWNED cpu_to_le32(0xC0000046) -#define STATUS_SEMAPHORE_LIMIT_EXCEEDED cpu_to_le32(0xC0000047) -#define STATUS_PORT_ALREADY_SET cpu_to_le32(0xC0000048) -#define STATUS_SECTION_NOT_IMAGE cpu_to_le32(0xC0000049) -#define STATUS_SUSPEND_COUNT_EXCEEDED cpu_to_le32(0xC000004A) -#define STATUS_THREAD_IS_TERMINATING cpu_to_le32(0xC000004B) -#define STATUS_BAD_WORKING_SET_LIMIT cpu_to_le32(0xC000004C) -#define STATUS_INCOMPATIBLE_FILE_MAP cpu_to_le32(0xC000004D) -#define STATUS_SECTION_PROTECTION cpu_to_le32(0xC000004E) -#define STATUS_EAS_NOT_SUPPORTED cpu_to_le32(0xC000004F) -#define STATUS_EA_TOO_LARGE cpu_to_le32(0xC0000050) -#define STATUS_NONEXISTENT_EA_ENTRY cpu_to_le32(0xC0000051) -#define STATUS_NO_EAS_ON_FILE cpu_to_le32(0xC0000052) -#define STATUS_EA_CORRUPT_ERROR cpu_to_le32(0xC0000053) -#define STATUS_FILE_LOCK_CONFLICT cpu_to_le32(0xC0000054) -#define STATUS_LOCK_NOT_GRANTED cpu_to_le32(0xC0000055) -#define STATUS_DELETE_PENDING cpu_to_le32(0xC0000056) -#define STATUS_CTL_FILE_NOT_SUPPORTED cpu_to_le32(0xC0000057) -#define STATUS_UNKNOWN_REVISION cpu_to_le32(0xC0000058) -#define STATUS_REVISION_MISMATCH cpu_to_le32(0xC0000059) -#define STATUS_INVALID_OWNER cpu_to_le32(0xC000005A) -#define STATUS_INVALID_PRIMARY_GROUP cpu_to_le32(0xC000005B) -#define STATUS_NO_IMPERSONATION_TOKEN cpu_to_le32(0xC000005C) -#define STATUS_CANT_DISABLE_MANDATORY cpu_to_le32(0xC000005D) -#define STATUS_NO_LOGON_SERVERS cpu_to_le32(0xC000005E) -#define STATUS_NO_SUCH_LOGON_SESSION cpu_to_le32(0xC000005F) -#define STATUS_NO_SUCH_PRIVILEGE cpu_to_le32(0xC0000060) -#define STATUS_PRIVILEGE_NOT_HELD cpu_to_le32(0xC0000061) -#define STATUS_INVALID_ACCOUNT_NAME cpu_to_le32(0xC0000062) -#define STATUS_USER_EXISTS cpu_to_le32(0xC0000063) -#define STATUS_NO_SUCH_USER cpu_to_le32(0xC0000064) -#define STATUS_GROUP_EXISTS cpu_to_le32(0xC0000065) -#define STATUS_NO_SUCH_GROUP cpu_to_le32(0xC0000066) -#define STATUS_MEMBER_IN_GROUP cpu_to_le32(0xC0000067) -#define STATUS_MEMBER_NOT_IN_GROUP cpu_to_le32(0xC0000068) -#define STATUS_LAST_ADMIN cpu_to_le32(0xC0000069) -#define STATUS_WRONG_PASSWORD cpu_to_le32(0xC000006A) -#define STATUS_ILL_FORMED_PASSWORD cpu_to_le32(0xC000006B) -#define STATUS_PASSWORD_RESTRICTION cpu_to_le32(0xC000006C) -#define STATUS_LOGON_FAILURE cpu_to_le32(0xC000006D) -#define STATUS_ACCOUNT_RESTRICTION cpu_to_le32(0xC000006E) -#define STATUS_INVALID_LOGON_HOURS cpu_to_le32(0xC000006F) -#define STATUS_INVALID_WORKSTATION cpu_to_le32(0xC0000070) -#define STATUS_PASSWORD_EXPIRED cpu_to_le32(0xC0000071) -#define STATUS_ACCOUNT_DISABLED cpu_to_le32(0xC0000072) -#define STATUS_NONE_MAPPED cpu_to_le32(0xC0000073) -#define STATUS_TOO_MANY_LUIDS_REQUESTED cpu_to_le32(0xC0000074) -#define STATUS_LUIDS_EXHAUSTED cpu_to_le32(0xC0000075) -#define STATUS_INVALID_SUB_AUTHORITY cpu_to_le32(0xC0000076) -#define STATUS_INVALID_ACL cpu_to_le32(0xC0000077) -#define STATUS_INVALID_SID cpu_to_le32(0xC0000078) -#define STATUS_INVALID_SECURITY_DESCR cpu_to_le32(0xC0000079) -#define STATUS_PROCEDURE_NOT_FOUND cpu_to_le32(0xC000007A) -#define STATUS_INVALID_IMAGE_FORMAT cpu_to_le32(0xC000007B) -#define STATUS_NO_TOKEN cpu_to_le32(0xC000007C) -#define STATUS_BAD_INHERITANCE_ACL cpu_to_le32(0xC000007D) -#define STATUS_RANGE_NOT_LOCKED cpu_to_le32(0xC000007E) -#define STATUS_DISK_FULL cpu_to_le32(0xC000007F) -#define STATUS_SERVER_DISABLED cpu_to_le32(0xC0000080) -#define STATUS_SERVER_NOT_DISABLED cpu_to_le32(0xC0000081) -#define STATUS_TOO_MANY_GUIDS_REQUESTED cpu_to_le32(0xC0000082) -#define STATUS_GUIDS_EXHAUSTED cpu_to_le32(0xC0000083) -#define STATUS_INVALID_ID_AUTHORITY cpu_to_le32(0xC0000084) -#define STATUS_AGENTS_EXHAUSTED cpu_to_le32(0xC0000085) -#define STATUS_INVALID_VOLUME_LABEL cpu_to_le32(0xC0000086) -#define STATUS_SECTION_NOT_EXTENDED cpu_to_le32(0xC0000087) -#define STATUS_NOT_MAPPED_DATA cpu_to_le32(0xC0000088) -#define STATUS_RESOURCE_DATA_NOT_FOUND cpu_to_le32(0xC0000089) -#define STATUS_RESOURCE_TYPE_NOT_FOUND cpu_to_le32(0xC000008A) -#define STATUS_RESOURCE_NAME_NOT_FOUND cpu_to_le32(0xC000008B) -#define STATUS_ARRAY_BOUNDS_EXCEEDED cpu_to_le32(0xC000008C) -#define STATUS_FLOAT_DENORMAL_OPERAND cpu_to_le32(0xC000008D) -#define STATUS_FLOAT_DIVIDE_BY_ZERO cpu_to_le32(0xC000008E) -#define STATUS_FLOAT_INEXACT_RESULT cpu_to_le32(0xC000008F) -#define STATUS_FLOAT_INVALID_OPERATION cpu_to_le32(0xC0000090) -#define STATUS_FLOAT_OVERFLOW cpu_to_le32(0xC0000091) -#define STATUS_FLOAT_STACK_CHECK cpu_to_le32(0xC0000092) -#define STATUS_FLOAT_UNDERFLOW cpu_to_le32(0xC0000093) -#define STATUS_INTEGER_DIVIDE_BY_ZERO cpu_to_le32(0xC0000094) -#define STATUS_INTEGER_OVERFLOW cpu_to_le32(0xC0000095) -#define STATUS_PRIVILEGED_INSTRUCTION cpu_to_le32(0xC0000096) -#define STATUS_TOO_MANY_PAGING_FILES cpu_to_le32(0xC0000097) -#define STATUS_FILE_INVALID cpu_to_le32(0xC0000098) -#define STATUS_ALLOTTED_SPACE_EXCEEDED cpu_to_le32(0xC0000099) -#define STATUS_INSUFFICIENT_RESOURCES cpu_to_le32(0xC000009A) -#define STATUS_DFS_EXIT_PATH_FOUND cpu_to_le32(0xC000009B) -#define STATUS_DEVICE_DATA_ERROR cpu_to_le32(0xC000009C) -#define STATUS_DEVICE_NOT_CONNECTED cpu_to_le32(0xC000009D) -#define STATUS_DEVICE_POWER_FAILURE cpu_to_le32(0xC000009E) -#define STATUS_FREE_VM_NOT_AT_BASE cpu_to_le32(0xC000009F) -#define STATUS_MEMORY_NOT_ALLOCATED cpu_to_le32(0xC00000A0) -#define STATUS_WORKING_SET_QUOTA cpu_to_le32(0xC00000A1) -#define STATUS_MEDIA_WRITE_PROTECTED cpu_to_le32(0xC00000A2) -#define STATUS_DEVICE_NOT_READY cpu_to_le32(0xC00000A3) -#define STATUS_INVALID_GROUP_ATTRIBUTES cpu_to_le32(0xC00000A4) -#define STATUS_BAD_IMPERSONATION_LEVEL cpu_to_le32(0xC00000A5) -#define STATUS_CANT_OPEN_ANONYMOUS cpu_to_le32(0xC00000A6) -#define STATUS_BAD_VALIDATION_CLASS cpu_to_le32(0xC00000A7) -#define STATUS_BAD_TOKEN_TYPE cpu_to_le32(0xC00000A8) -#define STATUS_BAD_MASTER_BOOT_RECORD cpu_to_le32(0xC00000A9) -#define STATUS_INSTRUCTION_MISALIGNMENT cpu_to_le32(0xC00000AA) -#define STATUS_INSTANCE_NOT_AVAILABLE cpu_to_le32(0xC00000AB) -#define STATUS_PIPE_NOT_AVAILABLE cpu_to_le32(0xC00000AC) -#define STATUS_INVALID_PIPE_STATE cpu_to_le32(0xC00000AD) -#define STATUS_PIPE_BUSY cpu_to_le32(0xC00000AE) -#define STATUS_ILLEGAL_FUNCTION cpu_to_le32(0xC00000AF) -#define STATUS_PIPE_DISCONNECTED cpu_to_le32(0xC00000B0) -#define STATUS_PIPE_CLOSING cpu_to_le32(0xC00000B1) -#define STATUS_PIPE_CONNECTED cpu_to_le32(0xC00000B2) -#define STATUS_PIPE_LISTENING cpu_to_le32(0xC00000B3) -#define STATUS_INVALID_READ_MODE cpu_to_le32(0xC00000B4) -#define STATUS_IO_TIMEOUT cpu_to_le32(0xC00000B5) -#define STATUS_FILE_FORCED_CLOSED cpu_to_le32(0xC00000B6) -#define STATUS_PROFILING_NOT_STARTED cpu_to_le32(0xC00000B7) -#define STATUS_PROFILING_NOT_STOPPED cpu_to_le32(0xC00000B8) -#define STATUS_COULD_NOT_INTERPRET cpu_to_le32(0xC00000B9) -#define STATUS_FILE_IS_A_DIRECTORY cpu_to_le32(0xC00000BA) -#define STATUS_NOT_SUPPORTED cpu_to_le32(0xC00000BB) -#define STATUS_REMOTE_NOT_LISTENING cpu_to_le32(0xC00000BC) -#define STATUS_DUPLICATE_NAME cpu_to_le32(0xC00000BD) -#define STATUS_BAD_NETWORK_PATH cpu_to_le32(0xC00000BE) -#define STATUS_NETWORK_BUSY cpu_to_le32(0xC00000BF) -#define STATUS_DEVICE_DOES_NOT_EXIST cpu_to_le32(0xC00000C0) -#define STATUS_TOO_MANY_COMMANDS cpu_to_le32(0xC00000C1) -#define STATUS_ADAPTER_HARDWARE_ERROR cpu_to_le32(0xC00000C2) -#define STATUS_INVALID_NETWORK_RESPONSE cpu_to_le32(0xC00000C3) -#define STATUS_UNEXPECTED_NETWORK_ERROR cpu_to_le32(0xC00000C4) -#define STATUS_BAD_REMOTE_ADAPTER cpu_to_le32(0xC00000C5) -#define STATUS_PRINT_QUEUE_FULL cpu_to_le32(0xC00000C6) -#define STATUS_NO_SPOOL_SPACE cpu_to_le32(0xC00000C7) -#define STATUS_PRINT_CANCELLED cpu_to_le32(0xC00000C8) -#define STATUS_NETWORK_NAME_DELETED cpu_to_le32(0xC00000C9) -#define STATUS_NETWORK_ACCESS_DENIED cpu_to_le32(0xC00000CA) -#define STATUS_BAD_DEVICE_TYPE cpu_to_le32(0xC00000CB) -#define STATUS_BAD_NETWORK_NAME cpu_to_le32(0xC00000CC) -#define STATUS_TOO_MANY_NAMES cpu_to_le32(0xC00000CD) -#define STATUS_TOO_MANY_SESSIONS cpu_to_le32(0xC00000CE) -#define STATUS_SHARING_PAUSED cpu_to_le32(0xC00000CF) -#define STATUS_REQUEST_NOT_ACCEPTED cpu_to_le32(0xC00000D0) -#define STATUS_REDIRECTOR_PAUSED cpu_to_le32(0xC00000D1) -#define STATUS_NET_WRITE_FAULT cpu_to_le32(0xC00000D2) -#define STATUS_PROFILING_AT_LIMIT cpu_to_le32(0xC00000D3) -#define STATUS_NOT_SAME_DEVICE cpu_to_le32(0xC00000D4) -#define STATUS_FILE_RENAMED cpu_to_le32(0xC00000D5) -#define STATUS_VIRTUAL_CIRCUIT_CLOSED cpu_to_le32(0xC00000D6) -#define STATUS_NO_SECURITY_ON_OBJECT cpu_to_le32(0xC00000D7) -#define STATUS_CANT_WAIT cpu_to_le32(0xC00000D8) -#define STATUS_PIPE_EMPTY cpu_to_le32(0xC00000D9) -#define STATUS_CANT_ACCESS_DOMAIN_INFO cpu_to_le32(0xC00000DA) -#define STATUS_CANT_TERMINATE_SELF cpu_to_le32(0xC00000DB) -#define STATUS_INVALID_SERVER_STATE cpu_to_le32(0xC00000DC) -#define STATUS_INVALID_DOMAIN_STATE cpu_to_le32(0xC00000DD) -#define STATUS_INVALID_DOMAIN_ROLE cpu_to_le32(0xC00000DE) -#define STATUS_NO_SUCH_DOMAIN cpu_to_le32(0xC00000DF) -#define STATUS_DOMAIN_EXISTS cpu_to_le32(0xC00000E0) -#define STATUS_DOMAIN_LIMIT_EXCEEDED cpu_to_le32(0xC00000E1) -#define STATUS_OPLOCK_NOT_GRANTED cpu_to_le32(0xC00000E2) -#define STATUS_INVALID_OPLOCK_PROTOCOL cpu_to_le32(0xC00000E3) -#define STATUS_INTERNAL_DB_CORRUPTION cpu_to_le32(0xC00000E4) -#define STATUS_INTERNAL_ERROR cpu_to_le32(0xC00000E5) -#define STATUS_GENERIC_NOT_MAPPED cpu_to_le32(0xC00000E6) -#define STATUS_BAD_DESCRIPTOR_FORMAT cpu_to_le32(0xC00000E7) -#define STATUS_INVALID_USER_BUFFER cpu_to_le32(0xC00000E8) -#define STATUS_UNEXPECTED_IO_ERROR cpu_to_le32(0xC00000E9) -#define STATUS_UNEXPECTED_MM_CREATE_ERR cpu_to_le32(0xC00000EA) -#define STATUS_UNEXPECTED_MM_MAP_ERROR cpu_to_le32(0xC00000EB) -#define STATUS_UNEXPECTED_MM_EXTEND_ERR cpu_to_le32(0xC00000EC) -#define STATUS_NOT_LOGON_PROCESS cpu_to_le32(0xC00000ED) -#define STATUS_LOGON_SESSION_EXISTS cpu_to_le32(0xC00000EE) -#define STATUS_INVALID_PARAMETER_1 cpu_to_le32(0xC00000EF) -#define STATUS_INVALID_PARAMETER_2 cpu_to_le32(0xC00000F0) -#define STATUS_INVALID_PARAMETER_3 cpu_to_le32(0xC00000F1) -#define STATUS_INVALID_PARAMETER_4 cpu_to_le32(0xC00000F2) -#define STATUS_INVALID_PARAMETER_5 cpu_to_le32(0xC00000F3) -#define STATUS_INVALID_PARAMETER_6 cpu_to_le32(0xC00000F4) -#define STATUS_INVALID_PARAMETER_7 cpu_to_le32(0xC00000F5) -#define STATUS_INVALID_PARAMETER_8 cpu_to_le32(0xC00000F6) -#define STATUS_INVALID_PARAMETER_9 cpu_to_le32(0xC00000F7) -#define STATUS_INVALID_PARAMETER_10 cpu_to_le32(0xC00000F8) -#define STATUS_INVALID_PARAMETER_11 cpu_to_le32(0xC00000F9) -#define STATUS_INVALID_PARAMETER_12 cpu_to_le32(0xC00000FA) -#define STATUS_REDIRECTOR_NOT_STARTED cpu_to_le32(0xC00000FB) -#define STATUS_REDIRECTOR_STARTED cpu_to_le32(0xC00000FC) -#define STATUS_STACK_OVERFLOW cpu_to_le32(0xC00000FD) -#define STATUS_NO_SUCH_PACKAGE cpu_to_le32(0xC00000FE) -#define STATUS_BAD_FUNCTION_TABLE cpu_to_le32(0xC00000FF) -#define STATUS_VARIABLE_NOT_FOUND cpu_to_le32(0xC0000100) -#define STATUS_DIRECTORY_NOT_EMPTY cpu_to_le32(0xC0000101) -#define STATUS_FILE_CORRUPT_ERROR cpu_to_le32(0xC0000102) -#define STATUS_NOT_A_DIRECTORY cpu_to_le32(0xC0000103) -#define STATUS_BAD_LOGON_SESSION_STATE cpu_to_le32(0xC0000104) -#define STATUS_LOGON_SESSION_COLLISION cpu_to_le32(0xC0000105) -#define STATUS_NAME_TOO_LONG cpu_to_le32(0xC0000106) -#define STATUS_FILES_OPEN cpu_to_le32(0xC0000107) -#define STATUS_CONNECTION_IN_USE cpu_to_le32(0xC0000108) -#define STATUS_MESSAGE_NOT_FOUND cpu_to_le32(0xC0000109) -#define STATUS_PROCESS_IS_TERMINATING cpu_to_le32(0xC000010A) -#define STATUS_INVALID_LOGON_TYPE cpu_to_le32(0xC000010B) -#define STATUS_NO_GUID_TRANSLATION cpu_to_le32(0xC000010C) -#define STATUS_CANNOT_IMPERSONATE cpu_to_le32(0xC000010D) -#define STATUS_IMAGE_ALREADY_LOADED cpu_to_le32(0xC000010E) -#define STATUS_ABIOS_NOT_PRESENT cpu_to_le32(0xC000010F) -#define STATUS_ABIOS_LID_NOT_EXIST cpu_to_le32(0xC0000110) -#define STATUS_ABIOS_LID_ALREADY_OWNED cpu_to_le32(0xC0000111) -#define STATUS_ABIOS_NOT_LID_OWNER cpu_to_le32(0xC0000112) -#define STATUS_ABIOS_INVALID_COMMAND cpu_to_le32(0xC0000113) -#define STATUS_ABIOS_INVALID_LID cpu_to_le32(0xC0000114) -#define STATUS_ABIOS_SELECTOR_NOT_AVAILABLE cpu_to_le32(0xC0000115) -#define STATUS_ABIOS_INVALID_SELECTOR cpu_to_le32(0xC0000116) -#define STATUS_NO_LDT cpu_to_le32(0xC0000117) -#define STATUS_INVALID_LDT_SIZE cpu_to_le32(0xC0000118) -#define STATUS_INVALID_LDT_OFFSET cpu_to_le32(0xC0000119) -#define STATUS_INVALID_LDT_DESCRIPTOR cpu_to_le32(0xC000011A) -#define STATUS_INVALID_IMAGE_NE_FORMAT cpu_to_le32(0xC000011B) -#define STATUS_RXACT_INVALID_STATE cpu_to_le32(0xC000011C) -#define STATUS_RXACT_COMMIT_FAILURE cpu_to_le32(0xC000011D) -#define STATUS_MAPPED_FILE_SIZE_ZERO cpu_to_le32(0xC000011E) -#define STATUS_TOO_MANY_OPENED_FILES cpu_to_le32(0xC000011F) -#define STATUS_CANCELLED cpu_to_le32(0xC0000120) -#define STATUS_CANNOT_DELETE cpu_to_le32(0xC0000121) -#define STATUS_INVALID_COMPUTER_NAME cpu_to_le32(0xC0000122) -#define STATUS_FILE_DELETED cpu_to_le32(0xC0000123) -#define STATUS_SPECIAL_ACCOUNT cpu_to_le32(0xC0000124) -#define STATUS_SPECIAL_GROUP cpu_to_le32(0xC0000125) -#define STATUS_SPECIAL_USER cpu_to_le32(0xC0000126) -#define STATUS_MEMBERS_PRIMARY_GROUP cpu_to_le32(0xC0000127) -#define STATUS_FILE_CLOSED cpu_to_le32(0xC0000128) -#define STATUS_TOO_MANY_THREADS cpu_to_le32(0xC0000129) -#define STATUS_THREAD_NOT_IN_PROCESS cpu_to_le32(0xC000012A) -#define STATUS_TOKEN_ALREADY_IN_USE cpu_to_le32(0xC000012B) -#define STATUS_PAGEFILE_QUOTA_EXCEEDED cpu_to_le32(0xC000012C) -#define STATUS_COMMITMENT_LIMIT cpu_to_le32(0xC000012D) -#define STATUS_INVALID_IMAGE_LE_FORMAT cpu_to_le32(0xC000012E) -#define STATUS_INVALID_IMAGE_NOT_MZ cpu_to_le32(0xC000012F) -#define STATUS_INVALID_IMAGE_PROTECT cpu_to_le32(0xC0000130) -#define STATUS_INVALID_IMAGE_WIN_16 cpu_to_le32(0xC0000131) -#define STATUS_LOGON_SERVER_CONFLICT cpu_to_le32(0xC0000132) -#define STATUS_TIME_DIFFERENCE_AT_DC cpu_to_le32(0xC0000133) -#define STATUS_SYNCHRONIZATION_REQUIRED cpu_to_le32(0xC0000134) -#define STATUS_DLL_NOT_FOUND cpu_to_le32(0xC0000135) -#define STATUS_OPEN_FAILED cpu_to_le32(0xC0000136) -#define STATUS_IO_PRIVILEGE_FAILED cpu_to_le32(0xC0000137) -#define STATUS_ORDINAL_NOT_FOUND cpu_to_le32(0xC0000138) -#define STATUS_ENTRYPOINT_NOT_FOUND cpu_to_le32(0xC0000139) -#define STATUS_CONTROL_C_EXIT cpu_to_le32(0xC000013A) -#define STATUS_LOCAL_DISCONNECT cpu_to_le32(0xC000013B) -#define STATUS_REMOTE_DISCONNECT cpu_to_le32(0xC000013C) -#define STATUS_REMOTE_RESOURCES cpu_to_le32(0xC000013D) -#define STATUS_LINK_FAILED cpu_to_le32(0xC000013E) -#define STATUS_LINK_TIMEOUT cpu_to_le32(0xC000013F) -#define STATUS_INVALID_CONNECTION cpu_to_le32(0xC0000140) -#define STATUS_INVALID_ADDRESS cpu_to_le32(0xC0000141) -#define STATUS_DLL_INIT_FAILED cpu_to_le32(0xC0000142) -#define STATUS_MISSING_SYSTEMFILE cpu_to_le32(0xC0000143) -#define STATUS_UNHANDLED_EXCEPTION cpu_to_le32(0xC0000144) -#define STATUS_APP_INIT_FAILURE cpu_to_le32(0xC0000145) -#define STATUS_PAGEFILE_CREATE_FAILED cpu_to_le32(0xC0000146) -#define STATUS_NO_PAGEFILE cpu_to_le32(0xC0000147) -#define STATUS_INVALID_LEVEL cpu_to_le32(0xC0000148) -#define STATUS_WRONG_PASSWORD_CORE cpu_to_le32(0xC0000149) -#define STATUS_ILLEGAL_FLOAT_CONTEXT cpu_to_le32(0xC000014A) -#define STATUS_PIPE_BROKEN cpu_to_le32(0xC000014B) -#define STATUS_REGISTRY_CORRUPT cpu_to_le32(0xC000014C) -#define STATUS_REGISTRY_IO_FAILED cpu_to_le32(0xC000014D) -#define STATUS_NO_EVENT_PAIR cpu_to_le32(0xC000014E) -#define STATUS_UNRECOGNIZED_VOLUME cpu_to_le32(0xC000014F) -#define STATUS_SERIAL_NO_DEVICE_INITED cpu_to_le32(0xC0000150) -#define STATUS_NO_SUCH_ALIAS cpu_to_le32(0xC0000151) -#define STATUS_MEMBER_NOT_IN_ALIAS cpu_to_le32(0xC0000152) -#define STATUS_MEMBER_IN_ALIAS cpu_to_le32(0xC0000153) -#define STATUS_ALIAS_EXISTS cpu_to_le32(0xC0000154) -#define STATUS_LOGON_NOT_GRANTED cpu_to_le32(0xC0000155) -#define STATUS_TOO_MANY_SECRETS cpu_to_le32(0xC0000156) -#define STATUS_SECRET_TOO_LONG cpu_to_le32(0xC0000157) -#define STATUS_INTERNAL_DB_ERROR cpu_to_le32(0xC0000158) -#define STATUS_FULLSCREEN_MODE cpu_to_le32(0xC0000159) -#define STATUS_TOO_MANY_CONTEXT_IDS cpu_to_le32(0xC000015A) -#define STATUS_LOGON_TYPE_NOT_GRANTED cpu_to_le32(0xC000015B) -#define STATUS_NOT_REGISTRY_FILE cpu_to_le32(0xC000015C) -#define STATUS_NT_CROSS_ENCRYPTION_REQUIRED cpu_to_le32(0xC000015D) -#define STATUS_DOMAIN_CTRLR_CONFIG_ERROR cpu_to_le32(0xC000015E) -#define STATUS_FT_MISSING_MEMBER cpu_to_le32(0xC000015F) -#define STATUS_ILL_FORMED_SERVICE_ENTRY cpu_to_le32(0xC0000160) -#define STATUS_ILLEGAL_CHARACTER cpu_to_le32(0xC0000161) -#define STATUS_UNMAPPABLE_CHARACTER cpu_to_le32(0xC0000162) -#define STATUS_UNDEFINED_CHARACTER cpu_to_le32(0xC0000163) -#define STATUS_FLOPPY_VOLUME cpu_to_le32(0xC0000164) -#define STATUS_FLOPPY_ID_MARK_NOT_FOUND cpu_to_le32(0xC0000165) -#define STATUS_FLOPPY_WRONG_CYLINDER cpu_to_le32(0xC0000166) -#define STATUS_FLOPPY_UNKNOWN_ERROR cpu_to_le32(0xC0000167) -#define STATUS_FLOPPY_BAD_REGISTERS cpu_to_le32(0xC0000168) -#define STATUS_DISK_RECALIBRATE_FAILED cpu_to_le32(0xC0000169) -#define STATUS_DISK_OPERATION_FAILED cpu_to_le32(0xC000016A) -#define STATUS_DISK_RESET_FAILED cpu_to_le32(0xC000016B) -#define STATUS_SHARED_IRQ_BUSY cpu_to_le32(0xC000016C) -#define STATUS_FT_ORPHANING cpu_to_le32(0xC000016D) -#define STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT cpu_to_le32(0xC000016E) -#define STATUS_PARTITION_FAILURE cpu_to_le32(0xC0000172) -#define STATUS_INVALID_BLOCK_LENGTH cpu_to_le32(0xC0000173) -#define STATUS_DEVICE_NOT_PARTITIONED cpu_to_le32(0xC0000174) -#define STATUS_UNABLE_TO_LOCK_MEDIA cpu_to_le32(0xC0000175) -#define STATUS_UNABLE_TO_UNLOAD_MEDIA cpu_to_le32(0xC0000176) -#define STATUS_EOM_OVERFLOW cpu_to_le32(0xC0000177) -#define STATUS_NO_MEDIA cpu_to_le32(0xC0000178) -#define STATUS_NO_SUCH_MEMBER cpu_to_le32(0xC000017A) -#define STATUS_INVALID_MEMBER cpu_to_le32(0xC000017B) -#define STATUS_KEY_DELETED cpu_to_le32(0xC000017C) -#define STATUS_NO_LOG_SPACE cpu_to_le32(0xC000017D) -#define STATUS_TOO_MANY_SIDS cpu_to_le32(0xC000017E) -#define STATUS_LM_CROSS_ENCRYPTION_REQUIRED cpu_to_le32(0xC000017F) -#define STATUS_KEY_HAS_CHILDREN cpu_to_le32(0xC0000180) -#define STATUS_CHILD_MUST_BE_VOLATILE cpu_to_le32(0xC0000181) -#define STATUS_DEVICE_CONFIGURATION_ERROR cpu_to_le32(0xC0000182) -#define STATUS_DRIVER_INTERNAL_ERROR cpu_to_le32(0xC0000183) -#define STATUS_INVALID_DEVICE_STATE cpu_to_le32(0xC0000184) -#define STATUS_IO_DEVICE_ERROR cpu_to_le32(0xC0000185) -#define STATUS_DEVICE_PROTOCOL_ERROR cpu_to_le32(0xC0000186) -#define STATUS_BACKUP_CONTROLLER cpu_to_le32(0xC0000187) -#define STATUS_LOG_FILE_FULL cpu_to_le32(0xC0000188) -#define STATUS_TOO_LATE cpu_to_le32(0xC0000189) -#define STATUS_NO_TRUST_LSA_SECRET cpu_to_le32(0xC000018A) -#define STATUS_NO_TRUST_SAM_ACCOUNT cpu_to_le32(0xC000018B) -#define STATUS_TRUSTED_DOMAIN_FAILURE cpu_to_le32(0xC000018C) -#define STATUS_TRUSTED_RELATIONSHIP_FAILURE cpu_to_le32(0xC000018D) -#define STATUS_EVENTLOG_FILE_CORRUPT cpu_to_le32(0xC000018E) -#define STATUS_EVENTLOG_CANT_START cpu_to_le32(0xC000018F) -#define STATUS_TRUST_FAILURE cpu_to_le32(0xC0000190) -#define STATUS_MUTANT_LIMIT_EXCEEDED cpu_to_le32(0xC0000191) -#define STATUS_NETLOGON_NOT_STARTED cpu_to_le32(0xC0000192) -#define STATUS_ACCOUNT_EXPIRED cpu_to_le32(0xC0000193) -#define STATUS_POSSIBLE_DEADLOCK cpu_to_le32(0xC0000194) -#define STATUS_NETWORK_CREDENTIAL_CONFLICT cpu_to_le32(0xC0000195) -#define STATUS_REMOTE_SESSION_LIMIT cpu_to_le32(0xC0000196) -#define STATUS_EVENTLOG_FILE_CHANGED cpu_to_le32(0xC0000197) -#define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT cpu_to_le32(0xC0000198) -#define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT cpu_to_le32(0xC0000199) -#define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT cpu_to_le32(0xC000019A) -#define STATUS_DOMAIN_TRUST_INCONSISTENT cpu_to_le32(0xC000019B) -#define STATUS_FS_DRIVER_REQUIRED cpu_to_le32(0xC000019C) -#define STATUS_IMAGE_ALREADY_LOADED_AS_DLL cpu_to_le32(0xC000019D) -#define STATUS_NETWORK_OPEN_RESTRICTION cpu_to_le32(0xC0000201) -#define STATUS_NO_USER_SESSION_KEY cpu_to_le32(0xC0000202) -#define STATUS_USER_SESSION_DELETED cpu_to_le32(0xC0000203) -#define STATUS_RESOURCE_LANG_NOT_FOUND cpu_to_le32(0xC0000204) -#define STATUS_INSUFF_SERVER_RESOURCES cpu_to_le32(0xC0000205) -#define STATUS_INVALID_BUFFER_SIZE cpu_to_le32(0xC0000206) -#define STATUS_INVALID_ADDRESS_COMPONENT cpu_to_le32(0xC0000207) -#define STATUS_INVALID_ADDRESS_WILDCARD cpu_to_le32(0xC0000208) -#define STATUS_TOO_MANY_ADDRESSES cpu_to_le32(0xC0000209) -#define STATUS_ADDRESS_ALREADY_EXISTS cpu_to_le32(0xC000020A) -#define STATUS_ADDRESS_CLOSED cpu_to_le32(0xC000020B) -#define STATUS_CONNECTION_DISCONNECTED cpu_to_le32(0xC000020C) -#define STATUS_CONNECTION_RESET cpu_to_le32(0xC000020D) -#define STATUS_TOO_MANY_NODES cpu_to_le32(0xC000020E) -#define STATUS_TRANSACTION_ABORTED cpu_to_le32(0xC000020F) -#define STATUS_TRANSACTION_TIMED_OUT cpu_to_le32(0xC0000210) -#define STATUS_TRANSACTION_NO_RELEASE cpu_to_le32(0xC0000211) -#define STATUS_TRANSACTION_NO_MATCH cpu_to_le32(0xC0000212) -#define STATUS_TRANSACTION_RESPONDED cpu_to_le32(0xC0000213) -#define STATUS_TRANSACTION_INVALID_ID cpu_to_le32(0xC0000214) -#define STATUS_TRANSACTION_INVALID_TYPE cpu_to_le32(0xC0000215) -#define STATUS_NOT_SERVER_SESSION cpu_to_le32(0xC0000216) -#define STATUS_NOT_CLIENT_SESSION cpu_to_le32(0xC0000217) -#define STATUS_CANNOT_LOAD_REGISTRY_FILE cpu_to_le32(0xC0000218) -#define STATUS_DEBUG_ATTACH_FAILED cpu_to_le32(0xC0000219) -#define STATUS_SYSTEM_PROCESS_TERMINATED cpu_to_le32(0xC000021A) -#define STATUS_DATA_NOT_ACCEPTED cpu_to_le32(0xC000021B) -#define STATUS_NO_BROWSER_SERVERS_FOUND cpu_to_le32(0xC000021C) -#define STATUS_VDM_HARD_ERROR cpu_to_le32(0xC000021D) -#define STATUS_DRIVER_CANCEL_TIMEOUT cpu_to_le32(0xC000021E) -#define STATUS_REPLY_MESSAGE_MISMATCH cpu_to_le32(0xC000021F) -#define STATUS_MAPPED_ALIGNMENT cpu_to_le32(0xC0000220) -#define STATUS_IMAGE_CHECKSUM_MISMATCH cpu_to_le32(0xC0000221) -#define STATUS_LOST_WRITEBEHIND_DATA cpu_to_le32(0xC0000222) -#define STATUS_CLIENT_SERVER_PARAMETERS_INVALID cpu_to_le32(0xC0000223) -#define STATUS_PASSWORD_MUST_CHANGE cpu_to_le32(0xC0000224) -#define STATUS_NOT_FOUND cpu_to_le32(0xC0000225) -#define STATUS_NOT_TINY_STREAM cpu_to_le32(0xC0000226) -#define STATUS_RECOVERY_FAILURE cpu_to_le32(0xC0000227) -#define STATUS_STACK_OVERFLOW_READ cpu_to_le32(0xC0000228) -#define STATUS_FAIL_CHECK cpu_to_le32(0xC0000229) -#define STATUS_DUPLICATE_OBJECTID cpu_to_le32(0xC000022A) -#define STATUS_OBJECTID_EXISTS cpu_to_le32(0xC000022B) -#define STATUS_CONVERT_TO_LARGE cpu_to_le32(0xC000022C) -#define STATUS_RETRY cpu_to_le32(0xC000022D) -#define STATUS_FOUND_OUT_OF_SCOPE cpu_to_le32(0xC000022E) -#define STATUS_ALLOCATE_BUCKET cpu_to_le32(0xC000022F) -#define STATUS_PROPSET_NOT_FOUND cpu_to_le32(0xC0000230) -#define STATUS_MARSHALL_OVERFLOW cpu_to_le32(0xC0000231) -#define STATUS_INVALID_VARIANT cpu_to_le32(0xC0000232) -#define STATUS_DOMAIN_CONTROLLER_NOT_FOUND cpu_to_le32(0xC0000233) -#define STATUS_ACCOUNT_LOCKED_OUT cpu_to_le32(0xC0000234) -#define STATUS_HANDLE_NOT_CLOSABLE cpu_to_le32(0xC0000235) -#define STATUS_CONNECTION_REFUSED cpu_to_le32(0xC0000236) -#define STATUS_GRACEFUL_DISCONNECT cpu_to_le32(0xC0000237) -#define STATUS_ADDRESS_ALREADY_ASSOCIATED cpu_to_le32(0xC0000238) -#define STATUS_ADDRESS_NOT_ASSOCIATED cpu_to_le32(0xC0000239) -#define STATUS_CONNECTION_INVALID cpu_to_le32(0xC000023A) -#define STATUS_CONNECTION_ACTIVE cpu_to_le32(0xC000023B) -#define STATUS_NETWORK_UNREACHABLE cpu_to_le32(0xC000023C) -#define STATUS_HOST_UNREACHABLE cpu_to_le32(0xC000023D) -#define STATUS_PROTOCOL_UNREACHABLE cpu_to_le32(0xC000023E) -#define STATUS_PORT_UNREACHABLE cpu_to_le32(0xC000023F) -#define STATUS_REQUEST_ABORTED cpu_to_le32(0xC0000240) -#define STATUS_CONNECTION_ABORTED cpu_to_le32(0xC0000241) -#define STATUS_BAD_COMPRESSION_BUFFER cpu_to_le32(0xC0000242) -#define STATUS_USER_MAPPED_FILE cpu_to_le32(0xC0000243) -#define STATUS_AUDIT_FAILED cpu_to_le32(0xC0000244) -#define STATUS_TIMER_RESOLUTION_NOT_SET cpu_to_le32(0xC0000245) -#define STATUS_CONNECTION_COUNT_LIMIT cpu_to_le32(0xC0000246) -#define STATUS_LOGIN_TIME_RESTRICTION cpu_to_le32(0xC0000247) -#define STATUS_LOGIN_WKSTA_RESTRICTION cpu_to_le32(0xC0000248) -#define STATUS_IMAGE_MP_UP_MISMATCH cpu_to_le32(0xC0000249) -#define STATUS_INSUFFICIENT_LOGON_INFO cpu_to_le32(0xC0000250) -#define STATUS_BAD_DLL_ENTRYPOINT cpu_to_le32(0xC0000251) -#define STATUS_BAD_SERVICE_ENTRYPOINT cpu_to_le32(0xC0000252) -#define STATUS_LPC_REPLY_LOST cpu_to_le32(0xC0000253) -#define STATUS_IP_ADDRESS_CONFLICT1 cpu_to_le32(0xC0000254) -#define STATUS_IP_ADDRESS_CONFLICT2 cpu_to_le32(0xC0000255) -#define STATUS_REGISTRY_QUOTA_LIMIT cpu_to_le32(0xC0000256) -#define STATUS_PATH_NOT_COVERED cpu_to_le32(0xC0000257) -#define STATUS_NO_CALLBACK_ACTIVE cpu_to_le32(0xC0000258) -#define STATUS_LICENSE_QUOTA_EXCEEDED cpu_to_le32(0xC0000259) -#define STATUS_PWD_TOO_SHORT cpu_to_le32(0xC000025A) -#define STATUS_PWD_TOO_RECENT cpu_to_le32(0xC000025B) -#define STATUS_PWD_HISTORY_CONFLICT cpu_to_le32(0xC000025C) -#define STATUS_PLUGPLAY_NO_DEVICE cpu_to_le32(0xC000025E) -#define STATUS_UNSUPPORTED_COMPRESSION cpu_to_le32(0xC000025F) -#define STATUS_INVALID_HW_PROFILE cpu_to_le32(0xC0000260) -#define STATUS_INVALID_PLUGPLAY_DEVICE_PATH cpu_to_le32(0xC0000261) -#define STATUS_DRIVER_ORDINAL_NOT_FOUND cpu_to_le32(0xC0000262) -#define STATUS_DRIVER_ENTRYPOINT_NOT_FOUND cpu_to_le32(0xC0000263) -#define STATUS_RESOURCE_NOT_OWNED cpu_to_le32(0xC0000264) -#define STATUS_TOO_MANY_LINKS cpu_to_le32(0xC0000265) -#define STATUS_QUOTA_LIST_INCONSISTENT cpu_to_le32(0xC0000266) -#define STATUS_FILE_IS_OFFLINE cpu_to_le32(0xC0000267) -#define STATUS_EVALUATION_EXPIRATION cpu_to_le32(0xC0000268) -#define STATUS_ILLEGAL_DLL_RELOCATION cpu_to_le32(0xC0000269) -#define STATUS_LICENSE_VIOLATION cpu_to_le32(0xC000026A) -#define STATUS_DLL_INIT_FAILED_LOGOFF cpu_to_le32(0xC000026B) -#define STATUS_DRIVER_UNABLE_TO_LOAD cpu_to_le32(0xC000026C) -#define STATUS_DFS_UNAVAILABLE cpu_to_le32(0xC000026D) -#define STATUS_VOLUME_DISMOUNTED cpu_to_le32(0xC000026E) -#define STATUS_WX86_INTERNAL_ERROR cpu_to_le32(0xC000026F) -#define STATUS_WX86_FLOAT_STACK_CHECK cpu_to_le32(0xC0000270) -#define STATUS_VALIDATE_CONTINUE cpu_to_le32(0xC0000271) -#define STATUS_NO_MATCH cpu_to_le32(0xC0000272) -#define STATUS_NO_MORE_MATCHES cpu_to_le32(0xC0000273) -#define STATUS_NOT_A_REPARSE_POINT cpu_to_le32(0xC0000275) -#define STATUS_IO_REPARSE_TAG_INVALID cpu_to_le32(0xC0000276) -#define STATUS_IO_REPARSE_TAG_MISMATCH cpu_to_le32(0xC0000277) -#define STATUS_IO_REPARSE_DATA_INVALID cpu_to_le32(0xC0000278) -#define STATUS_IO_REPARSE_TAG_NOT_HANDLED cpu_to_le32(0xC0000279) -#define STATUS_REPARSE_POINT_NOT_RESOLVED cpu_to_le32(0xC0000280) -#define STATUS_DIRECTORY_IS_A_REPARSE_POINT cpu_to_le32(0xC0000281) -#define STATUS_RANGE_LIST_CONFLICT cpu_to_le32(0xC0000282) -#define STATUS_SOURCE_ELEMENT_EMPTY cpu_to_le32(0xC0000283) -#define STATUS_DESTINATION_ELEMENT_FULL cpu_to_le32(0xC0000284) -#define STATUS_ILLEGAL_ELEMENT_ADDRESS cpu_to_le32(0xC0000285) -#define STATUS_MAGAZINE_NOT_PRESENT cpu_to_le32(0xC0000286) -#define STATUS_REINITIALIZATION_NEEDED cpu_to_le32(0xC0000287) -#define STATUS_ENCRYPTION_FAILED cpu_to_le32(0xC000028A) -#define STATUS_DECRYPTION_FAILED cpu_to_le32(0xC000028B) -#define STATUS_RANGE_NOT_FOUND cpu_to_le32(0xC000028C) -#define STATUS_NO_RECOVERY_POLICY cpu_to_le32(0xC000028D) -#define STATUS_NO_EFS cpu_to_le32(0xC000028E) -#define STATUS_WRONG_EFS cpu_to_le32(0xC000028F) -#define STATUS_NO_USER_KEYS cpu_to_le32(0xC0000290) -#define STATUS_FILE_NOT_ENCRYPTED cpu_to_le32(0xC0000291) -#define STATUS_NOT_EXPORT_FORMAT cpu_to_le32(0xC0000292) -#define STATUS_FILE_ENCRYPTED cpu_to_le32(0xC0000293) -#define STATUS_WMI_GUID_NOT_FOUND cpu_to_le32(0xC0000295) -#define STATUS_WMI_INSTANCE_NOT_FOUND cpu_to_le32(0xC0000296) -#define STATUS_WMI_ITEMID_NOT_FOUND cpu_to_le32(0xC0000297) -#define STATUS_WMI_TRY_AGAIN cpu_to_le32(0xC0000298) -#define STATUS_SHARED_POLICY cpu_to_le32(0xC0000299) -#define STATUS_POLICY_OBJECT_NOT_FOUND cpu_to_le32(0xC000029A) -#define STATUS_POLICY_ONLY_IN_DS cpu_to_le32(0xC000029B) -#define STATUS_VOLUME_NOT_UPGRADED cpu_to_le32(0xC000029C) -#define STATUS_REMOTE_STORAGE_NOT_ACTIVE cpu_to_le32(0xC000029D) -#define STATUS_REMOTE_STORAGE_MEDIA_ERROR cpu_to_le32(0xC000029E) -#define STATUS_NO_TRACKING_SERVICE cpu_to_le32(0xC000029F) -#define STATUS_SERVER_SID_MISMATCH cpu_to_le32(0xC00002A0) -#define STATUS_DS_NO_ATTRIBUTE_OR_VALUE cpu_to_le32(0xC00002A1) -#define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX cpu_to_le32(0xC00002A2) -#define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED cpu_to_le32(0xC00002A3) -#define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS cpu_to_le32(0xC00002A4) -#define STATUS_DS_BUSY cpu_to_le32(0xC00002A5) -#define STATUS_DS_UNAVAILABLE cpu_to_le32(0xC00002A6) -#define STATUS_DS_NO_RIDS_ALLOCATED cpu_to_le32(0xC00002A7) -#define STATUS_DS_NO_MORE_RIDS cpu_to_le32(0xC00002A8) -#define STATUS_DS_INCORRECT_ROLE_OWNER cpu_to_le32(0xC00002A9) -#define STATUS_DS_RIDMGR_INIT_ERROR cpu_to_le32(0xC00002AA) -#define STATUS_DS_OBJ_CLASS_VIOLATION cpu_to_le32(0xC00002AB) -#define STATUS_DS_CANT_ON_NON_LEAF cpu_to_le32(0xC00002AC) -#define STATUS_DS_CANT_ON_RDN cpu_to_le32(0xC00002AD) -#define STATUS_DS_CANT_MOD_OBJ_CLASS cpu_to_le32(0xC00002AE) -#define STATUS_DS_CROSS_DOM_MOVE_FAILED cpu_to_le32(0xC00002AF) -#define STATUS_DS_GC_NOT_AVAILABLE cpu_to_le32(0xC00002B0) -#define STATUS_DIRECTORY_SERVICE_REQUIRED cpu_to_le32(0xC00002B1) -#define STATUS_REPARSE_ATTRIBUTE_CONFLICT cpu_to_le32(0xC00002B2) -#define STATUS_CANT_ENABLE_DENY_ONLY cpu_to_le32(0xC00002B3) -#define STATUS_FLOAT_MULTIPLE_FAULTS cpu_to_le32(0xC00002B4) -#define STATUS_FLOAT_MULTIPLE_TRAPS cpu_to_le32(0xC00002B5) -#define STATUS_DEVICE_REMOVED cpu_to_le32(0xC00002B6) -#define STATUS_JOURNAL_DELETE_IN_PROGRESS cpu_to_le32(0xC00002B7) -#define STATUS_JOURNAL_NOT_ACTIVE cpu_to_le32(0xC00002B8) -#define STATUS_NOINTERFACE cpu_to_le32(0xC00002B9) -#define STATUS_DS_ADMIN_LIMIT_EXCEEDED cpu_to_le32(0xC00002C1) -#define STATUS_DRIVER_FAILED_SLEEP cpu_to_le32(0xC00002C2) -#define STATUS_MUTUAL_AUTHENTICATION_FAILED cpu_to_le32(0xC00002C3) -#define STATUS_CORRUPT_SYSTEM_FILE cpu_to_le32(0xC00002C4) -#define STATUS_DATATYPE_MISALIGNMENT_ERROR cpu_to_le32(0xC00002C5) -#define STATUS_WMI_READ_ONLY cpu_to_le32(0xC00002C6) -#define STATUS_WMI_SET_FAILURE cpu_to_le32(0xC00002C7) -#define STATUS_COMMITMENT_MINIMUM cpu_to_le32(0xC00002C8) -#define STATUS_REG_NAT_CONSUMPTION cpu_to_le32(0xC00002C9) -#define STATUS_TRANSPORT_FULL cpu_to_le32(0xC00002CA) -#define STATUS_DS_SAM_INIT_FAILURE cpu_to_le32(0xC00002CB) -#define STATUS_ONLY_IF_CONNECTED cpu_to_le32(0xC00002CC) -#define STATUS_DS_SENSITIVE_GROUP_VIOLATION cpu_to_le32(0xC00002CD) -#define STATUS_PNP_RESTART_ENUMERATION cpu_to_le32(0xC00002CE) -#define STATUS_JOURNAL_ENTRY_DELETED cpu_to_le32(0xC00002CF) -#define STATUS_DS_CANT_MOD_PRIMARYGROUPID cpu_to_le32(0xC00002D0) -#define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE cpu_to_le32(0xC00002D1) -#define STATUS_PNP_REBOOT_REQUIRED cpu_to_le32(0xC00002D2) -#define STATUS_POWER_STATE_INVALID cpu_to_le32(0xC00002D3) -#define STATUS_DS_INVALID_GROUP_TYPE cpu_to_le32(0xC00002D4) -#define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN cpu_to_le32(0xC00002D5) -#define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN cpu_to_le32(0xC00002D6) -#define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER cpu_to_le32(0xC00002D7) -#define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER cpu_to_le32(0xC00002D8) -#define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER cpu_to_le32(0xC00002D9) -#define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER cpu_to_le32(0xC00002DA) -#define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER \ - cpu_to_le32(0xC00002DB) -#define STATUS_DS_HAVE_PRIMARY_MEMBERS cpu_to_le32(0xC00002DC) -#define STATUS_WMI_NOT_SUPPORTED cpu_to_le32(0xC00002DD) -#define STATUS_INSUFFICIENT_POWER cpu_to_le32(0xC00002DE) -#define STATUS_SAM_NEED_BOOTKEY_PASSWORD cpu_to_le32(0xC00002DF) -#define STATUS_SAM_NEED_BOOTKEY_FLOPPY cpu_to_le32(0xC00002E0) -#define STATUS_DS_CANT_START cpu_to_le32(0xC00002E1) -#define STATUS_DS_INIT_FAILURE cpu_to_le32(0xC00002E2) -#define STATUS_SAM_INIT_FAILURE cpu_to_le32(0xC00002E3) -#define STATUS_DS_GC_REQUIRED cpu_to_le32(0xC00002E4) -#define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY cpu_to_le32(0xC00002E5) -#define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS cpu_to_le32(0xC00002E6) -#define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED cpu_to_le32(0xC00002E7) -#define STATUS_MULTIPLE_FAULT_VIOLATION cpu_to_le32(0xC00002E8) -#define STATUS_CURRENT_DOMAIN_NOT_ALLOWED cpu_to_le32(0xC00002E9) -#define STATUS_CANNOT_MAKE cpu_to_le32(0xC00002EA) -#define STATUS_SYSTEM_SHUTDOWN cpu_to_le32(0xC00002EB) -#define STATUS_DS_INIT_FAILURE_CONSOLE cpu_to_le32(0xC00002EC) -#define STATUS_DS_SAM_INIT_FAILURE_CONSOLE cpu_to_le32(0xC00002ED) -#define STATUS_UNFINISHED_CONTEXT_DELETED cpu_to_le32(0xC00002EE) -#define STATUS_NO_TGT_REPLY cpu_to_le32(0xC00002EF) -#define STATUS_OBJECTID_NOT_FOUND cpu_to_le32(0xC00002F0) -#define STATUS_NO_IP_ADDRESSES cpu_to_le32(0xC00002F1) -#define STATUS_WRONG_CREDENTIAL_HANDLE cpu_to_le32(0xC00002F2) -#define STATUS_CRYPTO_SYSTEM_INVALID cpu_to_le32(0xC00002F3) -#define STATUS_MAX_REFERRALS_EXCEEDED cpu_to_le32(0xC00002F4) -#define STATUS_MUST_BE_KDC cpu_to_le32(0xC00002F5) -#define STATUS_STRONG_CRYPTO_NOT_SUPPORTED cpu_to_le32(0xC00002F6) -#define STATUS_TOO_MANY_PRINCIPALS cpu_to_le32(0xC00002F7) -#define STATUS_NO_PA_DATA cpu_to_le32(0xC00002F8) -#define STATUS_PKINIT_NAME_MISMATCH cpu_to_le32(0xC00002F9) -#define STATUS_SMARTCARD_LOGON_REQUIRED cpu_to_le32(0xC00002FA) -#define STATUS_KDC_INVALID_REQUEST cpu_to_le32(0xC00002FB) -#define STATUS_KDC_UNABLE_TO_REFER cpu_to_le32(0xC00002FC) -#define STATUS_KDC_UNKNOWN_ETYPE cpu_to_le32(0xC00002FD) -#define STATUS_SHUTDOWN_IN_PROGRESS cpu_to_le32(0xC00002FE) -#define STATUS_SERVER_SHUTDOWN_IN_PROGRESS cpu_to_le32(0xC00002FF) -#define STATUS_NOT_SUPPORTED_ON_SBS cpu_to_le32(0xC0000300) -#define STATUS_WMI_GUID_DISCONNECTED cpu_to_le32(0xC0000301) -#define STATUS_WMI_ALREADY_DISABLED cpu_to_le32(0xC0000302) -#define STATUS_WMI_ALREADY_ENABLED cpu_to_le32(0xC0000303) -#define STATUS_MFT_TOO_FRAGMENTED cpu_to_le32(0xC0000304) -#define STATUS_COPY_PROTECTION_FAILURE cpu_to_le32(0xC0000305) -#define STATUS_CSS_AUTHENTICATION_FAILURE cpu_to_le32(0xC0000306) -#define STATUS_CSS_KEY_NOT_PRESENT cpu_to_le32(0xC0000307) -#define STATUS_CSS_KEY_NOT_ESTABLISHED cpu_to_le32(0xC0000308) -#define STATUS_CSS_SCRAMBLED_SECTOR cpu_to_le32(0xC0000309) -#define STATUS_CSS_REGION_MISMATCH cpu_to_le32(0xC000030A) -#define STATUS_CSS_RESETS_EXHAUSTED cpu_to_le32(0xC000030B) -#define STATUS_PKINIT_FAILURE cpu_to_le32(0xC0000320) -#define STATUS_SMARTCARD_SUBSYSTEM_FAILURE cpu_to_le32(0xC0000321) -#define STATUS_NO_KERB_KEY cpu_to_le32(0xC0000322) -#define STATUS_HOST_DOWN cpu_to_le32(0xC0000350) -#define STATUS_UNSUPPORTED_PREAUTH cpu_to_le32(0xC0000351) -#define STATUS_EFS_ALG_BLOB_TOO_BIG cpu_to_le32(0xC0000352) -#define STATUS_PORT_NOT_SET cpu_to_le32(0xC0000353) -#define STATUS_DEBUGGER_INACTIVE cpu_to_le32(0xC0000354) -#define STATUS_DS_VERSION_CHECK_FAILURE cpu_to_le32(0xC0000355) -#define STATUS_AUDITING_DISABLED cpu_to_le32(0xC0000356) -#define STATUS_PRENT4_MACHINE_ACCOUNT cpu_to_le32(0xC0000357) -#define STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER cpu_to_le32(0xC0000358) -#define STATUS_INVALID_IMAGE_WIN_32 cpu_to_le32(0xC0000359) -#define STATUS_INVALID_IMAGE_WIN_64 cpu_to_le32(0xC000035A) -#define STATUS_BAD_BINDINGS cpu_to_le32(0xC000035B) -#define STATUS_NETWORK_SESSION_EXPIRED cpu_to_le32(0xC000035C) -#define STATUS_APPHELP_BLOCK cpu_to_le32(0xC000035D) -#define STATUS_ALL_SIDS_FILTERED cpu_to_le32(0xC000035E) -#define STATUS_NOT_SAFE_MODE_DRIVER cpu_to_le32(0xC000035F) -#define STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT cpu_to_le32(0xC0000361) -#define STATUS_ACCESS_DISABLED_BY_POLICY_PATH cpu_to_le32(0xC0000362) -#define STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER cpu_to_le32(0xC0000363) -#define STATUS_ACCESS_DISABLED_BY_POLICY_OTHER cpu_to_le32(0xC0000364) -#define STATUS_FAILED_DRIVER_ENTRY cpu_to_le32(0xC0000365) -#define STATUS_DEVICE_ENUMERATION_ERROR cpu_to_le32(0xC0000366) -#define STATUS_MOUNT_POINT_NOT_RESOLVED cpu_to_le32(0xC0000368) -#define STATUS_INVALID_DEVICE_OBJECT_PARAMETER cpu_to_le32(0xC0000369) -#define STATUS_MCA_OCCURRED cpu_to_le32(0xC000036A) -#define STATUS_DRIVER_BLOCKED_CRITICAL cpu_to_le32(0xC000036B) -#define STATUS_DRIVER_BLOCKED cpu_to_le32(0xC000036C) -#define STATUS_DRIVER_DATABASE_ERROR cpu_to_le32(0xC000036D) -#define STATUS_SYSTEM_HIVE_TOO_LARGE cpu_to_le32(0xC000036E) -#define STATUS_INVALID_IMPORT_OF_NON_DLL cpu_to_le32(0xC000036F) -#define STATUS_NO_SECRETS cpu_to_le32(0xC0000371) -#define STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY cpu_to_le32(0xC0000372) -#define STATUS_FAILED_STACK_SWITCH cpu_to_le32(0xC0000373) -#define STATUS_HEAP_CORRUPTION cpu_to_le32(0xC0000374) -#define STATUS_SMARTCARD_WRONG_PIN cpu_to_le32(0xC0000380) -#define STATUS_SMARTCARD_CARD_BLOCKED cpu_to_le32(0xC0000381) -#define STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED cpu_to_le32(0xC0000382) -#define STATUS_SMARTCARD_NO_CARD cpu_to_le32(0xC0000383) -#define STATUS_SMARTCARD_NO_KEY_CONTAINER cpu_to_le32(0xC0000384) -#define STATUS_SMARTCARD_NO_CERTIFICATE cpu_to_le32(0xC0000385) -#define STATUS_SMARTCARD_NO_KEYSET cpu_to_le32(0xC0000386) -#define STATUS_SMARTCARD_IO_ERROR cpu_to_le32(0xC0000387) -#define STATUS_DOWNGRADE_DETECTED cpu_to_le32(0xC0000388) -#define STATUS_SMARTCARD_CERT_REVOKED cpu_to_le32(0xC0000389) -#define STATUS_ISSUING_CA_UNTRUSTED cpu_to_le32(0xC000038A) -#define STATUS_REVOCATION_OFFLINE_C cpu_to_le32(0xC000038B) -#define STATUS_PKINIT_CLIENT_FAILURE cpu_to_le32(0xC000038C) -#define STATUS_SMARTCARD_CERT_EXPIRED cpu_to_le32(0xC000038D) -#define STATUS_DRIVER_FAILED_PRIOR_UNLOAD cpu_to_le32(0xC000038E) -#define STATUS_SMARTCARD_SILENT_CONTEXT cpu_to_le32(0xC000038F) -#define STATUS_PER_USER_TRUST_QUOTA_EXCEEDED cpu_to_le32(0xC0000401) -#define STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED cpu_to_le32(0xC0000402) -#define STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED cpu_to_le32(0xC0000403) -#define STATUS_DS_NAME_NOT_UNIQUE cpu_to_le32(0xC0000404) -#define STATUS_DS_DUPLICATE_ID_FOUND cpu_to_le32(0xC0000405) -#define STATUS_DS_GROUP_CONVERSION_ERROR cpu_to_le32(0xC0000406) -#define STATUS_VOLSNAP_PREPARE_HIBERNATE cpu_to_le32(0xC0000407) -#define STATUS_USER2USER_REQUIRED cpu_to_le32(0xC0000408) -#define STATUS_STACK_BUFFER_OVERRUN cpu_to_le32(0xC0000409) -#define STATUS_NO_S4U_PROT_SUPPORT cpu_to_le32(0xC000040A) -#define STATUS_CROSSREALM_DELEGATION_FAILURE cpu_to_le32(0xC000040B) -#define STATUS_REVOCATION_OFFLINE_KDC cpu_to_le32(0xC000040C) -#define STATUS_ISSUING_CA_UNTRUSTED_KDC cpu_to_le32(0xC000040D) -#define STATUS_KDC_CERT_EXPIRED cpu_to_le32(0xC000040E) -#define STATUS_KDC_CERT_REVOKED cpu_to_le32(0xC000040F) -#define STATUS_PARAMETER_QUOTA_EXCEEDED cpu_to_le32(0xC0000410) -#define STATUS_HIBERNATION_FAILURE cpu_to_le32(0xC0000411) -#define STATUS_DELAY_LOAD_FAILED cpu_to_le32(0xC0000412) -#define STATUS_AUTHENTICATION_FIREWALL_FAILED cpu_to_le32(0xC0000413) -#define STATUS_VDM_DISALLOWED cpu_to_le32(0xC0000414) -#define STATUS_HUNG_DISPLAY_DRIVER_THREAD cpu_to_le32(0xC0000415) -#define STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE \ - cpu_to_le32(0xC0000416) -#define STATUS_INVALID_CRUNTIME_PARAMETER cpu_to_le32(0xC0000417) -#define STATUS_NTLM_BLOCKED cpu_to_le32(0xC0000418) -#define STATUS_ASSERTION_FAILURE cpu_to_le32(0xC0000420) -#define STATUS_VERIFIER_STOP cpu_to_le32(0xC0000421) -#define STATUS_CALLBACK_POP_STACK cpu_to_le32(0xC0000423) -#define STATUS_INCOMPATIBLE_DRIVER_BLOCKED cpu_to_le32(0xC0000424) -#define STATUS_HIVE_UNLOADED cpu_to_le32(0xC0000425) -#define STATUS_COMPRESSION_DISABLED cpu_to_le32(0xC0000426) -#define STATUS_FILE_SYSTEM_LIMITATION cpu_to_le32(0xC0000427) -#define STATUS_INVALID_IMAGE_HASH cpu_to_le32(0xC0000428) -#define STATUS_NOT_CAPABLE cpu_to_le32(0xC0000429) -#define STATUS_REQUEST_OUT_OF_SEQUENCE cpu_to_le32(0xC000042A) -#define STATUS_IMPLEMENTATION_LIMIT cpu_to_le32(0xC000042B) -#define STATUS_ELEVATION_REQUIRED cpu_to_le32(0xC000042C) -#define STATUS_BEYOND_VDL cpu_to_le32(0xC0000432) -#define STATUS_ENCOUNTERED_WRITE_IN_PROGRESS cpu_to_le32(0xC0000433) -#define STATUS_PTE_CHANGED cpu_to_le32(0xC0000434) -#define STATUS_PURGE_FAILED cpu_to_le32(0xC0000435) -#define STATUS_CRED_REQUIRES_CONFIRMATION cpu_to_le32(0xC0000440) -#define STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE cpu_to_le32(0xC0000441) -#define STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER cpu_to_le32(0xC0000442) -#define STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE cpu_to_le32(0xC0000443) -#define STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE cpu_to_le32(0xC0000444) -#define STATUS_CS_ENCRYPTION_FILE_NOT_CSE cpu_to_le32(0xC0000445) -#define STATUS_INVALID_LABEL cpu_to_le32(0xC0000446) -#define STATUS_DRIVER_PROCESS_TERMINATED cpu_to_le32(0xC0000450) -#define STATUS_AMBIGUOUS_SYSTEM_DEVICE cpu_to_le32(0xC0000451) -#define STATUS_SYSTEM_DEVICE_NOT_FOUND cpu_to_le32(0xC0000452) -#define STATUS_RESTART_BOOT_APPLICATION cpu_to_le32(0xC0000453) -#define STATUS_INVALID_TASK_NAME cpu_to_le32(0xC0000500) -#define STATUS_INVALID_TASK_INDEX cpu_to_le32(0xC0000501) -#define STATUS_THREAD_ALREADY_IN_TASK cpu_to_le32(0xC0000502) -#define STATUS_CALLBACK_BYPASS cpu_to_le32(0xC0000503) -#define STATUS_PORT_CLOSED cpu_to_le32(0xC0000700) -#define STATUS_MESSAGE_LOST cpu_to_le32(0xC0000701) -#define STATUS_INVALID_MESSAGE cpu_to_le32(0xC0000702) -#define STATUS_REQUEST_CANCELED cpu_to_le32(0xC0000703) -#define STATUS_RECURSIVE_DISPATCH cpu_to_le32(0xC0000704) -#define STATUS_LPC_RECEIVE_BUFFER_EXPECTED cpu_to_le32(0xC0000705) -#define STATUS_LPC_INVALID_CONNECTION_USAGE cpu_to_le32(0xC0000706) -#define STATUS_LPC_REQUESTS_NOT_ALLOWED cpu_to_le32(0xC0000707) -#define STATUS_RESOURCE_IN_USE cpu_to_le32(0xC0000708) -#define STATUS_HARDWARE_MEMORY_ERROR cpu_to_le32(0xC0000709) -#define STATUS_THREADPOOL_HANDLE_EXCEPTION cpu_to_le32(0xC000070A) -#define STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED cpu_to_le32(0xC000070B) -#define STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED \ - cpu_to_le32(0xC000070C) -#define STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED \ - cpu_to_le32(0xC000070D) -#define STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED \ - cpu_to_le32(0xC000070E) -#define STATUS_THREADPOOL_RELEASED_DURING_OPERATION cpu_to_le32(0xC000070F) -#define STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING cpu_to_le32(0xC0000710) -#define STATUS_APC_RETURNED_WHILE_IMPERSONATING cpu_to_le32(0xC0000711) -#define STATUS_PROCESS_IS_PROTECTED cpu_to_le32(0xC0000712) -#define STATUS_MCA_EXCEPTION cpu_to_le32(0xC0000713) -#define STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE cpu_to_le32(0xC0000714) -#define STATUS_SYMLINK_CLASS_DISABLED cpu_to_le32(0xC0000715) -#define STATUS_INVALID_IDN_NORMALIZATION cpu_to_le32(0xC0000716) -#define STATUS_NO_UNICODE_TRANSLATION cpu_to_le32(0xC0000717) -#define STATUS_ALREADY_REGISTERED cpu_to_le32(0xC0000718) -#define STATUS_CONTEXT_MISMATCH cpu_to_le32(0xC0000719) -#define STATUS_PORT_ALREADY_HAS_COMPLETION_LIST cpu_to_le32(0xC000071A) -#define STATUS_CALLBACK_RETURNED_THREAD_PRIORITY cpu_to_le32(0xC000071B) -#define STATUS_INVALID_THREAD cpu_to_le32(0xC000071C) -#define STATUS_CALLBACK_RETURNED_TRANSACTION cpu_to_le32(0xC000071D) -#define STATUS_CALLBACK_RETURNED_LDR_LOCK cpu_to_le32(0xC000071E) -#define STATUS_CALLBACK_RETURNED_LANG cpu_to_le32(0xC000071F) -#define STATUS_CALLBACK_RETURNED_PRI_BACK cpu_to_le32(0xC0000720) -#define STATUS_CALLBACK_RETURNED_THREAD_AFFINITY cpu_to_le32(0xC0000721) -#define STATUS_DISK_REPAIR_DISABLED cpu_to_le32(0xC0000800) -#define STATUS_DS_DOMAIN_RENAME_IN_PROGRESS cpu_to_le32(0xC0000801) -#define STATUS_DISK_QUOTA_EXCEEDED cpu_to_le32(0xC0000802) -#define STATUS_CONTENT_BLOCKED cpu_to_le32(0xC0000804) -#define STATUS_BAD_CLUSTERS cpu_to_le32(0xC0000805) -#define STATUS_VOLUME_DIRTY cpu_to_le32(0xC0000806) -#define STATUS_FILE_CHECKED_OUT cpu_to_le32(0xC0000901) -#define STATUS_CHECKOUT_REQUIRED cpu_to_le32(0xC0000902) -#define STATUS_BAD_FILE_TYPE cpu_to_le32(0xC0000903) -#define STATUS_FILE_TOO_LARGE cpu_to_le32(0xC0000904) -#define STATUS_FORMS_AUTH_REQUIRED cpu_to_le32(0xC0000905) -#define STATUS_VIRUS_INFECTED cpu_to_le32(0xC0000906) -#define STATUS_VIRUS_DELETED cpu_to_le32(0xC0000907) -#define STATUS_BAD_MCFG_TABLE cpu_to_le32(0xC0000908) -#define STATUS_WOW_ASSERTION cpu_to_le32(0xC0009898) -#define STATUS_INVALID_SIGNATURE cpu_to_le32(0xC000A000) -#define STATUS_HMAC_NOT_SUPPORTED cpu_to_le32(0xC000A001) -#define STATUS_IPSEC_QUEUE_OVERFLOW cpu_to_le32(0xC000A010) -#define STATUS_ND_QUEUE_OVERFLOW cpu_to_le32(0xC000A011) -#define STATUS_HOPLIMIT_EXCEEDED cpu_to_le32(0xC000A012) -#define STATUS_PROTOCOL_NOT_SUPPORTED cpu_to_le32(0xC000A013) -#define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED \ - cpu_to_le32(0xC000A080) -#define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR \ - cpu_to_le32(0xC000A081) -#define STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR cpu_to_le32(0xC000A082) -#define STATUS_XML_PARSE_ERROR cpu_to_le32(0xC000A083) -#define STATUS_XMLDSIG_ERROR cpu_to_le32(0xC000A084) -#define STATUS_WRONG_COMPARTMENT cpu_to_le32(0xC000A085) -#define STATUS_AUTHIP_FAILURE cpu_to_le32(0xC000A086) -#define DBG_NO_STATE_CHANGE cpu_to_le32(0xC0010001) -#define DBG_APP_NOT_IDLE cpu_to_le32(0xC0010002) -#define RPC_NT_INVALID_STRING_BINDING cpu_to_le32(0xC0020001) -#define RPC_NT_WRONG_KIND_OF_BINDING cpu_to_le32(0xC0020002) -#define RPC_NT_INVALID_BINDING cpu_to_le32(0xC0020003) -#define RPC_NT_PROTSEQ_NOT_SUPPORTED cpu_to_le32(0xC0020004) -#define RPC_NT_INVALID_RPC_PROTSEQ cpu_to_le32(0xC0020005) -#define RPC_NT_INVALID_STRING_UUID cpu_to_le32(0xC0020006) -#define RPC_NT_INVALID_ENDPOINT_FORMAT cpu_to_le32(0xC0020007) -#define RPC_NT_INVALID_NET_ADDR cpu_to_le32(0xC0020008) -#define RPC_NT_NO_ENDPOINT_FOUND cpu_to_le32(0xC0020009) -#define RPC_NT_INVALID_TIMEOUT cpu_to_le32(0xC002000A) -#define RPC_NT_OBJECT_NOT_FOUND cpu_to_le32(0xC002000B) -#define RPC_NT_ALREADY_REGISTERED cpu_to_le32(0xC002000C) -#define RPC_NT_TYPE_ALREADY_REGISTERED cpu_to_le32(0xC002000D) -#define RPC_NT_ALREADY_LISTENING cpu_to_le32(0xC002000E) -#define RPC_NT_NO_PROTSEQS_REGISTERED cpu_to_le32(0xC002000F) -#define RPC_NT_NOT_LISTENING cpu_to_le32(0xC0020010) -#define RPC_NT_UNKNOWN_MGR_TYPE cpu_to_le32(0xC0020011) -#define RPC_NT_UNKNOWN_IF cpu_to_le32(0xC0020012) -#define RPC_NT_NO_BINDINGS cpu_to_le32(0xC0020013) -#define RPC_NT_NO_PROTSEQS cpu_to_le32(0xC0020014) -#define RPC_NT_CANT_CREATE_ENDPOINT cpu_to_le32(0xC0020015) -#define RPC_NT_OUT_OF_RESOURCES cpu_to_le32(0xC0020016) -#define RPC_NT_SERVER_UNAVAILABLE cpu_to_le32(0xC0020017) -#define RPC_NT_SERVER_TOO_BUSY cpu_to_le32(0xC0020018) -#define RPC_NT_INVALID_NETWORK_OPTIONS cpu_to_le32(0xC0020019) -#define RPC_NT_NO_CALL_ACTIVE cpu_to_le32(0xC002001A) -#define RPC_NT_CALL_FAILED cpu_to_le32(0xC002001B) -#define RPC_NT_CALL_FAILED_DNE cpu_to_le32(0xC002001C) -#define RPC_NT_PROTOCOL_ERROR cpu_to_le32(0xC002001D) -#define RPC_NT_UNSUPPORTED_TRANS_SYN cpu_to_le32(0xC002001F) -#define RPC_NT_UNSUPPORTED_TYPE cpu_to_le32(0xC0020021) -#define RPC_NT_INVALID_TAG cpu_to_le32(0xC0020022) -#define RPC_NT_INVALID_BOUND cpu_to_le32(0xC0020023) -#define RPC_NT_NO_ENTRY_NAME cpu_to_le32(0xC0020024) -#define RPC_NT_INVALID_NAME_SYNTAX cpu_to_le32(0xC0020025) -#define RPC_NT_UNSUPPORTED_NAME_SYNTAX cpu_to_le32(0xC0020026) -#define RPC_NT_UUID_NO_ADDRESS cpu_to_le32(0xC0020028) -#define RPC_NT_DUPLICATE_ENDPOINT cpu_to_le32(0xC0020029) -#define RPC_NT_UNKNOWN_AUTHN_TYPE cpu_to_le32(0xC002002A) -#define RPC_NT_MAX_CALLS_TOO_SMALL cpu_to_le32(0xC002002B) -#define RPC_NT_STRING_TOO_LONG cpu_to_le32(0xC002002C) -#define RPC_NT_PROTSEQ_NOT_FOUND cpu_to_le32(0xC002002D) -#define RPC_NT_PROCNUM_OUT_OF_RANGE cpu_to_le32(0xC002002E) -#define RPC_NT_BINDING_HAS_NO_AUTH cpu_to_le32(0xC002002F) -#define RPC_NT_UNKNOWN_AUTHN_SERVICE cpu_to_le32(0xC0020030) -#define RPC_NT_UNKNOWN_AUTHN_LEVEL cpu_to_le32(0xC0020031) -#define RPC_NT_INVALID_AUTH_IDENTITY cpu_to_le32(0xC0020032) -#define RPC_NT_UNKNOWN_AUTHZ_SERVICE cpu_to_le32(0xC0020033) -#define EPT_NT_INVALID_ENTRY cpu_to_le32(0xC0020034) -#define EPT_NT_CANT_PERFORM_OP cpu_to_le32(0xC0020035) -#define EPT_NT_NOT_REGISTERED cpu_to_le32(0xC0020036) -#define RPC_NT_NOTHING_TO_EXPORT cpu_to_le32(0xC0020037) -#define RPC_NT_INCOMPLETE_NAME cpu_to_le32(0xC0020038) -#define RPC_NT_INVALID_VERS_OPTION cpu_to_le32(0xC0020039) -#define RPC_NT_NO_MORE_MEMBERS cpu_to_le32(0xC002003A) -#define RPC_NT_NOT_ALL_OBJS_UNEXPORTED cpu_to_le32(0xC002003B) -#define RPC_NT_INTERFACE_NOT_FOUND cpu_to_le32(0xC002003C) -#define RPC_NT_ENTRY_ALREADY_EXISTS cpu_to_le32(0xC002003D) -#define RPC_NT_ENTRY_NOT_FOUND cpu_to_le32(0xC002003E) -#define RPC_NT_NAME_SERVICE_UNAVAILABLE cpu_to_le32(0xC002003F) -#define RPC_NT_INVALID_NAF_ID cpu_to_le32(0xC0020040) -#define RPC_NT_CANNOT_SUPPORT cpu_to_le32(0xC0020041) -#define RPC_NT_NO_CONTEXT_AVAILABLE cpu_to_le32(0xC0020042) -#define RPC_NT_INTERNAL_ERROR cpu_to_le32(0xC0020043) -#define RPC_NT_ZERO_DIVIDE cpu_to_le32(0xC0020044) -#define RPC_NT_ADDRESS_ERROR cpu_to_le32(0xC0020045) -#define RPC_NT_FP_DIV_ZERO cpu_to_le32(0xC0020046) -#define RPC_NT_FP_UNDERFLOW cpu_to_le32(0xC0020047) -#define RPC_NT_FP_OVERFLOW cpu_to_le32(0xC0020048) -#define RPC_NT_CALL_IN_PROGRESS cpu_to_le32(0xC0020049) -#define RPC_NT_NO_MORE_BINDINGS cpu_to_le32(0xC002004A) -#define RPC_NT_GROUP_MEMBER_NOT_FOUND cpu_to_le32(0xC002004B) -#define EPT_NT_CANT_CREATE cpu_to_le32(0xC002004C) -#define RPC_NT_INVALID_OBJECT cpu_to_le32(0xC002004D) -#define RPC_NT_NO_INTERFACES cpu_to_le32(0xC002004F) -#define RPC_NT_CALL_CANCELLED cpu_to_le32(0xC0020050) -#define RPC_NT_BINDING_INCOMPLETE cpu_to_le32(0xC0020051) -#define RPC_NT_COMM_FAILURE cpu_to_le32(0xC0020052) -#define RPC_NT_UNSUPPORTED_AUTHN_LEVEL cpu_to_le32(0xC0020053) -#define RPC_NT_NO_PRINC_NAME cpu_to_le32(0xC0020054) -#define RPC_NT_NOT_RPC_ERROR cpu_to_le32(0xC0020055) -#define RPC_NT_SEC_PKG_ERROR cpu_to_le32(0xC0020057) -#define RPC_NT_NOT_CANCELLED cpu_to_le32(0xC0020058) -#define RPC_NT_INVALID_ASYNC_HANDLE cpu_to_le32(0xC0020062) -#define RPC_NT_INVALID_ASYNC_CALL cpu_to_le32(0xC0020063) -#define RPC_NT_PROXY_ACCESS_DENIED cpu_to_le32(0xC0020064) -#define RPC_NT_NO_MORE_ENTRIES cpu_to_le32(0xC0030001) -#define RPC_NT_SS_CHAR_TRANS_OPEN_FAIL cpu_to_le32(0xC0030002) -#define RPC_NT_SS_CHAR_TRANS_SHORT_FILE cpu_to_le32(0xC0030003) -#define RPC_NT_SS_IN_NULL_CONTEXT cpu_to_le32(0xC0030004) -#define RPC_NT_SS_CONTEXT_MISMATCH cpu_to_le32(0xC0030005) -#define RPC_NT_SS_CONTEXT_DAMAGED cpu_to_le32(0xC0030006) -#define RPC_NT_SS_HANDLES_MISMATCH cpu_to_le32(0xC0030007) -#define RPC_NT_SS_CANNOT_GET_CALL_HANDLE cpu_to_le32(0xC0030008) -#define RPC_NT_NULL_REF_POINTER cpu_to_le32(0xC0030009) -#define RPC_NT_ENUM_VALUE_OUT_OF_RANGE cpu_to_le32(0xC003000A) -#define RPC_NT_BYTE_COUNT_TOO_SMALL cpu_to_le32(0xC003000B) -#define RPC_NT_BAD_STUB_DATA cpu_to_le32(0xC003000C) -#define RPC_NT_INVALID_ES_ACTION cpu_to_le32(0xC0030059) -#define RPC_NT_WRONG_ES_VERSION cpu_to_le32(0xC003005A) -#define RPC_NT_WRONG_STUB_VERSION cpu_to_le32(0xC003005B) -#define RPC_NT_INVALID_PIPE_OBJECT cpu_to_le32(0xC003005C) -#define RPC_NT_INVALID_PIPE_OPERATION cpu_to_le32(0xC003005D) -#define RPC_NT_WRONG_PIPE_VERSION cpu_to_le32(0xC003005E) -#define RPC_NT_PIPE_CLOSED cpu_to_le32(0xC003005F) -#define RPC_NT_PIPE_DISCIPLINE_ERROR cpu_to_le32(0xC0030060) -#define RPC_NT_PIPE_EMPTY cpu_to_le32(0xC0030061) -#define STATUS_PNP_BAD_MPS_TABLE cpu_to_le32(0xC0040035) -#define STATUS_PNP_TRANSLATION_FAILED cpu_to_le32(0xC0040036) -#define STATUS_PNP_IRQ_TRANSLATION_FAILED cpu_to_le32(0xC0040037) -#define STATUS_PNP_INVALID_ID cpu_to_le32(0xC0040038) -#define STATUS_IO_REISSUE_AS_CACHED cpu_to_le32(0xC0040039) -#define STATUS_CTX_WINSTATION_NAME_INVALID cpu_to_le32(0xC00A0001) -#define STATUS_CTX_INVALID_PD cpu_to_le32(0xC00A0002) -#define STATUS_CTX_PD_NOT_FOUND cpu_to_le32(0xC00A0003) -#define STATUS_CTX_CLOSE_PENDING cpu_to_le32(0xC00A0006) -#define STATUS_CTX_NO_OUTBUF cpu_to_le32(0xC00A0007) -#define STATUS_CTX_MODEM_INF_NOT_FOUND cpu_to_le32(0xC00A0008) -#define STATUS_CTX_INVALID_MODEMNAME cpu_to_le32(0xC00A0009) -#define STATUS_CTX_RESPONSE_ERROR cpu_to_le32(0xC00A000A) -#define STATUS_CTX_MODEM_RESPONSE_TIMEOUT cpu_to_le32(0xC00A000B) -#define STATUS_CTX_MODEM_RESPONSE_NO_CARRIER cpu_to_le32(0xC00A000C) -#define STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE cpu_to_le32(0xC00A000D) -#define STATUS_CTX_MODEM_RESPONSE_BUSY cpu_to_le32(0xC00A000E) -#define STATUS_CTX_MODEM_RESPONSE_VOICE cpu_to_le32(0xC00A000F) -#define STATUS_CTX_TD_ERROR cpu_to_le32(0xC00A0010) -#define STATUS_CTX_LICENSE_CLIENT_INVALID cpu_to_le32(0xC00A0012) -#define STATUS_CTX_LICENSE_NOT_AVAILABLE cpu_to_le32(0xC00A0013) -#define STATUS_CTX_LICENSE_EXPIRED cpu_to_le32(0xC00A0014) -#define STATUS_CTX_WINSTATION_NOT_FOUND cpu_to_le32(0xC00A0015) -#define STATUS_CTX_WINSTATION_NAME_COLLISION cpu_to_le32(0xC00A0016) -#define STATUS_CTX_WINSTATION_BUSY cpu_to_le32(0xC00A0017) -#define STATUS_CTX_BAD_VIDEO_MODE cpu_to_le32(0xC00A0018) -#define STATUS_CTX_GRAPHICS_INVALID cpu_to_le32(0xC00A0022) -#define STATUS_CTX_NOT_CONSOLE cpu_to_le32(0xC00A0024) -#define STATUS_CTX_CLIENT_QUERY_TIMEOUT cpu_to_le32(0xC00A0026) -#define STATUS_CTX_CONSOLE_DISCONNECT cpu_to_le32(0xC00A0027) -#define STATUS_CTX_CONSOLE_CONNECT cpu_to_le32(0xC00A0028) -#define STATUS_CTX_SHADOW_DENIED cpu_to_le32(0xC00A002A) -#define STATUS_CTX_WINSTATION_ACCESS_DENIED cpu_to_le32(0xC00A002B) -#define STATUS_CTX_INVALID_WD cpu_to_le32(0xC00A002E) -#define STATUS_CTX_WD_NOT_FOUND cpu_to_le32(0xC00A002F) -#define STATUS_CTX_SHADOW_INVALID cpu_to_le32(0xC00A0030) -#define STATUS_CTX_SHADOW_DISABLED cpu_to_le32(0xC00A0031) -#define STATUS_RDP_PROTOCOL_ERROR cpu_to_le32(0xC00A0032) -#define STATUS_CTX_CLIENT_LICENSE_NOT_SET cpu_to_le32(0xC00A0033) -#define STATUS_CTX_CLIENT_LICENSE_IN_USE cpu_to_le32(0xC00A0034) -#define STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE cpu_to_le32(0xC00A0035) -#define STATUS_CTX_SHADOW_NOT_RUNNING cpu_to_le32(0xC00A0036) -#define STATUS_CTX_LOGON_DISABLED cpu_to_le32(0xC00A0037) -#define STATUS_CTX_SECURITY_LAYER_ERROR cpu_to_le32(0xC00A0038) -#define STATUS_TS_INCOMPATIBLE_SESSIONS cpu_to_le32(0xC00A0039) -#define STATUS_MUI_FILE_NOT_FOUND cpu_to_le32(0xC00B0001) -#define STATUS_MUI_INVALID_FILE cpu_to_le32(0xC00B0002) -#define STATUS_MUI_INVALID_RC_CONFIG cpu_to_le32(0xC00B0003) -#define STATUS_MUI_INVALID_LOCALE_NAME cpu_to_le32(0xC00B0004) -#define STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME cpu_to_le32(0xC00B0005) -#define STATUS_MUI_FILE_NOT_LOADED cpu_to_le32(0xC00B0006) -#define STATUS_RESOURCE_ENUM_USER_STOP cpu_to_le32(0xC00B0007) -#define STATUS_CLUSTER_INVALID_NODE cpu_to_le32(0xC0130001) -#define STATUS_CLUSTER_NODE_EXISTS cpu_to_le32(0xC0130002) -#define STATUS_CLUSTER_JOIN_IN_PROGRESS cpu_to_le32(0xC0130003) -#define STATUS_CLUSTER_NODE_NOT_FOUND cpu_to_le32(0xC0130004) -#define STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND cpu_to_le32(0xC0130005) -#define STATUS_CLUSTER_NETWORK_EXISTS cpu_to_le32(0xC0130006) -#define STATUS_CLUSTER_NETWORK_NOT_FOUND cpu_to_le32(0xC0130007) -#define STATUS_CLUSTER_NETINTERFACE_EXISTS cpu_to_le32(0xC0130008) -#define STATUS_CLUSTER_NETINTERFACE_NOT_FOUND cpu_to_le32(0xC0130009) -#define STATUS_CLUSTER_INVALID_REQUEST cpu_to_le32(0xC013000A) -#define STATUS_CLUSTER_INVALID_NETWORK_PROVIDER cpu_to_le32(0xC013000B) -#define STATUS_CLUSTER_NODE_DOWN cpu_to_le32(0xC013000C) -#define STATUS_CLUSTER_NODE_UNREACHABLE cpu_to_le32(0xC013000D) -#define STATUS_CLUSTER_NODE_NOT_MEMBER cpu_to_le32(0xC013000E) -#define STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS cpu_to_le32(0xC013000F) -#define STATUS_CLUSTER_INVALID_NETWORK cpu_to_le32(0xC0130010) -#define STATUS_CLUSTER_NO_NET_ADAPTERS cpu_to_le32(0xC0130011) -#define STATUS_CLUSTER_NODE_UP cpu_to_le32(0xC0130012) -#define STATUS_CLUSTER_NODE_PAUSED cpu_to_le32(0xC0130013) -#define STATUS_CLUSTER_NODE_NOT_PAUSED cpu_to_le32(0xC0130014) -#define STATUS_CLUSTER_NO_SECURITY_CONTEXT cpu_to_le32(0xC0130015) -#define STATUS_CLUSTER_NETWORK_NOT_INTERNAL cpu_to_le32(0xC0130016) -#define STATUS_CLUSTER_POISONED cpu_to_le32(0xC0130017) -#define STATUS_ACPI_INVALID_OPCODE cpu_to_le32(0xC0140001) -#define STATUS_ACPI_STACK_OVERFLOW cpu_to_le32(0xC0140002) -#define STATUS_ACPI_ASSERT_FAILED cpu_to_le32(0xC0140003) -#define STATUS_ACPI_INVALID_INDEX cpu_to_le32(0xC0140004) -#define STATUS_ACPI_INVALID_ARGUMENT cpu_to_le32(0xC0140005) -#define STATUS_ACPI_FATAL cpu_to_le32(0xC0140006) -#define STATUS_ACPI_INVALID_SUPERNAME cpu_to_le32(0xC0140007) -#define STATUS_ACPI_INVALID_ARGTYPE cpu_to_le32(0xC0140008) -#define STATUS_ACPI_INVALID_OBJTYPE cpu_to_le32(0xC0140009) -#define STATUS_ACPI_INVALID_TARGETTYPE cpu_to_le32(0xC014000A) -#define STATUS_ACPI_INCORRECT_ARGUMENT_COUNT cpu_to_le32(0xC014000B) -#define STATUS_ACPI_ADDRESS_NOT_MAPPED cpu_to_le32(0xC014000C) -#define STATUS_ACPI_INVALID_EVENTTYPE cpu_to_le32(0xC014000D) -#define STATUS_ACPI_HANDLER_COLLISION cpu_to_le32(0xC014000E) -#define STATUS_ACPI_INVALID_DATA cpu_to_le32(0xC014000F) -#define STATUS_ACPI_INVALID_REGION cpu_to_le32(0xC0140010) -#define STATUS_ACPI_INVALID_ACCESS_SIZE cpu_to_le32(0xC0140011) -#define STATUS_ACPI_ACQUIRE_GLOBAL_LOCK cpu_to_le32(0xC0140012) -#define STATUS_ACPI_ALREADY_INITIALIZED cpu_to_le32(0xC0140013) -#define STATUS_ACPI_NOT_INITIALIZED cpu_to_le32(0xC0140014) -#define STATUS_ACPI_INVALID_MUTEX_LEVEL cpu_to_le32(0xC0140015) -#define STATUS_ACPI_MUTEX_NOT_OWNED cpu_to_le32(0xC0140016) -#define STATUS_ACPI_MUTEX_NOT_OWNER cpu_to_le32(0xC0140017) -#define STATUS_ACPI_RS_ACCESS cpu_to_le32(0xC0140018) -#define STATUS_ACPI_INVALID_TABLE cpu_to_le32(0xC0140019) -#define STATUS_ACPI_REG_HANDLER_FAILED cpu_to_le32(0xC0140020) -#define STATUS_ACPI_POWER_REQUEST_FAILED cpu_to_le32(0xC0140021) -#define STATUS_SXS_SECTION_NOT_FOUND cpu_to_le32(0xC0150001) -#define STATUS_SXS_CANT_GEN_ACTCTX cpu_to_le32(0xC0150002) -#define STATUS_SXS_INVALID_ACTCTXDATA_FORMAT cpu_to_le32(0xC0150003) -#define STATUS_SXS_ASSEMBLY_NOT_FOUND cpu_to_le32(0xC0150004) -#define STATUS_SXS_MANIFEST_FORMAT_ERROR cpu_to_le32(0xC0150005) -#define STATUS_SXS_MANIFEST_PARSE_ERROR cpu_to_le32(0xC0150006) -#define STATUS_SXS_ACTIVATION_CONTEXT_DISABLED cpu_to_le32(0xC0150007) -#define STATUS_SXS_KEY_NOT_FOUND cpu_to_le32(0xC0150008) -#define STATUS_SXS_VERSION_CONFLICT cpu_to_le32(0xC0150009) -#define STATUS_SXS_WRONG_SECTION_TYPE cpu_to_le32(0xC015000A) -#define STATUS_SXS_THREAD_QUERIES_DISABLED cpu_to_le32(0xC015000B) -#define STATUS_SXS_ASSEMBLY_MISSING cpu_to_le32(0xC015000C) -#define STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET cpu_to_le32(0xC015000E) -#define STATUS_SXS_EARLY_DEACTIVATION cpu_to_le32(0xC015000F) -#define STATUS_SXS_INVALID_DEACTIVATION cpu_to_le32(0xC0150010) -#define STATUS_SXS_MULTIPLE_DEACTIVATION cpu_to_le32(0xC0150011) -#define STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY \ - cpu_to_le32(0xC0150012) -#define STATUS_SXS_PROCESS_TERMINATION_REQUESTED cpu_to_le32(0xC0150013) -#define STATUS_SXS_CORRUPT_ACTIVATION_STACK cpu_to_le32(0xC0150014) -#define STATUS_SXS_CORRUPTION cpu_to_le32(0xC0150015) -#define STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE cpu_to_le32(0xC0150016) -#define STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME cpu_to_le32(0xC0150017) -#define STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE cpu_to_le32(0xC0150018) -#define STATUS_SXS_IDENTITY_PARSE_ERROR cpu_to_le32(0xC0150019) -#define STATUS_SXS_COMPONENT_STORE_CORRUPT cpu_to_le32(0xC015001A) -#define STATUS_SXS_FILE_HASH_MISMATCH cpu_to_le32(0xC015001B) -#define STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT \ - cpu_to_le32(0xC015001C) -#define STATUS_SXS_IDENTITIES_DIFFERENT cpu_to_le32(0xC015001D) -#define STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT cpu_to_le32(0xC015001E) -#define STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY cpu_to_le32(0xC015001F) -#define STATUS_ADVANCED_INSTALLER_FAILED cpu_to_le32(0xC0150020) -#define STATUS_XML_ENCODING_MISMATCH cpu_to_le32(0xC0150021) -#define STATUS_SXS_MANIFEST_TOO_BIG cpu_to_le32(0xC0150022) -#define STATUS_SXS_SETTING_NOT_REGISTERED cpu_to_le32(0xC0150023) -#define STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE cpu_to_le32(0xC0150024) -#define STATUS_SMI_PRIMITIVE_INSTALLER_FAILED cpu_to_le32(0xC0150025) -#define STATUS_GENERIC_COMMAND_FAILED cpu_to_le32(0xC0150026) -#define STATUS_SXS_FILE_HASH_MISSING cpu_to_le32(0xC0150027) -#define STATUS_TRANSACTIONAL_CONFLICT cpu_to_le32(0xC0190001) -#define STATUS_INVALID_TRANSACTION cpu_to_le32(0xC0190002) -#define STATUS_TRANSACTION_NOT_ACTIVE cpu_to_le32(0xC0190003) -#define STATUS_TM_INITIALIZATION_FAILED cpu_to_le32(0xC0190004) -#define STATUS_RM_NOT_ACTIVE cpu_to_le32(0xC0190005) -#define STATUS_RM_METADATA_CORRUPT cpu_to_le32(0xC0190006) -#define STATUS_TRANSACTION_NOT_JOINED cpu_to_le32(0xC0190007) -#define STATUS_DIRECTORY_NOT_RM cpu_to_le32(0xC0190008) -#define STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE cpu_to_le32(0xC019000A) -#define STATUS_LOG_RESIZE_INVALID_SIZE cpu_to_le32(0xC019000B) -#define STATUS_REMOTE_FILE_VERSION_MISMATCH cpu_to_le32(0xC019000C) -#define STATUS_CRM_PROTOCOL_ALREADY_EXISTS cpu_to_le32(0xC019000F) -#define STATUS_TRANSACTION_PROPAGATION_FAILED cpu_to_le32(0xC0190010) -#define STATUS_CRM_PROTOCOL_NOT_FOUND cpu_to_le32(0xC0190011) -#define STATUS_TRANSACTION_SUPERIOR_EXISTS cpu_to_le32(0xC0190012) -#define STATUS_TRANSACTION_REQUEST_NOT_VALID cpu_to_le32(0xC0190013) -#define STATUS_TRANSACTION_NOT_REQUESTED cpu_to_le32(0xC0190014) -#define STATUS_TRANSACTION_ALREADY_ABORTED cpu_to_le32(0xC0190015) -#define STATUS_TRANSACTION_ALREADY_COMMITTED cpu_to_le32(0xC0190016) -#define STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER cpu_to_le32(0xC0190017) -#define STATUS_CURRENT_TRANSACTION_NOT_VALID cpu_to_le32(0xC0190018) -#define STATUS_LOG_GROWTH_FAILED cpu_to_le32(0xC0190019) -#define STATUS_OBJECT_NO_LONGER_EXISTS cpu_to_le32(0xC0190021) -#define STATUS_STREAM_MINIVERSION_NOT_FOUND cpu_to_le32(0xC0190022) -#define STATUS_STREAM_MINIVERSION_NOT_VALID cpu_to_le32(0xC0190023) -#define STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION \ - cpu_to_le32(0xC0190024) -#define STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT cpu_to_le32(0xC0190025) -#define STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS cpu_to_le32(0xC0190026) -#define STATUS_HANDLE_NO_LONGER_VALID cpu_to_le32(0xC0190028) -#define STATUS_LOG_CORRUPTION_DETECTED cpu_to_le32(0xC0190030) -#define STATUS_RM_DISCONNECTED cpu_to_le32(0xC0190032) -#define STATUS_ENLISTMENT_NOT_SUPERIOR cpu_to_le32(0xC0190033) -#define STATUS_FILE_IDENTITY_NOT_PERSISTENT cpu_to_le32(0xC0190036) -#define STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY cpu_to_le32(0xC0190037) -#define STATUS_CANT_CROSS_RM_BOUNDARY cpu_to_le32(0xC0190038) -#define STATUS_TXF_DIR_NOT_EMPTY cpu_to_le32(0xC0190039) -#define STATUS_INDOUBT_TRANSACTIONS_EXIST cpu_to_le32(0xC019003A) -#define STATUS_TM_VOLATILE cpu_to_le32(0xC019003B) -#define STATUS_ROLLBACK_TIMER_EXPIRED cpu_to_le32(0xC019003C) -#define STATUS_TXF_ATTRIBUTE_CORRUPT cpu_to_le32(0xC019003D) -#define STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION cpu_to_le32(0xC019003E) -#define STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED cpu_to_le32(0xC019003F) -#define STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE cpu_to_le32(0xC0190040) -#define STATUS_TRANSACTION_REQUIRED_PROMOTION cpu_to_le32(0xC0190043) -#define STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION cpu_to_le32(0xC0190044) -#define STATUS_TRANSACTIONS_NOT_FROZEN cpu_to_le32(0xC0190045) -#define STATUS_TRANSACTION_FREEZE_IN_PROGRESS cpu_to_le32(0xC0190046) -#define STATUS_NOT_SNAPSHOT_VOLUME cpu_to_le32(0xC0190047) -#define STATUS_NO_SAVEPOINT_WITH_OPEN_FILES cpu_to_le32(0xC0190048) -#define STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION cpu_to_le32(0xC0190049) -#define STATUS_TM_IDENTITY_MISMATCH cpu_to_le32(0xC019004A) -#define STATUS_FLOATED_SECTION cpu_to_le32(0xC019004B) -#define STATUS_CANNOT_ACCEPT_TRANSACTED_WORK cpu_to_le32(0xC019004C) -#define STATUS_CANNOT_ABORT_TRANSACTIONS cpu_to_le32(0xC019004D) -#define STATUS_TRANSACTION_NOT_FOUND cpu_to_le32(0xC019004E) -#define STATUS_RESOURCEMANAGER_NOT_FOUND cpu_to_le32(0xC019004F) -#define STATUS_ENLISTMENT_NOT_FOUND cpu_to_le32(0xC0190050) -#define STATUS_TRANSACTIONMANAGER_NOT_FOUND cpu_to_le32(0xC0190051) -#define STATUS_TRANSACTIONMANAGER_NOT_ONLINE cpu_to_le32(0xC0190052) -#define STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION \ - cpu_to_le32(0xC0190053) -#define STATUS_TRANSACTION_NOT_ROOT cpu_to_le32(0xC0190054) -#define STATUS_TRANSACTION_OBJECT_EXPIRED cpu_to_le32(0xC0190055) -#define STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION cpu_to_le32(0xC0190056) -#define STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED cpu_to_le32(0xC0190057) -#define STATUS_TRANSACTION_RECORD_TOO_LONG cpu_to_le32(0xC0190058) -#define STATUS_NO_LINK_TRACKING_IN_TRANSACTION cpu_to_le32(0xC0190059) -#define STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION cpu_to_le32(0xC019005A) -#define STATUS_TRANSACTION_INTEGRITY_VIOLATED cpu_to_le32(0xC019005B) -#define STATUS_LOG_SECTOR_INVALID cpu_to_le32(0xC01A0001) -#define STATUS_LOG_SECTOR_PARITY_INVALID cpu_to_le32(0xC01A0002) -#define STATUS_LOG_SECTOR_REMAPPED cpu_to_le32(0xC01A0003) -#define STATUS_LOG_BLOCK_INCOMPLETE cpu_to_le32(0xC01A0004) -#define STATUS_LOG_INVALID_RANGE cpu_to_le32(0xC01A0005) -#define STATUS_LOG_BLOCKS_EXHAUSTED cpu_to_le32(0xC01A0006) -#define STATUS_LOG_READ_CONTEXT_INVALID cpu_to_le32(0xC01A0007) -#define STATUS_LOG_RESTART_INVALID cpu_to_le32(0xC01A0008) -#define STATUS_LOG_BLOCK_VERSION cpu_to_le32(0xC01A0009) -#define STATUS_LOG_BLOCK_INVALID cpu_to_le32(0xC01A000A) -#define STATUS_LOG_READ_MODE_INVALID cpu_to_le32(0xC01A000B) -#define STATUS_LOG_METADATA_CORRUPT cpu_to_le32(0xC01A000D) -#define STATUS_LOG_METADATA_INVALID cpu_to_le32(0xC01A000E) -#define STATUS_LOG_METADATA_INCONSISTENT cpu_to_le32(0xC01A000F) -#define STATUS_LOG_RESERVATION_INVALID cpu_to_le32(0xC01A0010) -#define STATUS_LOG_CANT_DELETE cpu_to_le32(0xC01A0011) -#define STATUS_LOG_CONTAINER_LIMIT_EXCEEDED cpu_to_le32(0xC01A0012) -#define STATUS_LOG_START_OF_LOG cpu_to_le32(0xC01A0013) -#define STATUS_LOG_POLICY_ALREADY_INSTALLED cpu_to_le32(0xC01A0014) -#define STATUS_LOG_POLICY_NOT_INSTALLED cpu_to_le32(0xC01A0015) -#define STATUS_LOG_POLICY_INVALID cpu_to_le32(0xC01A0016) -#define STATUS_LOG_POLICY_CONFLICT cpu_to_le32(0xC01A0017) -#define STATUS_LOG_PINNED_ARCHIVE_TAIL cpu_to_le32(0xC01A0018) -#define STATUS_LOG_RECORD_NONEXISTENT cpu_to_le32(0xC01A0019) -#define STATUS_LOG_RECORDS_RESERVED_INVALID cpu_to_le32(0xC01A001A) -#define STATUS_LOG_SPACE_RESERVED_INVALID cpu_to_le32(0xC01A001B) -#define STATUS_LOG_TAIL_INVALID cpu_to_le32(0xC01A001C) -#define STATUS_LOG_FULL cpu_to_le32(0xC01A001D) -#define STATUS_LOG_MULTIPLEXED cpu_to_le32(0xC01A001E) -#define STATUS_LOG_DEDICATED cpu_to_le32(0xC01A001F) -#define STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS cpu_to_le32(0xC01A0020) -#define STATUS_LOG_ARCHIVE_IN_PROGRESS cpu_to_le32(0xC01A0021) -#define STATUS_LOG_EPHEMERAL cpu_to_le32(0xC01A0022) -#define STATUS_LOG_NOT_ENOUGH_CONTAINERS cpu_to_le32(0xC01A0023) -#define STATUS_LOG_CLIENT_ALREADY_REGISTERED cpu_to_le32(0xC01A0024) -#define STATUS_LOG_CLIENT_NOT_REGISTERED cpu_to_le32(0xC01A0025) -#define STATUS_LOG_FULL_HANDLER_IN_PROGRESS cpu_to_le32(0xC01A0026) -#define STATUS_LOG_CONTAINER_READ_FAILED cpu_to_le32(0xC01A0027) -#define STATUS_LOG_CONTAINER_WRITE_FAILED cpu_to_le32(0xC01A0028) -#define STATUS_LOG_CONTAINER_OPEN_FAILED cpu_to_le32(0xC01A0029) -#define STATUS_LOG_CONTAINER_STATE_INVALID cpu_to_le32(0xC01A002A) -#define STATUS_LOG_STATE_INVALID cpu_to_le32(0xC01A002B) -#define STATUS_LOG_PINNED cpu_to_le32(0xC01A002C) -#define STATUS_LOG_METADATA_FLUSH_FAILED cpu_to_le32(0xC01A002D) -#define STATUS_LOG_INCONSISTENT_SECURITY cpu_to_le32(0xC01A002E) -#define STATUS_LOG_APPENDED_FLUSH_FAILED cpu_to_le32(0xC01A002F) -#define STATUS_LOG_PINNED_RESERVATION cpu_to_le32(0xC01A0030) -#define STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD cpu_to_le32(0xC01B00EA) -#define STATUS_FLT_NO_HANDLER_DEFINED cpu_to_le32(0xC01C0001) -#define STATUS_FLT_CONTEXT_ALREADY_DEFINED cpu_to_le32(0xC01C0002) -#define STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST cpu_to_le32(0xC01C0003) -#define STATUS_FLT_DISALLOW_FAST_IO cpu_to_le32(0xC01C0004) -#define STATUS_FLT_INVALID_NAME_REQUEST cpu_to_le32(0xC01C0005) -#define STATUS_FLT_NOT_SAFE_TO_POST_OPERATION cpu_to_le32(0xC01C0006) -#define STATUS_FLT_NOT_INITIALIZED cpu_to_le32(0xC01C0007) -#define STATUS_FLT_FILTER_NOT_READY cpu_to_le32(0xC01C0008) -#define STATUS_FLT_POST_OPERATION_CLEANUP cpu_to_le32(0xC01C0009) -#define STATUS_FLT_INTERNAL_ERROR cpu_to_le32(0xC01C000A) -#define STATUS_FLT_DELETING_OBJECT cpu_to_le32(0xC01C000B) -#define STATUS_FLT_MUST_BE_NONPAGED_POOL cpu_to_le32(0xC01C000C) -#define STATUS_FLT_DUPLICATE_ENTRY cpu_to_le32(0xC01C000D) -#define STATUS_FLT_CBDQ_DISABLED cpu_to_le32(0xC01C000E) -#define STATUS_FLT_DO_NOT_ATTACH cpu_to_le32(0xC01C000F) -#define STATUS_FLT_DO_NOT_DETACH cpu_to_le32(0xC01C0010) -#define STATUS_FLT_INSTANCE_ALTITUDE_COLLISION cpu_to_le32(0xC01C0011) -#define STATUS_FLT_INSTANCE_NAME_COLLISION cpu_to_le32(0xC01C0012) -#define STATUS_FLT_FILTER_NOT_FOUND cpu_to_le32(0xC01C0013) -#define STATUS_FLT_VOLUME_NOT_FOUND cpu_to_le32(0xC01C0014) -#define STATUS_FLT_INSTANCE_NOT_FOUND cpu_to_le32(0xC01C0015) -#define STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND cpu_to_le32(0xC01C0016) -#define STATUS_FLT_INVALID_CONTEXT_REGISTRATION cpu_to_le32(0xC01C0017) -#define STATUS_FLT_NAME_CACHE_MISS cpu_to_le32(0xC01C0018) -#define STATUS_FLT_NO_DEVICE_OBJECT cpu_to_le32(0xC01C0019) -#define STATUS_FLT_VOLUME_ALREADY_MOUNTED cpu_to_le32(0xC01C001A) -#define STATUS_FLT_ALREADY_ENLISTED cpu_to_le32(0xC01C001B) -#define STATUS_FLT_CONTEXT_ALREADY_LINKED cpu_to_le32(0xC01C001C) -#define STATUS_FLT_NO_WAITER_FOR_REPLY cpu_to_le32(0xC01C0020) -#define STATUS_MONITOR_NO_DESCRIPTOR cpu_to_le32(0xC01D0001) -#define STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT cpu_to_le32(0xC01D0002) -#define STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM cpu_to_le32(0xC01D0003) -#define STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK cpu_to_le32(0xC01D0004) -#define STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED cpu_to_le32(0xC01D0005) -#define STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK \ - cpu_to_le32(0xC01D0006) -#define STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK \ - cpu_to_le32(0xC01D0007) -#define STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA cpu_to_le32(0xC01D0008) -#define STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK cpu_to_le32(0xC01D0009) -#define STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER cpu_to_le32(0xC01E0000) -#define STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER cpu_to_le32(0xC01E0001) -#define STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER cpu_to_le32(0xC01E0002) -#define STATUS_GRAPHICS_ADAPTER_WAS_RESET cpu_to_le32(0xC01E0003) -#define STATUS_GRAPHICS_INVALID_DRIVER_MODEL cpu_to_le32(0xC01E0004) -#define STATUS_GRAPHICS_PRESENT_MODE_CHANGED cpu_to_le32(0xC01E0005) -#define STATUS_GRAPHICS_PRESENT_OCCLUDED cpu_to_le32(0xC01E0006) -#define STATUS_GRAPHICS_PRESENT_DENIED cpu_to_le32(0xC01E0007) -#define STATUS_GRAPHICS_CANNOTCOLORCONVERT cpu_to_le32(0xC01E0008) -#define STATUS_GRAPHICS_NO_VIDEO_MEMORY cpu_to_le32(0xC01E0100) -#define STATUS_GRAPHICS_CANT_LOCK_MEMORY cpu_to_le32(0xC01E0101) -#define STATUS_GRAPHICS_ALLOCATION_BUSY cpu_to_le32(0xC01E0102) -#define STATUS_GRAPHICS_TOO_MANY_REFERENCES cpu_to_le32(0xC01E0103) -#define STATUS_GRAPHICS_TRY_AGAIN_LATER cpu_to_le32(0xC01E0104) -#define STATUS_GRAPHICS_TRY_AGAIN_NOW cpu_to_le32(0xC01E0105) -#define STATUS_GRAPHICS_ALLOCATION_INVALID cpu_to_le32(0xC01E0106) -#define STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE cpu_to_le32(0xC01E0107) -#define STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED cpu_to_le32(0xC01E0108) -#define STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION cpu_to_le32(0xC01E0109) -#define STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE cpu_to_le32(0xC01E0110) -#define STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION cpu_to_le32(0xC01E0111) -#define STATUS_GRAPHICS_ALLOCATION_CLOSED cpu_to_le32(0xC01E0112) -#define STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE cpu_to_le32(0xC01E0113) -#define STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE cpu_to_le32(0xC01E0114) -#define STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE cpu_to_le32(0xC01E0115) -#define STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST cpu_to_le32(0xC01E0116) -#define STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE cpu_to_le32(0xC01E0200) -#define STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY cpu_to_le32(0xC01E0300) -#define STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED cpu_to_le32(0xC01E0301) -#define STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED \ - cpu_to_le32(0xC01E0302) -#define STATUS_GRAPHICS_INVALID_VIDPN cpu_to_le32(0xC01E0303) -#define STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE cpu_to_le32(0xC01E0304) -#define STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET cpu_to_le32(0xC01E0305) -#define STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED cpu_to_le32(0xC01E0306) -#define STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET cpu_to_le32(0xC01E0308) -#define STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET cpu_to_le32(0xC01E0309) -#define STATUS_GRAPHICS_INVALID_FREQUENCY cpu_to_le32(0xC01E030A) -#define STATUS_GRAPHICS_INVALID_ACTIVE_REGION cpu_to_le32(0xC01E030B) -#define STATUS_GRAPHICS_INVALID_TOTAL_REGION cpu_to_le32(0xC01E030C) -#define STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE \ - cpu_to_le32(0xC01E0310) -#define STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE \ - cpu_to_le32(0xC01E0311) -#define STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET cpu_to_le32(0xC01E0312) -#define STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY cpu_to_le32(0xC01E0313) -#define STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET cpu_to_le32(0xC01E0314) -#define STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET cpu_to_le32(0xC01E0315) -#define STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET cpu_to_le32(0xC01E0316) -#define STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET cpu_to_le32(0xC01E0317) -#define STATUS_GRAPHICS_TARGET_ALREADY_IN_SET cpu_to_le32(0xC01E0318) -#define STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH cpu_to_le32(0xC01E0319) -#define STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY cpu_to_le32(0xC01E031A) -#define STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET \ - cpu_to_le32(0xC01E031B) -#define STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE cpu_to_le32(0xC01E031C) -#define STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET cpu_to_le32(0xC01E031D) -#define STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET cpu_to_le32(0xC01E031F) -#define STATUS_GRAPHICS_STALE_MODESET cpu_to_le32(0xC01E0320) -#define STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET cpu_to_le32(0xC01E0321) -#define STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE cpu_to_le32(0xC01E0322) -#define STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN cpu_to_le32(0xC01E0323) -#define STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE cpu_to_le32(0xC01E0324) -#define STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION \ - cpu_to_le32(0xC01E0325) -#define STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES \ - cpu_to_le32(0xC01E0326) -#define STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY cpu_to_le32(0xC01E0327) -#define STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE \ - cpu_to_le32(0xC01E0328) -#define STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET \ - cpu_to_le32(0xC01E0329) -#define STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET cpu_to_le32(0xC01E032A) -#define STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR cpu_to_le32(0xC01E032B) -#define STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET cpu_to_le32(0xC01E032C) -#define STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET cpu_to_le32(0xC01E032D) -#define STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE \ - cpu_to_le32(0xC01E032E) -#define STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE cpu_to_le32(0xC01E032F) -#define STATUS_GRAPHICS_RESOURCES_NOT_RELATED cpu_to_le32(0xC01E0330) -#define STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE cpu_to_le32(0xC01E0331) -#define STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE cpu_to_le32(0xC01E0332) -#define STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET cpu_to_le32(0xC01E0333) -#define STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER \ - cpu_to_le32(0xC01E0334) -#define STATUS_GRAPHICS_NO_VIDPNMGR cpu_to_le32(0xC01E0335) -#define STATUS_GRAPHICS_NO_ACTIVE_VIDPN cpu_to_le32(0xC01E0336) -#define STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY cpu_to_le32(0xC01E0337) -#define STATUS_GRAPHICS_MONITOR_NOT_CONNECTED cpu_to_le32(0xC01E0338) -#define STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY cpu_to_le32(0xC01E0339) -#define STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE cpu_to_le32(0xC01E033A) -#define STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE cpu_to_le32(0xC01E033B) -#define STATUS_GRAPHICS_INVALID_STRIDE cpu_to_le32(0xC01E033C) -#define STATUS_GRAPHICS_INVALID_PIXELFORMAT cpu_to_le32(0xC01E033D) -#define STATUS_GRAPHICS_INVALID_COLORBASIS cpu_to_le32(0xC01E033E) -#define STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE cpu_to_le32(0xC01E033F) -#define STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY cpu_to_le32(0xC01E0340) -#define STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT \ - cpu_to_le32(0xC01E0341) -#define STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE cpu_to_le32(0xC01E0342) -#define STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN cpu_to_le32(0xC01E0343) -#define STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL cpu_to_le32(0xC01E0344) -#define STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION \ - cpu_to_le32(0xC01E0345) -#define STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED \ - cpu_to_le32(0xC01E0346) -#define STATUS_GRAPHICS_INVALID_GAMMA_RAMP cpu_to_le32(0xC01E0347) -#define STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED cpu_to_le32(0xC01E0348) -#define STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED cpu_to_le32(0xC01E0349) -#define STATUS_GRAPHICS_MODE_NOT_IN_MODESET cpu_to_le32(0xC01E034A) -#define STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON \ - cpu_to_le32(0xC01E034D) -#define STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE cpu_to_le32(0xC01E034E) -#define STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE cpu_to_le32(0xC01E034F) -#define STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS \ - cpu_to_le32(0xC01E0350) -#define STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING cpu_to_le32(0xC01E0352) -#define STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED cpu_to_le32(0xC01E0353) -#define STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS cpu_to_le32(0xC01E0354) -#define STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT cpu_to_le32(0xC01E0355) -#define STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM cpu_to_le32(0xC01E0356) -#define STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN \ - cpu_to_le32(0xC01E0357) -#define STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT \ - cpu_to_le32(0xC01E0358) -#define STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED cpu_to_le32(0xC01E0359) -#define STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION \ - cpu_to_le32(0xC01E035A) -#define STATUS_GRAPHICS_INVALID_CLIENT_TYPE cpu_to_le32(0xC01E035B) -#define STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET cpu_to_le32(0xC01E035C) -#define STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED \ - cpu_to_le32(0xC01E0400) -#define STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED cpu_to_le32(0xC01E0401) -#define STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER cpu_to_le32(0xC01E0430) -#define STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED cpu_to_le32(0xC01E0431) -#define STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED cpu_to_le32(0xC01E0432) -#define STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY cpu_to_le32(0xC01E0433) -#define STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED cpu_to_le32(0xC01E0434) -#define STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON cpu_to_le32(0xC01E0435) -#define STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE cpu_to_le32(0xC01E0436) -#define STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER cpu_to_le32(0xC01E0438) -#define STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED cpu_to_le32(0xC01E043B) -#define STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS \ - cpu_to_le32(0xC01E051C) -#define STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST cpu_to_le32(0xC01E051D) -#define STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR cpu_to_le32(0xC01E051E) -#define STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS \ - cpu_to_le32(0xC01E051F) -#define STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED cpu_to_le32(0xC01E0520) -#define STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST \ - cpu_to_le32(0xC01E0521) -#define STATUS_GRAPHICS_OPM_NOT_SUPPORTED cpu_to_le32(0xC01E0500) -#define STATUS_GRAPHICS_COPP_NOT_SUPPORTED cpu_to_le32(0xC01E0501) -#define STATUS_GRAPHICS_UAB_NOT_SUPPORTED cpu_to_le32(0xC01E0502) -#define STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS cpu_to_le32(0xC01E0503) -#define STATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL cpu_to_le32(0xC01E0504) -#define STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST cpu_to_le32(0xC01E0505) -#define STATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME \ - cpu_to_le32(0xC01E0506) -#define STATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP \ - cpu_to_le32(0xC01E0507) -#define STATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED \ - cpu_to_le32(0xC01E0508) -#define STATUS_GRAPHICS_OPM_INVALID_POINTER cpu_to_le32(0xC01E050A) -#define STATUS_GRAPHICS_OPM_INTERNAL_ERROR cpu_to_le32(0xC01E050B) -#define STATUS_GRAPHICS_OPM_INVALID_HANDLE cpu_to_le32(0xC01E050C) -#define STATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE \ - cpu_to_le32(0xC01E050D) -#define STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH cpu_to_le32(0xC01E050E) -#define STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED cpu_to_le32(0xC01E050F) -#define STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED cpu_to_le32(0xC01E0510) -#define STATUS_GRAPHICS_PVP_HFS_FAILED cpu_to_le32(0xC01E0511) -#define STATUS_GRAPHICS_OPM_INVALID_SRM cpu_to_le32(0xC01E0512) -#define STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP cpu_to_le32(0xC01E0513) -#define STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP cpu_to_le32(0xC01E0514) -#define STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA \ - cpu_to_le32(0xC01E0515) -#define STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET cpu_to_le32(0xC01E0516) -#define STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH cpu_to_le32(0xC01E0517) -#define STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE \ - cpu_to_le32(0xC01E0518) -#define STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS \ - cpu_to_le32(0xC01E051A) -#define STATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS \ - cpu_to_le32(0xC01E051B) -#define STATUS_GRAPHICS_I2C_NOT_SUPPORTED cpu_to_le32(0xC01E0580) -#define STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST cpu_to_le32(0xC01E0581) -#define STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA cpu_to_le32(0xC01E0582) -#define STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA cpu_to_le32(0xC01E0583) -#define STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED cpu_to_le32(0xC01E0584) -#define STATUS_GRAPHICS_DDCCI_INVALID_DATA cpu_to_le32(0xC01E0585) -#define STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE \ - cpu_to_le32(0xC01E0586) -#define STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING \ - cpu_to_le32(0xC01E0587) -#define STATUS_GRAPHICS_MCA_INTERNAL_ERROR cpu_to_le32(0xC01E0588) -#define STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND cpu_to_le32(0xC01E0589) -#define STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH cpu_to_le32(0xC01E058A) -#define STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM cpu_to_le32(0xC01E058B) -#define STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE cpu_to_le32(0xC01E058C) -#define STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS cpu_to_le32(0xC01E058D) -#define STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED cpu_to_le32(0xC01E05E0) -#define STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME \ - cpu_to_le32(0xC01E05E1) -#define STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP \ - cpu_to_le32(0xC01E05E2) -#define STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED cpu_to_le32(0xC01E05E3) -#define STATUS_GRAPHICS_INVALID_POINTER cpu_to_le32(0xC01E05E4) -#define STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE \ - cpu_to_le32(0xC01E05E5) -#define STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL cpu_to_le32(0xC01E05E6) -#define STATUS_GRAPHICS_INTERNAL_ERROR cpu_to_le32(0xC01E05E7) -#define STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS cpu_to_le32(0xC01E05E8) -#define STATUS_FVE_LOCKED_VOLUME cpu_to_le32(0xC0210000) -#define STATUS_FVE_NOT_ENCRYPTED cpu_to_le32(0xC0210001) -#define STATUS_FVE_BAD_INFORMATION cpu_to_le32(0xC0210002) -#define STATUS_FVE_TOO_SMALL cpu_to_le32(0xC0210003) -#define STATUS_FVE_FAILED_WRONG_FS cpu_to_le32(0xC0210004) -#define STATUS_FVE_FAILED_BAD_FS cpu_to_le32(0xC0210005) -#define STATUS_FVE_FS_NOT_EXTENDED cpu_to_le32(0xC0210006) -#define STATUS_FVE_FS_MOUNTED cpu_to_le32(0xC0210007) -#define STATUS_FVE_NO_LICENSE cpu_to_le32(0xC0210008) -#define STATUS_FVE_ACTION_NOT_ALLOWED cpu_to_le32(0xC0210009) -#define STATUS_FVE_BAD_DATA cpu_to_le32(0xC021000A) -#define STATUS_FVE_VOLUME_NOT_BOUND cpu_to_le32(0xC021000B) -#define STATUS_FVE_NOT_DATA_VOLUME cpu_to_le32(0xC021000C) -#define STATUS_FVE_CONV_READ_ERROR cpu_to_le32(0xC021000D) -#define STATUS_FVE_CONV_WRITE_ERROR cpu_to_le32(0xC021000E) -#define STATUS_FVE_OVERLAPPED_UPDATE cpu_to_le32(0xC021000F) -#define STATUS_FVE_FAILED_SECTOR_SIZE cpu_to_le32(0xC0210010) -#define STATUS_FVE_FAILED_AUTHENTICATION cpu_to_le32(0xC0210011) -#define STATUS_FVE_NOT_OS_VOLUME cpu_to_le32(0xC0210012) -#define STATUS_FVE_KEYFILE_NOT_FOUND cpu_to_le32(0xC0210013) -#define STATUS_FVE_KEYFILE_INVALID cpu_to_le32(0xC0210014) -#define STATUS_FVE_KEYFILE_NO_VMK cpu_to_le32(0xC0210015) -#define STATUS_FVE_TPM_DISABLED cpu_to_le32(0xC0210016) -#define STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO cpu_to_le32(0xC0210017) -#define STATUS_FVE_TPM_INVALID_PCR cpu_to_le32(0xC0210018) -#define STATUS_FVE_TPM_NO_VMK cpu_to_le32(0xC0210019) -#define STATUS_FVE_PIN_INVALID cpu_to_le32(0xC021001A) -#define STATUS_FVE_AUTH_INVALID_APPLICATION cpu_to_le32(0xC021001B) -#define STATUS_FVE_AUTH_INVALID_CONFIG cpu_to_le32(0xC021001C) -#define STATUS_FVE_DEBUGGER_ENABLED cpu_to_le32(0xC021001D) -#define STATUS_FVE_DRY_RUN_FAILED cpu_to_le32(0xC021001E) -#define STATUS_FVE_BAD_METADATA_POINTER cpu_to_le32(0xC021001F) -#define STATUS_FVE_OLD_METADATA_COPY cpu_to_le32(0xC0210020) -#define STATUS_FVE_REBOOT_REQUIRED cpu_to_le32(0xC0210021) -#define STATUS_FVE_RAW_ACCESS cpu_to_le32(0xC0210022) -#define STATUS_FVE_RAW_BLOCKED cpu_to_le32(0xC0210023) -#define STATUS_FWP_CALLOUT_NOT_FOUND cpu_to_le32(0xC0220001) -#define STATUS_FWP_CONDITION_NOT_FOUND cpu_to_le32(0xC0220002) -#define STATUS_FWP_FILTER_NOT_FOUND cpu_to_le32(0xC0220003) -#define STATUS_FWP_LAYER_NOT_FOUND cpu_to_le32(0xC0220004) -#define STATUS_FWP_PROVIDER_NOT_FOUND cpu_to_le32(0xC0220005) -#define STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND cpu_to_le32(0xC0220006) -#define STATUS_FWP_SUBLAYER_NOT_FOUND cpu_to_le32(0xC0220007) -#define STATUS_FWP_NOT_FOUND cpu_to_le32(0xC0220008) -#define STATUS_FWP_ALREADY_EXISTS cpu_to_le32(0xC0220009) -#define STATUS_FWP_IN_USE cpu_to_le32(0xC022000A) -#define STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS cpu_to_le32(0xC022000B) -#define STATUS_FWP_WRONG_SESSION cpu_to_le32(0xC022000C) -#define STATUS_FWP_NO_TXN_IN_PROGRESS cpu_to_le32(0xC022000D) -#define STATUS_FWP_TXN_IN_PROGRESS cpu_to_le32(0xC022000E) -#define STATUS_FWP_TXN_ABORTED cpu_to_le32(0xC022000F) -#define STATUS_FWP_SESSION_ABORTED cpu_to_le32(0xC0220010) -#define STATUS_FWP_INCOMPATIBLE_TXN cpu_to_le32(0xC0220011) -#define STATUS_FWP_TIMEOUT cpu_to_le32(0xC0220012) -#define STATUS_FWP_NET_EVENTS_DISABLED cpu_to_le32(0xC0220013) -#define STATUS_FWP_INCOMPATIBLE_LAYER cpu_to_le32(0xC0220014) -#define STATUS_FWP_KM_CLIENTS_ONLY cpu_to_le32(0xC0220015) -#define STATUS_FWP_LIFETIME_MISMATCH cpu_to_le32(0xC0220016) -#define STATUS_FWP_BUILTIN_OBJECT cpu_to_le32(0xC0220017) -#define STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS cpu_to_le32(0xC0220018) -#define STATUS_FWP_TOO_MANY_CALLOUTS cpu_to_le32(0xC0220018) -#define STATUS_FWP_NOTIFICATION_DROPPED cpu_to_le32(0xC0220019) -#define STATUS_FWP_TRAFFIC_MISMATCH cpu_to_le32(0xC022001A) -#define STATUS_FWP_INCOMPATIBLE_SA_STATE cpu_to_le32(0xC022001B) -#define STATUS_FWP_NULL_POINTER cpu_to_le32(0xC022001C) -#define STATUS_FWP_INVALID_ENUMERATOR cpu_to_le32(0xC022001D) -#define STATUS_FWP_INVALID_FLAGS cpu_to_le32(0xC022001E) -#define STATUS_FWP_INVALID_NET_MASK cpu_to_le32(0xC022001F) -#define STATUS_FWP_INVALID_RANGE cpu_to_le32(0xC0220020) -#define STATUS_FWP_INVALID_INTERVAL cpu_to_le32(0xC0220021) -#define STATUS_FWP_ZERO_LENGTH_ARRAY cpu_to_le32(0xC0220022) -#define STATUS_FWP_NULL_DISPLAY_NAME cpu_to_le32(0xC0220023) -#define STATUS_FWP_INVALID_ACTION_TYPE cpu_to_le32(0xC0220024) -#define STATUS_FWP_INVALID_WEIGHT cpu_to_le32(0xC0220025) -#define STATUS_FWP_MATCH_TYPE_MISMATCH cpu_to_le32(0xC0220026) -#define STATUS_FWP_TYPE_MISMATCH cpu_to_le32(0xC0220027) -#define STATUS_FWP_OUT_OF_BOUNDS cpu_to_le32(0xC0220028) -#define STATUS_FWP_RESERVED cpu_to_le32(0xC0220029) -#define STATUS_FWP_DUPLICATE_CONDITION cpu_to_le32(0xC022002A) -#define STATUS_FWP_DUPLICATE_KEYMOD cpu_to_le32(0xC022002B) -#define STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER cpu_to_le32(0xC022002C) -#define STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER cpu_to_le32(0xC022002D) -#define STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER cpu_to_le32(0xC022002E) -#define STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT cpu_to_le32(0xC022002F) -#define STATUS_FWP_INCOMPATIBLE_AUTH_METHOD cpu_to_le32(0xC0220030) -#define STATUS_FWP_INCOMPATIBLE_DH_GROUP cpu_to_le32(0xC0220031) -#define STATUS_FWP_EM_NOT_SUPPORTED cpu_to_le32(0xC0220032) -#define STATUS_FWP_NEVER_MATCH cpu_to_le32(0xC0220033) -#define STATUS_FWP_PROVIDER_CONTEXT_MISMATCH cpu_to_le32(0xC0220034) -#define STATUS_FWP_INVALID_PARAMETER cpu_to_le32(0xC0220035) -#define STATUS_FWP_TOO_MANY_SUBLAYERS cpu_to_le32(0xC0220036) -#define STATUS_FWP_CALLOUT_NOTIFICATION_FAILED cpu_to_le32(0xC0220037) -#define STATUS_FWP_INCOMPATIBLE_AUTH_CONFIG cpu_to_le32(0xC0220038) -#define STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG cpu_to_le32(0xC0220039) -#define STATUS_FWP_TCPIP_NOT_READY cpu_to_le32(0xC0220100) -#define STATUS_FWP_INJECT_HANDLE_CLOSING cpu_to_le32(0xC0220101) -#define STATUS_FWP_INJECT_HANDLE_STALE cpu_to_le32(0xC0220102) -#define STATUS_FWP_CANNOT_PEND cpu_to_le32(0xC0220103) -#define STATUS_NDIS_CLOSING cpu_to_le32(0xC0230002) -#define STATUS_NDIS_BAD_VERSION cpu_to_le32(0xC0230004) -#define STATUS_NDIS_BAD_CHARACTERISTICS cpu_to_le32(0xC0230005) -#define STATUS_NDIS_ADAPTER_NOT_FOUND cpu_to_le32(0xC0230006) -#define STATUS_NDIS_OPEN_FAILED cpu_to_le32(0xC0230007) -#define STATUS_NDIS_DEVICE_FAILED cpu_to_le32(0xC0230008) -#define STATUS_NDIS_MULTICAST_FULL cpu_to_le32(0xC0230009) -#define STATUS_NDIS_MULTICAST_EXISTS cpu_to_le32(0xC023000A) -#define STATUS_NDIS_MULTICAST_NOT_FOUND cpu_to_le32(0xC023000B) -#define STATUS_NDIS_REQUEST_ABORTED cpu_to_le32(0xC023000C) -#define STATUS_NDIS_RESET_IN_PROGRESS cpu_to_le32(0xC023000D) -#define STATUS_NDIS_INVALID_PACKET cpu_to_le32(0xC023000F) -#define STATUS_NDIS_INVALID_DEVICE_REQUEST cpu_to_le32(0xC0230010) -#define STATUS_NDIS_ADAPTER_NOT_READY cpu_to_le32(0xC0230011) -#define STATUS_NDIS_INVALID_LENGTH cpu_to_le32(0xC0230014) -#define STATUS_NDIS_INVALID_DATA cpu_to_le32(0xC0230015) -#define STATUS_NDIS_BUFFER_TOO_SHORT cpu_to_le32(0xC0230016) -#define STATUS_NDIS_INVALID_OID cpu_to_le32(0xC0230017) -#define STATUS_NDIS_ADAPTER_REMOVED cpu_to_le32(0xC0230018) -#define STATUS_NDIS_UNSUPPORTED_MEDIA cpu_to_le32(0xC0230019) -#define STATUS_NDIS_GROUP_ADDRESS_IN_USE cpu_to_le32(0xC023001A) -#define STATUS_NDIS_FILE_NOT_FOUND cpu_to_le32(0xC023001B) -#define STATUS_NDIS_ERROR_READING_FILE cpu_to_le32(0xC023001C) -#define STATUS_NDIS_ALREADY_MAPPED cpu_to_le32(0xC023001D) -#define STATUS_NDIS_RESOURCE_CONFLICT cpu_to_le32(0xC023001E) -#define STATUS_NDIS_MEDIA_DISCONNECTED cpu_to_le32(0xC023001F) -#define STATUS_NDIS_INVALID_ADDRESS cpu_to_le32(0xC0230022) -#define STATUS_NDIS_PAUSED cpu_to_le32(0xC023002A) -#define STATUS_NDIS_INTERFACE_NOT_FOUND cpu_to_le32(0xC023002B) -#define STATUS_NDIS_UNSUPPORTED_REVISION cpu_to_le32(0xC023002C) -#define STATUS_NDIS_INVALID_PORT cpu_to_le32(0xC023002D) -#define STATUS_NDIS_INVALID_PORT_STATE cpu_to_le32(0xC023002E) -#define STATUS_NDIS_LOW_POWER_STATE cpu_to_le32(0xC023002F) -#define STATUS_NDIS_NOT_SUPPORTED cpu_to_le32(0xC02300BB) -#define STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED cpu_to_le32(0xC0232000) -#define STATUS_NDIS_DOT11_MEDIA_IN_USE cpu_to_le32(0xC0232001) -#define STATUS_NDIS_DOT11_POWER_STATE_INVALID cpu_to_le32(0xC0232002) -#define STATUS_IPSEC_BAD_SPI cpu_to_le32(0xC0360001) -#define STATUS_IPSEC_SA_LIFETIME_EXPIRED cpu_to_le32(0xC0360002) -#define STATUS_IPSEC_WRONG_SA cpu_to_le32(0xC0360003) -#define STATUS_IPSEC_REPLAY_CHECK_FAILED cpu_to_le32(0xC0360004) -#define STATUS_IPSEC_INVALID_PACKET cpu_to_le32(0xC0360005) -#define STATUS_IPSEC_INTEGRITY_CHECK_FAILED cpu_to_le32(0xC0360006) -#define STATUS_IPSEC_CLEAR_TEXT_DROP cpu_to_le32(0xC0360007) - -#define STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP cpu_to_le32(0xC05D0000) -#define STATUS_INVALID_LOCK_RANGE cpu_to_le32(0xC00001a1) diff --git a/fs/ksmbd/transport_ipc.c b/fs/ksmbd/transport_ipc.c deleted file mode 100644 index 40c721f9227e..000000000000 --- a/fs/ksmbd/transport_ipc.c +++ /dev/null @@ -1,884 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/jhash.h> -#include <linux/slab.h> -#include <linux/rwsem.h> -#include <linux/mutex.h> -#include <linux/wait.h> -#include <linux/hashtable.h> -#include <net/net_namespace.h> -#include <net/genetlink.h> -#include <linux/socket.h> -#include <linux/workqueue.h> - -#include "vfs_cache.h" -#include "transport_ipc.h" -#include "server.h" -#include "smb_common.h" - -#include "mgmt/user_config.h" -#include "mgmt/share_config.h" -#include "mgmt/user_session.h" -#include "mgmt/tree_connect.h" -#include "mgmt/ksmbd_ida.h" -#include "connection.h" -#include "transport_tcp.h" -#include "transport_rdma.h" - -#define IPC_WAIT_TIMEOUT (2 * HZ) - -#define IPC_MSG_HASH_BITS 3 -static DEFINE_HASHTABLE(ipc_msg_table, IPC_MSG_HASH_BITS); -static DECLARE_RWSEM(ipc_msg_table_lock); -static DEFINE_MUTEX(startup_lock); - -static DEFINE_IDA(ipc_ida); - -static unsigned int ksmbd_tools_pid; - -static bool ksmbd_ipc_validate_version(struct genl_info *m) -{ - if (m->genlhdr->version != KSMBD_GENL_VERSION) { - pr_err("%s. ksmbd: %d, kernel module: %d. %s.\n", - "Daemon and kernel module version mismatch", - m->genlhdr->version, - KSMBD_GENL_VERSION, - "User-space ksmbd should terminate"); - return false; - } - return true; -} - -struct ksmbd_ipc_msg { - unsigned int type; - unsigned int sz; - unsigned char payload[]; -}; - -struct ipc_msg_table_entry { - unsigned int handle; - unsigned int type; - wait_queue_head_t wait; - struct hlist_node ipc_table_hlist; - - void *response; -}; - -static struct delayed_work ipc_timer_work; - -static int handle_startup_event(struct sk_buff *skb, struct genl_info *info); -static int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info); -static int handle_generic_event(struct sk_buff *skb, struct genl_info *info); -static int ksmbd_ipc_heartbeat_request(void); - -static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX] = { - [KSMBD_EVENT_UNSPEC] = { - .len = 0, - }, - [KSMBD_EVENT_HEARTBEAT_REQUEST] = { - .len = sizeof(struct ksmbd_heartbeat), - }, - [KSMBD_EVENT_STARTING_UP] = { - .len = sizeof(struct ksmbd_startup_request), - }, - [KSMBD_EVENT_SHUTTING_DOWN] = { - .len = sizeof(struct ksmbd_shutdown_request), - }, - [KSMBD_EVENT_LOGIN_REQUEST] = { - .len = sizeof(struct ksmbd_login_request), - }, - [KSMBD_EVENT_LOGIN_RESPONSE] = { - .len = sizeof(struct ksmbd_login_response), - }, - [KSMBD_EVENT_SHARE_CONFIG_REQUEST] = { - .len = sizeof(struct ksmbd_share_config_request), - }, - [KSMBD_EVENT_SHARE_CONFIG_RESPONSE] = { - .len = sizeof(struct ksmbd_share_config_response), - }, - [KSMBD_EVENT_TREE_CONNECT_REQUEST] = { - .len = sizeof(struct ksmbd_tree_connect_request), - }, - [KSMBD_EVENT_TREE_CONNECT_RESPONSE] = { - .len = sizeof(struct ksmbd_tree_connect_response), - }, - [KSMBD_EVENT_TREE_DISCONNECT_REQUEST] = { - .len = sizeof(struct ksmbd_tree_disconnect_request), - }, - [KSMBD_EVENT_LOGOUT_REQUEST] = { - .len = sizeof(struct ksmbd_logout_request), - }, - [KSMBD_EVENT_RPC_REQUEST] = { - }, - [KSMBD_EVENT_RPC_RESPONSE] = { - }, - [KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST] = { - }, - [KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE] = { - }, -}; - -static struct genl_ops ksmbd_genl_ops[] = { - { - .cmd = KSMBD_EVENT_UNSPEC, - .doit = handle_unsupported_event, - }, - { - .cmd = KSMBD_EVENT_HEARTBEAT_REQUEST, - .doit = handle_unsupported_event, - }, - { - .cmd = KSMBD_EVENT_STARTING_UP, - .doit = handle_startup_event, - }, - { - .cmd = KSMBD_EVENT_SHUTTING_DOWN, - .doit = handle_unsupported_event, - }, - { - .cmd = KSMBD_EVENT_LOGIN_REQUEST, - .doit = handle_unsupported_event, - }, - { - .cmd = KSMBD_EVENT_LOGIN_RESPONSE, - .doit = handle_generic_event, - }, - { - .cmd = KSMBD_EVENT_SHARE_CONFIG_REQUEST, - .doit = handle_unsupported_event, - }, - { - .cmd = KSMBD_EVENT_SHARE_CONFIG_RESPONSE, - .doit = handle_generic_event, - }, - { - .cmd = KSMBD_EVENT_TREE_CONNECT_REQUEST, - .doit = handle_unsupported_event, - }, - { - .cmd = KSMBD_EVENT_TREE_CONNECT_RESPONSE, - .doit = handle_generic_event, - }, - { - .cmd = KSMBD_EVENT_TREE_DISCONNECT_REQUEST, - .doit = handle_unsupported_event, - }, - { - .cmd = KSMBD_EVENT_LOGOUT_REQUEST, - .doit = handle_unsupported_event, - }, - { - .cmd = KSMBD_EVENT_RPC_REQUEST, - .doit = handle_unsupported_event, - }, - { - .cmd = KSMBD_EVENT_RPC_RESPONSE, - .doit = handle_generic_event, - }, - { - .cmd = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST, - .doit = handle_unsupported_event, - }, - { - .cmd = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE, - .doit = handle_generic_event, - }, -}; - -static struct genl_family ksmbd_genl_family = { - .name = KSMBD_GENL_NAME, - .version = KSMBD_GENL_VERSION, - .hdrsize = 0, - .maxattr = KSMBD_EVENT_MAX, - .netnsok = true, - .module = THIS_MODULE, - .ops = ksmbd_genl_ops, - .n_ops = ARRAY_SIZE(ksmbd_genl_ops), - .resv_start_op = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE + 1, -}; - -static void ksmbd_nl_init_fixup(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ksmbd_genl_ops); i++) - ksmbd_genl_ops[i].validate = GENL_DONT_VALIDATE_STRICT | - GENL_DONT_VALIDATE_DUMP; - - ksmbd_genl_family.policy = ksmbd_nl_policy; -} - -static int rpc_context_flags(struct ksmbd_session *sess) -{ - if (user_guest(sess->user)) - return KSMBD_RPC_RESTRICTED_CONTEXT; - return 0; -} - -static void ipc_update_last_active(void) -{ - if (server_conf.ipc_timeout) - server_conf.ipc_last_active = jiffies; -} - -static struct ksmbd_ipc_msg *ipc_msg_alloc(size_t sz) -{ - struct ksmbd_ipc_msg *msg; - size_t msg_sz = sz + sizeof(struct ksmbd_ipc_msg); - - msg = kvmalloc(msg_sz, GFP_KERNEL | __GFP_ZERO); - if (msg) - msg->sz = sz; - return msg; -} - -static void ipc_msg_free(struct ksmbd_ipc_msg *msg) -{ - kvfree(msg); -} - -static void ipc_msg_handle_free(int handle) -{ - if (handle >= 0) - ksmbd_release_id(&ipc_ida, handle); -} - -static int handle_response(int type, void *payload, size_t sz) -{ - unsigned int handle = *(unsigned int *)payload; - struct ipc_msg_table_entry *entry; - int ret = 0; - - ipc_update_last_active(); - down_read(&ipc_msg_table_lock); - hash_for_each_possible(ipc_msg_table, entry, ipc_table_hlist, handle) { - if (handle != entry->handle) - continue; - - entry->response = NULL; - /* - * Response message type value should be equal to - * request message type + 1. - */ - if (entry->type + 1 != type) { - pr_err("Waiting for IPC type %d, got %d. Ignore.\n", - entry->type + 1, type); - } - - entry->response = kvmalloc(sz, GFP_KERNEL | __GFP_ZERO); - if (!entry->response) { - ret = -ENOMEM; - break; - } - - memcpy(entry->response, payload, sz); - wake_up_interruptible(&entry->wait); - ret = 0; - break; - } - up_read(&ipc_msg_table_lock); - - return ret; -} - -static int ipc_server_config_on_startup(struct ksmbd_startup_request *req) -{ - int ret; - - ksmbd_set_fd_limit(req->file_max); - server_conf.flags = req->flags; - server_conf.signing = req->signing; - server_conf.tcp_port = req->tcp_port; - server_conf.ipc_timeout = req->ipc_timeout * HZ; - server_conf.deadtime = req->deadtime * SMB_ECHO_INTERVAL; - server_conf.share_fake_fscaps = req->share_fake_fscaps; - ksmbd_init_domain(req->sub_auth); - - if (req->smb2_max_read) - init_smb2_max_read_size(req->smb2_max_read); - if (req->smb2_max_write) - init_smb2_max_write_size(req->smb2_max_write); - if (req->smb2_max_trans) - init_smb2_max_trans_size(req->smb2_max_trans); - if (req->smb2_max_credits) - init_smb2_max_credits(req->smb2_max_credits); - if (req->smbd_max_io_size) - init_smbd_max_io_size(req->smbd_max_io_size); - - if (req->max_connections) - server_conf.max_connections = req->max_connections; - - ret = ksmbd_set_netbios_name(req->netbios_name); - ret |= ksmbd_set_server_string(req->server_string); - ret |= ksmbd_set_work_group(req->work_group); - ret |= ksmbd_tcp_set_interfaces(KSMBD_STARTUP_CONFIG_INTERFACES(req), - req->ifc_list_sz); - if (ret) { - pr_err("Server configuration error: %s %s %s\n", - req->netbios_name, req->server_string, - req->work_group); - return ret; - } - - if (req->min_prot[0]) { - ret = ksmbd_lookup_protocol_idx(req->min_prot); - if (ret >= 0) - server_conf.min_protocol = ret; - } - if (req->max_prot[0]) { - ret = ksmbd_lookup_protocol_idx(req->max_prot); - if (ret >= 0) - server_conf.max_protocol = ret; - } - - if (server_conf.ipc_timeout) - schedule_delayed_work(&ipc_timer_work, server_conf.ipc_timeout); - return 0; -} - -static int handle_startup_event(struct sk_buff *skb, struct genl_info *info) -{ - int ret = 0; - -#ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN - if (!netlink_capable(skb, CAP_NET_ADMIN)) - return -EPERM; -#endif - - if (!ksmbd_ipc_validate_version(info)) - return -EINVAL; - - if (!info->attrs[KSMBD_EVENT_STARTING_UP]) - return -EINVAL; - - mutex_lock(&startup_lock); - if (!ksmbd_server_configurable()) { - mutex_unlock(&startup_lock); - pr_err("Server reset is in progress, can't start daemon\n"); - return -EINVAL; - } - - if (ksmbd_tools_pid) { - if (ksmbd_ipc_heartbeat_request() == 0) { - ret = -EINVAL; - goto out; - } - - pr_err("Reconnect to a new user space daemon\n"); - } else { - struct ksmbd_startup_request *req; - - req = nla_data(info->attrs[info->genlhdr->cmd]); - ret = ipc_server_config_on_startup(req); - if (ret) - goto out; - server_queue_ctrl_init_work(); - } - - ksmbd_tools_pid = info->snd_portid; - ipc_update_last_active(); - -out: - mutex_unlock(&startup_lock); - return ret; -} - -static int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info) -{ - pr_err("Unknown IPC event: %d, ignore.\n", info->genlhdr->cmd); - return -EINVAL; -} - -static int handle_generic_event(struct sk_buff *skb, struct genl_info *info) -{ - void *payload; - int sz; - int type = info->genlhdr->cmd; - -#ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN - if (!netlink_capable(skb, CAP_NET_ADMIN)) - return -EPERM; -#endif - - if (type >= KSMBD_EVENT_MAX) { - WARN_ON(1); - return -EINVAL; - } - - if (!ksmbd_ipc_validate_version(info)) - return -EINVAL; - - if (!info->attrs[type]) - return -EINVAL; - - payload = nla_data(info->attrs[info->genlhdr->cmd]); - sz = nla_len(info->attrs[info->genlhdr->cmd]); - return handle_response(type, payload, sz); -} - -static int ipc_msg_send(struct ksmbd_ipc_msg *msg) -{ - struct genlmsghdr *nlh; - struct sk_buff *skb; - int ret = -EINVAL; - - if (!ksmbd_tools_pid) - return ret; - - skb = genlmsg_new(msg->sz, GFP_KERNEL); - if (!skb) - return -ENOMEM; - - nlh = genlmsg_put(skb, 0, 0, &ksmbd_genl_family, 0, msg->type); - if (!nlh) - goto out; - - ret = nla_put(skb, msg->type, msg->sz, msg->payload); - if (ret) { - genlmsg_cancel(skb, nlh); - goto out; - } - - genlmsg_end(skb, nlh); - ret = genlmsg_unicast(&init_net, skb, ksmbd_tools_pid); - if (!ret) - ipc_update_last_active(); - return ret; - -out: - nlmsg_free(skb); - return ret; -} - -static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle) -{ - struct ipc_msg_table_entry entry; - int ret; - - if ((int)handle < 0) - return NULL; - - entry.type = msg->type; - entry.response = NULL; - init_waitqueue_head(&entry.wait); - - down_write(&ipc_msg_table_lock); - entry.handle = handle; - hash_add(ipc_msg_table, &entry.ipc_table_hlist, entry.handle); - up_write(&ipc_msg_table_lock); - - ret = ipc_msg_send(msg); - if (ret) - goto out; - - ret = wait_event_interruptible_timeout(entry.wait, - entry.response != NULL, - IPC_WAIT_TIMEOUT); -out: - down_write(&ipc_msg_table_lock); - hash_del(&entry.ipc_table_hlist); - up_write(&ipc_msg_table_lock); - return entry.response; -} - -static int ksmbd_ipc_heartbeat_request(void) -{ - struct ksmbd_ipc_msg *msg; - int ret; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_heartbeat)); - if (!msg) - return -EINVAL; - - msg->type = KSMBD_EVENT_HEARTBEAT_REQUEST; - ret = ipc_msg_send(msg); - ipc_msg_free(msg); - return ret; -} - -struct ksmbd_login_response *ksmbd_ipc_login_request(const char *account) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_login_request *req; - struct ksmbd_login_response *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; - 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 * -ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_spnego_authen_request *req; - struct ksmbd_spnego_authen_response *resp; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_spnego_authen_request) + - blob_len + 1); - if (!msg) - return NULL; - - msg->type = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST; - req = (struct ksmbd_spnego_authen_request *)msg->payload; - req->handle = ksmbd_acquire_id(&ipc_ida); - req->spnego_blob_len = blob_len; - memcpy(req->spnego_blob, spnego_blob, blob_len); - - resp = ipc_msg_send_request(msg, req->handle); - ipc_msg_handle_free(req->handle); - ipc_msg_free(msg); - return resp; -} - -struct ksmbd_tree_connect_response * -ksmbd_ipc_tree_connect_request(struct ksmbd_session *sess, - struct ksmbd_share_config *share, - struct ksmbd_tree_connect *tree_conn, - struct sockaddr *peer_addr) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_tree_connect_request *req; - struct ksmbd_tree_connect_response *resp; - - if (strlen(user_name(sess->user)) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) - return NULL; - - if (strlen(share->name) >= KSMBD_REQ_MAX_SHARE_NAME) - return NULL; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_connect_request)); - if (!msg) - return NULL; - - msg->type = KSMBD_EVENT_TREE_CONNECT_REQUEST; - req = (struct ksmbd_tree_connect_request *)msg->payload; - - req->handle = ksmbd_acquire_id(&ipc_ida); - req->account_flags = sess->user->flags; - req->session_id = sess->id; - req->connect_id = tree_conn->id; - strscpy(req->account, user_name(sess->user), KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); - strscpy(req->share, share->name, KSMBD_REQ_MAX_SHARE_NAME); - snprintf(req->peer_addr, sizeof(req->peer_addr), "%pIS", peer_addr); - - if (peer_addr->sa_family == AF_INET6) - req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_IPV6; - if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2)) - req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_SMB2; - - resp = ipc_msg_send_request(msg, req->handle); - ipc_msg_handle_free(req->handle); - ipc_msg_free(msg); - return resp; -} - -int ksmbd_ipc_tree_disconnect_request(unsigned long long session_id, - unsigned long long connect_id) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_tree_disconnect_request *req; - int ret; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_disconnect_request)); - if (!msg) - return -ENOMEM; - - msg->type = KSMBD_EVENT_TREE_DISCONNECT_REQUEST; - req = (struct ksmbd_tree_disconnect_request *)msg->payload; - req->session_id = session_id; - req->connect_id = connect_id; - - ret = ipc_msg_send(msg); - ipc_msg_free(msg); - return ret; -} - -int ksmbd_ipc_logout_request(const char *account, int flags) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_logout_request *req; - int ret; - - if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) - return -EINVAL; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_logout_request)); - if (!msg) - return -ENOMEM; - - msg->type = KSMBD_EVENT_LOGOUT_REQUEST; - req = (struct ksmbd_logout_request *)msg->payload; - req->account_flags = flags; - strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); - - ret = ipc_msg_send(msg); - ipc_msg_free(msg); - return ret; -} - -struct ksmbd_share_config_response * -ksmbd_ipc_share_config_request(const char *name) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_share_config_request *req; - struct ksmbd_share_config_response *resp; - - if (strlen(name) >= KSMBD_REQ_MAX_SHARE_NAME) - return NULL; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_share_config_request)); - if (!msg) - return NULL; - - msg->type = KSMBD_EVENT_SHARE_CONFIG_REQUEST; - req = (struct ksmbd_share_config_request *)msg->payload; - req->handle = ksmbd_acquire_id(&ipc_ida); - strscpy(req->share_name, name, KSMBD_REQ_MAX_SHARE_NAME); - - resp = ipc_msg_send_request(msg, req->handle); - ipc_msg_handle_free(req->handle); - ipc_msg_free(msg); - return resp; -} - -struct ksmbd_rpc_command *ksmbd_rpc_open(struct ksmbd_session *sess, int handle) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_rpc_command *req; - struct ksmbd_rpc_command *resp; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command)); - if (!msg) - return NULL; - - msg->type = KSMBD_EVENT_RPC_REQUEST; - req = (struct ksmbd_rpc_command *)msg->payload; - req->handle = handle; - req->flags = ksmbd_session_rpc_method(sess, handle); - req->flags |= KSMBD_RPC_OPEN_METHOD; - req->payload_sz = 0; - - resp = ipc_msg_send_request(msg, req->handle); - ipc_msg_free(msg); - return resp; -} - -struct ksmbd_rpc_command *ksmbd_rpc_close(struct ksmbd_session *sess, int handle) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_rpc_command *req; - struct ksmbd_rpc_command *resp; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command)); - if (!msg) - return NULL; - - msg->type = KSMBD_EVENT_RPC_REQUEST; - req = (struct ksmbd_rpc_command *)msg->payload; - req->handle = handle; - req->flags = ksmbd_session_rpc_method(sess, handle); - req->flags |= KSMBD_RPC_CLOSE_METHOD; - req->payload_sz = 0; - - resp = ipc_msg_send_request(msg, req->handle); - ipc_msg_free(msg); - return resp; -} - -struct ksmbd_rpc_command *ksmbd_rpc_write(struct ksmbd_session *sess, int handle, - void *payload, size_t payload_sz) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_rpc_command *req; - struct ksmbd_rpc_command *resp; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1); - if (!msg) - return NULL; - - msg->type = KSMBD_EVENT_RPC_REQUEST; - req = (struct ksmbd_rpc_command *)msg->payload; - req->handle = handle; - req->flags = ksmbd_session_rpc_method(sess, handle); - req->flags |= rpc_context_flags(sess); - req->flags |= KSMBD_RPC_WRITE_METHOD; - req->payload_sz = payload_sz; - memcpy(req->payload, payload, payload_sz); - - resp = ipc_msg_send_request(msg, req->handle); - ipc_msg_free(msg); - return resp; -} - -struct ksmbd_rpc_command *ksmbd_rpc_read(struct ksmbd_session *sess, int handle) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_rpc_command *req; - struct ksmbd_rpc_command *resp; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command)); - if (!msg) - return NULL; - - msg->type = KSMBD_EVENT_RPC_REQUEST; - req = (struct ksmbd_rpc_command *)msg->payload; - req->handle = handle; - req->flags = ksmbd_session_rpc_method(sess, handle); - req->flags |= rpc_context_flags(sess); - req->flags |= KSMBD_RPC_READ_METHOD; - req->payload_sz = 0; - - resp = ipc_msg_send_request(msg, req->handle); - ipc_msg_free(msg); - return resp; -} - -struct ksmbd_rpc_command *ksmbd_rpc_ioctl(struct ksmbd_session *sess, int handle, - void *payload, size_t payload_sz) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_rpc_command *req; - struct ksmbd_rpc_command *resp; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1); - if (!msg) - return NULL; - - msg->type = KSMBD_EVENT_RPC_REQUEST; - req = (struct ksmbd_rpc_command *)msg->payload; - req->handle = handle; - req->flags = ksmbd_session_rpc_method(sess, handle); - req->flags |= rpc_context_flags(sess); - req->flags |= KSMBD_RPC_IOCTL_METHOD; - req->payload_sz = payload_sz; - memcpy(req->payload, payload, payload_sz); - - resp = ipc_msg_send_request(msg, req->handle); - ipc_msg_free(msg); - return resp; -} - -struct ksmbd_rpc_command *ksmbd_rpc_rap(struct ksmbd_session *sess, void *payload, - size_t payload_sz) -{ - struct ksmbd_ipc_msg *msg; - struct ksmbd_rpc_command *req; - struct ksmbd_rpc_command *resp; - - msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1); - if (!msg) - return NULL; - - msg->type = KSMBD_EVENT_RPC_REQUEST; - req = (struct ksmbd_rpc_command *)msg->payload; - req->handle = ksmbd_acquire_id(&ipc_ida); - req->flags = rpc_context_flags(sess); - req->flags |= KSMBD_RPC_RAP_METHOD; - req->payload_sz = payload_sz; - memcpy(req->payload, payload, payload_sz); - - resp = ipc_msg_send_request(msg, req->handle); - ipc_msg_handle_free(req->handle); - ipc_msg_free(msg); - return resp; -} - -static int __ipc_heartbeat(void) -{ - unsigned long delta; - - if (!ksmbd_server_running()) - return 0; - - if (time_after(jiffies, server_conf.ipc_last_active)) { - delta = (jiffies - server_conf.ipc_last_active); - } else { - ipc_update_last_active(); - schedule_delayed_work(&ipc_timer_work, - server_conf.ipc_timeout); - return 0; - } - - if (delta < server_conf.ipc_timeout) { - schedule_delayed_work(&ipc_timer_work, - server_conf.ipc_timeout - delta); - return 0; - } - - if (ksmbd_ipc_heartbeat_request() == 0) { - schedule_delayed_work(&ipc_timer_work, - server_conf.ipc_timeout); - return 0; - } - - mutex_lock(&startup_lock); - WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING); - server_conf.ipc_last_active = 0; - ksmbd_tools_pid = 0; - pr_err("No IPC daemon response for %lus\n", delta / HZ); - mutex_unlock(&startup_lock); - return -EINVAL; -} - -static void ipc_timer_heartbeat(struct work_struct *w) -{ - if (__ipc_heartbeat()) - server_queue_ctrl_reset_work(); -} - -int ksmbd_ipc_id_alloc(void) -{ - return ksmbd_acquire_id(&ipc_ida); -} - -void ksmbd_rpc_id_free(int handle) -{ - ksmbd_release_id(&ipc_ida, handle); -} - -void ksmbd_ipc_release(void) -{ - cancel_delayed_work_sync(&ipc_timer_work); - genl_unregister_family(&ksmbd_genl_family); -} - -void ksmbd_ipc_soft_reset(void) -{ - mutex_lock(&startup_lock); - ksmbd_tools_pid = 0; - cancel_delayed_work_sync(&ipc_timer_work); - mutex_unlock(&startup_lock); -} - -int ksmbd_ipc_init(void) -{ - int ret = 0; - - ksmbd_nl_init_fixup(); - INIT_DELAYED_WORK(&ipc_timer_work, ipc_timer_heartbeat); - - ret = genl_register_family(&ksmbd_genl_family); - if (ret) { - pr_err("Failed to register KSMBD netlink interface %d\n", ret); - cancel_delayed_work_sync(&ipc_timer_work); - } - - return ret; -} diff --git a/fs/ksmbd/transport_ipc.h b/fs/ksmbd/transport_ipc.h deleted file mode 100644 index 5e5b90a0c187..000000000000 --- a/fs/ksmbd/transport_ipc.h +++ /dev/null @@ -1,47 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __KSMBD_TRANSPORT_IPC_H__ -#define __KSMBD_TRANSPORT_IPC_H__ - -#include <linux/wait.h> - -#define KSMBD_IPC_MAX_PAYLOAD 4096 - -struct ksmbd_login_response * -ksmbd_ipc_login_request(const char *account); - -struct ksmbd_session; -struct ksmbd_share_config; -struct ksmbd_tree_connect; -struct sockaddr; - -struct ksmbd_tree_connect_response * -ksmbd_ipc_tree_connect_request(struct ksmbd_session *sess, - struct ksmbd_share_config *share, - struct ksmbd_tree_connect *tree_conn, - struct sockaddr *peer_addr); -int ksmbd_ipc_tree_disconnect_request(unsigned long long session_id, - unsigned long long connect_id); -int ksmbd_ipc_logout_request(const char *account, int flags); -struct ksmbd_share_config_response * -ksmbd_ipc_share_config_request(const char *name); -struct ksmbd_spnego_authen_response * -ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len); -int ksmbd_ipc_id_alloc(void); -void ksmbd_rpc_id_free(int handle); -struct ksmbd_rpc_command *ksmbd_rpc_open(struct ksmbd_session *sess, int handle); -struct ksmbd_rpc_command *ksmbd_rpc_close(struct ksmbd_session *sess, int handle); -struct ksmbd_rpc_command *ksmbd_rpc_write(struct ksmbd_session *sess, int handle, - void *payload, size_t payload_sz); -struct ksmbd_rpc_command *ksmbd_rpc_read(struct ksmbd_session *sess, int handle); -struct ksmbd_rpc_command *ksmbd_rpc_ioctl(struct ksmbd_session *sess, int handle, - void *payload, size_t payload_sz); -struct ksmbd_rpc_command *ksmbd_rpc_rap(struct ksmbd_session *sess, void *payload, - size_t payload_sz); -void ksmbd_ipc_release(void); -void ksmbd_ipc_soft_reset(void); -int ksmbd_ipc_init(void); -#endif /* __KSMBD_TRANSPORT_IPC_H__ */ diff --git a/fs/ksmbd/transport_rdma.c b/fs/ksmbd/transport_rdma.c deleted file mode 100644 index c06efc020bd9..000000000000 --- a/fs/ksmbd/transport_rdma.c +++ /dev/null @@ -1,2273 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2017, Microsoft Corporation. - * Copyright (C) 2018, LG Electronics. - * - * Author(s): Long Li <longli@microsoft.com>, - * Hyunchul Lee <hyc.lee@gmail.com> - */ - -#define SUBMOD_NAME "smb_direct" - -#include <linux/kthread.h> -#include <linux/list.h> -#include <linux/mempool.h> -#include <linux/highmem.h> -#include <linux/scatterlist.h> -#include <rdma/ib_verbs.h> -#include <rdma/rdma_cm.h> -#include <rdma/rw.h> - -#include "glob.h" -#include "connection.h" -#include "smb_common.h" -#include "smbstatus.h" -#include "transport_rdma.h" - -#define SMB_DIRECT_PORT_IWARP 5445 -#define SMB_DIRECT_PORT_INFINIBAND 445 - -#define SMB_DIRECT_VERSION_LE cpu_to_le16(0x0100) - -/* SMB_DIRECT negotiation timeout in seconds */ -#define SMB_DIRECT_NEGOTIATE_TIMEOUT 120 - -#define SMB_DIRECT_MAX_SEND_SGES 6 -#define SMB_DIRECT_MAX_RECV_SGES 1 - -/* - * Default maximum number of RDMA read/write outstanding on this connection - * This value is possibly decreased during QP creation on hardware limit - */ -#define SMB_DIRECT_CM_INITIATOR_DEPTH 8 - -/* Maximum number of retries on data transfer operations */ -#define SMB_DIRECT_CM_RETRY 6 -/* No need to retry on Receiver Not Ready since SMB_DIRECT manages credits */ -#define SMB_DIRECT_CM_RNR_RETRY 0 - -/* - * User configurable initial values per SMB_DIRECT transport connection - * as defined in [MS-SMBD] 3.1.1.1 - * Those may change after a SMB_DIRECT negotiation - */ - -/* Set 445 port to SMB Direct port by default */ -static int smb_direct_port = SMB_DIRECT_PORT_INFINIBAND; - -/* The local peer's maximum number of credits to grant to the peer */ -static int smb_direct_receive_credit_max = 255; - -/* The remote peer's credit request of local peer */ -static int smb_direct_send_credit_target = 255; - -/* The maximum single message size can be sent to remote peer */ -static int smb_direct_max_send_size = 1364; - -/* The maximum fragmented upper-layer payload receive size supported */ -static int smb_direct_max_fragmented_recv_size = 1024 * 1024; - -/* The maximum single-message size which can be received */ -static int smb_direct_max_receive_size = 1364; - -static int smb_direct_max_read_write_size = SMBD_DEFAULT_IOSIZE; - -static LIST_HEAD(smb_direct_device_list); -static DEFINE_RWLOCK(smb_direct_device_lock); - -struct smb_direct_device { - struct ib_device *ib_dev; - struct list_head list; -}; - -static struct smb_direct_listener { - struct rdma_cm_id *cm_id; -} smb_direct_listener; - -static struct workqueue_struct *smb_direct_wq; - -enum smb_direct_status { - SMB_DIRECT_CS_NEW = 0, - SMB_DIRECT_CS_CONNECTED, - SMB_DIRECT_CS_DISCONNECTING, - SMB_DIRECT_CS_DISCONNECTED, -}; - -struct smb_direct_transport { - struct ksmbd_transport transport; - - enum smb_direct_status status; - bool full_packet_received; - wait_queue_head_t wait_status; - - struct rdma_cm_id *cm_id; - struct ib_cq *send_cq; - struct ib_cq *recv_cq; - struct ib_pd *pd; - struct ib_qp *qp; - - int max_send_size; - int max_recv_size; - int max_fragmented_send_size; - int max_fragmented_recv_size; - int max_rdma_rw_size; - - spinlock_t reassembly_queue_lock; - struct list_head reassembly_queue; - int reassembly_data_length; - int reassembly_queue_length; - int first_entry_offset; - wait_queue_head_t wait_reassembly_queue; - - spinlock_t receive_credit_lock; - int recv_credits; - int count_avail_recvmsg; - int recv_credit_max; - int recv_credit_target; - - spinlock_t recvmsg_queue_lock; - struct list_head recvmsg_queue; - - spinlock_t empty_recvmsg_queue_lock; - struct list_head empty_recvmsg_queue; - - int send_credit_target; - atomic_t send_credits; - spinlock_t lock_new_recv_credits; - int new_recv_credits; - int max_rw_credits; - int pages_per_rw_credit; - atomic_t rw_credits; - - wait_queue_head_t wait_send_credits; - wait_queue_head_t wait_rw_credits; - - mempool_t *sendmsg_mempool; - struct kmem_cache *sendmsg_cache; - mempool_t *recvmsg_mempool; - struct kmem_cache *recvmsg_cache; - - wait_queue_head_t wait_send_pending; - atomic_t send_pending; - - struct delayed_work post_recv_credits_work; - struct work_struct send_immediate_work; - struct work_struct disconnect_work; - - bool negotiation_requested; -}; - -#define KSMBD_TRANS(t) ((struct ksmbd_transport *)&((t)->transport)) - -enum { - SMB_DIRECT_MSG_NEGOTIATE_REQ = 0, - SMB_DIRECT_MSG_DATA_TRANSFER -}; - -static struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops; - -struct smb_direct_send_ctx { - struct list_head msg_list; - int wr_cnt; - bool need_invalidate_rkey; - unsigned int remote_key; -}; - -struct smb_direct_sendmsg { - struct smb_direct_transport *transport; - struct ib_send_wr wr; - struct list_head list; - int num_sge; - struct ib_sge sge[SMB_DIRECT_MAX_SEND_SGES]; - struct ib_cqe cqe; - u8 packet[]; -}; - -struct smb_direct_recvmsg { - struct smb_direct_transport *transport; - struct list_head list; - int type; - struct ib_sge sge; - struct ib_cqe cqe; - bool first_segment; - u8 packet[]; -}; - -struct smb_direct_rdma_rw_msg { - struct smb_direct_transport *t; - struct ib_cqe cqe; - int status; - struct completion *completion; - struct list_head list; - struct rdma_rw_ctx rw_ctx; - struct sg_table sgt; - struct scatterlist sg_list[]; -}; - -void init_smbd_max_io_size(unsigned int sz) -{ - sz = clamp_val(sz, SMBD_MIN_IOSIZE, SMBD_MAX_IOSIZE); - smb_direct_max_read_write_size = sz; -} - -unsigned int get_smbd_max_read_write_size(void) -{ - return smb_direct_max_read_write_size; -} - -static inline int get_buf_page_count(void *buf, int size) -{ - return DIV_ROUND_UP((uintptr_t)buf + size, PAGE_SIZE) - - (uintptr_t)buf / PAGE_SIZE; -} - -static void smb_direct_destroy_pools(struct smb_direct_transport *transport); -static void smb_direct_post_recv_credits(struct work_struct *work); -static int smb_direct_post_send_data(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx, - struct kvec *iov, int niov, - int remaining_data_length); - -static inline struct smb_direct_transport * -smb_trans_direct_transfort(struct ksmbd_transport *t) -{ - return container_of(t, struct smb_direct_transport, transport); -} - -static inline void -*smb_direct_recvmsg_payload(struct smb_direct_recvmsg *recvmsg) -{ - return (void *)recvmsg->packet; -} - -static inline bool is_receive_credit_post_required(int receive_credits, - int avail_recvmsg_count) -{ - return receive_credits <= (smb_direct_receive_credit_max >> 3) && - avail_recvmsg_count >= (receive_credits >> 2); -} - -static struct -smb_direct_recvmsg *get_free_recvmsg(struct smb_direct_transport *t) -{ - struct smb_direct_recvmsg *recvmsg = NULL; - - spin_lock(&t->recvmsg_queue_lock); - if (!list_empty(&t->recvmsg_queue)) { - recvmsg = list_first_entry(&t->recvmsg_queue, - struct smb_direct_recvmsg, - list); - list_del(&recvmsg->list); - } - spin_unlock(&t->recvmsg_queue_lock); - return recvmsg; -} - -static void put_recvmsg(struct smb_direct_transport *t, - struct smb_direct_recvmsg *recvmsg) -{ - ib_dma_unmap_single(t->cm_id->device, recvmsg->sge.addr, - recvmsg->sge.length, DMA_FROM_DEVICE); - - spin_lock(&t->recvmsg_queue_lock); - list_add(&recvmsg->list, &t->recvmsg_queue); - spin_unlock(&t->recvmsg_queue_lock); -} - -static struct -smb_direct_recvmsg *get_empty_recvmsg(struct smb_direct_transport *t) -{ - struct smb_direct_recvmsg *recvmsg = NULL; - - spin_lock(&t->empty_recvmsg_queue_lock); - if (!list_empty(&t->empty_recvmsg_queue)) { - recvmsg = list_first_entry(&t->empty_recvmsg_queue, - struct smb_direct_recvmsg, list); - list_del(&recvmsg->list); - } - spin_unlock(&t->empty_recvmsg_queue_lock); - return recvmsg; -} - -static void put_empty_recvmsg(struct smb_direct_transport *t, - struct smb_direct_recvmsg *recvmsg) -{ - ib_dma_unmap_single(t->cm_id->device, recvmsg->sge.addr, - recvmsg->sge.length, DMA_FROM_DEVICE); - - spin_lock(&t->empty_recvmsg_queue_lock); - list_add_tail(&recvmsg->list, &t->empty_recvmsg_queue); - spin_unlock(&t->empty_recvmsg_queue_lock); -} - -static void enqueue_reassembly(struct smb_direct_transport *t, - struct smb_direct_recvmsg *recvmsg, - int data_length) -{ - spin_lock(&t->reassembly_queue_lock); - list_add_tail(&recvmsg->list, &t->reassembly_queue); - t->reassembly_queue_length++; - /* - * Make sure reassembly_data_length is updated after list and - * reassembly_queue_length are updated. On the dequeue side - * reassembly_data_length is checked without a lock to determine - * if reassembly_queue_length and list is up to date - */ - virt_wmb(); - t->reassembly_data_length += data_length; - spin_unlock(&t->reassembly_queue_lock); -} - -static struct smb_direct_recvmsg *get_first_reassembly(struct smb_direct_transport *t) -{ - if (!list_empty(&t->reassembly_queue)) - return list_first_entry(&t->reassembly_queue, - struct smb_direct_recvmsg, list); - else - return NULL; -} - -static void smb_direct_disconnect_rdma_work(struct work_struct *work) -{ - struct smb_direct_transport *t = - container_of(work, struct smb_direct_transport, - disconnect_work); - - if (t->status == SMB_DIRECT_CS_CONNECTED) { - t->status = SMB_DIRECT_CS_DISCONNECTING; - rdma_disconnect(t->cm_id); - } -} - -static void -smb_direct_disconnect_rdma_connection(struct smb_direct_transport *t) -{ - if (t->status == SMB_DIRECT_CS_CONNECTED) - queue_work(smb_direct_wq, &t->disconnect_work); -} - -static void smb_direct_send_immediate_work(struct work_struct *work) -{ - struct smb_direct_transport *t = container_of(work, - struct smb_direct_transport, send_immediate_work); - - if (t->status != SMB_DIRECT_CS_CONNECTED) - return; - - smb_direct_post_send_data(t, NULL, NULL, 0, 0); -} - -static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) -{ - struct smb_direct_transport *t; - struct ksmbd_conn *conn; - - t = kzalloc(sizeof(*t), GFP_KERNEL); - if (!t) - return NULL; - - t->cm_id = cm_id; - cm_id->context = t; - - t->status = SMB_DIRECT_CS_NEW; - init_waitqueue_head(&t->wait_status); - - spin_lock_init(&t->reassembly_queue_lock); - INIT_LIST_HEAD(&t->reassembly_queue); - t->reassembly_data_length = 0; - t->reassembly_queue_length = 0; - init_waitqueue_head(&t->wait_reassembly_queue); - init_waitqueue_head(&t->wait_send_credits); - init_waitqueue_head(&t->wait_rw_credits); - - spin_lock_init(&t->receive_credit_lock); - spin_lock_init(&t->recvmsg_queue_lock); - INIT_LIST_HEAD(&t->recvmsg_queue); - - spin_lock_init(&t->empty_recvmsg_queue_lock); - INIT_LIST_HEAD(&t->empty_recvmsg_queue); - - init_waitqueue_head(&t->wait_send_pending); - atomic_set(&t->send_pending, 0); - - spin_lock_init(&t->lock_new_recv_credits); - - INIT_DELAYED_WORK(&t->post_recv_credits_work, - smb_direct_post_recv_credits); - INIT_WORK(&t->send_immediate_work, smb_direct_send_immediate_work); - INIT_WORK(&t->disconnect_work, smb_direct_disconnect_rdma_work); - - conn = ksmbd_conn_alloc(); - if (!conn) - goto err; - conn->transport = KSMBD_TRANS(t); - KSMBD_TRANS(t)->conn = conn; - KSMBD_TRANS(t)->ops = &ksmbd_smb_direct_transport_ops; - return t; -err: - kfree(t); - return NULL; -} - -static void free_transport(struct smb_direct_transport *t) -{ - struct smb_direct_recvmsg *recvmsg; - - wake_up_interruptible(&t->wait_send_credits); - - ksmbd_debug(RDMA, "wait for all send posted to IB to finish\n"); - wait_event(t->wait_send_pending, - atomic_read(&t->send_pending) == 0); - - cancel_work_sync(&t->disconnect_work); - cancel_delayed_work_sync(&t->post_recv_credits_work); - cancel_work_sync(&t->send_immediate_work); - - if (t->qp) { - ib_drain_qp(t->qp); - ib_mr_pool_destroy(t->qp, &t->qp->rdma_mrs); - ib_destroy_qp(t->qp); - } - - ksmbd_debug(RDMA, "drain the reassembly queue\n"); - do { - spin_lock(&t->reassembly_queue_lock); - recvmsg = get_first_reassembly(t); - if (recvmsg) { - list_del(&recvmsg->list); - spin_unlock(&t->reassembly_queue_lock); - put_recvmsg(t, recvmsg); - } else { - spin_unlock(&t->reassembly_queue_lock); - } - } while (recvmsg); - t->reassembly_data_length = 0; - - if (t->send_cq) - ib_free_cq(t->send_cq); - if (t->recv_cq) - ib_free_cq(t->recv_cq); - if (t->pd) - ib_dealloc_pd(t->pd); - if (t->cm_id) - rdma_destroy_id(t->cm_id); - - smb_direct_destroy_pools(t); - ksmbd_conn_free(KSMBD_TRANS(t)->conn); - kfree(t); -} - -static struct smb_direct_sendmsg -*smb_direct_alloc_sendmsg(struct smb_direct_transport *t) -{ - struct smb_direct_sendmsg *msg; - - msg = mempool_alloc(t->sendmsg_mempool, GFP_KERNEL); - if (!msg) - return ERR_PTR(-ENOMEM); - msg->transport = t; - INIT_LIST_HEAD(&msg->list); - msg->num_sge = 0; - return msg; -} - -static void smb_direct_free_sendmsg(struct smb_direct_transport *t, - struct smb_direct_sendmsg *msg) -{ - int i; - - if (msg->num_sge > 0) { - ib_dma_unmap_single(t->cm_id->device, - msg->sge[0].addr, msg->sge[0].length, - DMA_TO_DEVICE); - for (i = 1; i < msg->num_sge; i++) - ib_dma_unmap_page(t->cm_id->device, - msg->sge[i].addr, msg->sge[i].length, - DMA_TO_DEVICE); - } - mempool_free(msg, t->sendmsg_mempool); -} - -static int smb_direct_check_recvmsg(struct smb_direct_recvmsg *recvmsg) -{ - switch (recvmsg->type) { - case SMB_DIRECT_MSG_DATA_TRANSFER: { - struct smb_direct_data_transfer *req = - (struct smb_direct_data_transfer *)recvmsg->packet; - struct smb2_hdr *hdr = (struct smb2_hdr *)(recvmsg->packet - + le32_to_cpu(req->data_offset)); - ksmbd_debug(RDMA, - "CreditGranted: %u, CreditRequested: %u, DataLength: %u, RemainingDataLength: %u, SMB: %x, Command: %u\n", - le16_to_cpu(req->credits_granted), - le16_to_cpu(req->credits_requested), - req->data_length, req->remaining_data_length, - hdr->ProtocolId, hdr->Command); - break; - } - case SMB_DIRECT_MSG_NEGOTIATE_REQ: { - struct smb_direct_negotiate_req *req = - (struct smb_direct_negotiate_req *)recvmsg->packet; - ksmbd_debug(RDMA, - "MinVersion: %u, MaxVersion: %u, CreditRequested: %u, MaxSendSize: %u, MaxRecvSize: %u, MaxFragmentedSize: %u\n", - le16_to_cpu(req->min_version), - le16_to_cpu(req->max_version), - le16_to_cpu(req->credits_requested), - le32_to_cpu(req->preferred_send_size), - le32_to_cpu(req->max_receive_size), - le32_to_cpu(req->max_fragmented_size)); - if (le16_to_cpu(req->min_version) > 0x0100 || - le16_to_cpu(req->max_version) < 0x0100) - return -EOPNOTSUPP; - if (le16_to_cpu(req->credits_requested) <= 0 || - le32_to_cpu(req->max_receive_size) <= 128 || - le32_to_cpu(req->max_fragmented_size) <= - 128 * 1024) - return -ECONNABORTED; - - break; - } - default: - return -EINVAL; - } - return 0; -} - -static void recv_done(struct ib_cq *cq, struct ib_wc *wc) -{ - struct smb_direct_recvmsg *recvmsg; - struct smb_direct_transport *t; - - recvmsg = container_of(wc->wr_cqe, struct smb_direct_recvmsg, cqe); - t = recvmsg->transport; - - if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) { - if (wc->status != IB_WC_WR_FLUSH_ERR) { - pr_err("Recv error. status='%s (%d)' opcode=%d\n", - ib_wc_status_msg(wc->status), wc->status, - wc->opcode); - smb_direct_disconnect_rdma_connection(t); - } - put_empty_recvmsg(t, recvmsg); - return; - } - - ksmbd_debug(RDMA, "Recv completed. status='%s (%d)', opcode=%d\n", - ib_wc_status_msg(wc->status), wc->status, - wc->opcode); - - ib_dma_sync_single_for_cpu(wc->qp->device, recvmsg->sge.addr, - recvmsg->sge.length, DMA_FROM_DEVICE); - - switch (recvmsg->type) { - case SMB_DIRECT_MSG_NEGOTIATE_REQ: - if (wc->byte_len < sizeof(struct smb_direct_negotiate_req)) { - put_empty_recvmsg(t, recvmsg); - return; - } - t->negotiation_requested = true; - t->full_packet_received = true; - t->status = SMB_DIRECT_CS_CONNECTED; - enqueue_reassembly(t, recvmsg, 0); - wake_up_interruptible(&t->wait_status); - break; - case SMB_DIRECT_MSG_DATA_TRANSFER: { - struct smb_direct_data_transfer *data_transfer = - (struct smb_direct_data_transfer *)recvmsg->packet; - unsigned int data_length; - int avail_recvmsg_count, receive_credits; - - if (wc->byte_len < - offsetof(struct smb_direct_data_transfer, padding)) { - put_empty_recvmsg(t, recvmsg); - return; - } - - data_length = le32_to_cpu(data_transfer->data_length); - if (data_length) { - if (wc->byte_len < sizeof(struct smb_direct_data_transfer) + - (u64)data_length) { - put_empty_recvmsg(t, recvmsg); - return; - } - - if (t->full_packet_received) - recvmsg->first_segment = true; - - if (le32_to_cpu(data_transfer->remaining_data_length)) - t->full_packet_received = false; - else - t->full_packet_received = true; - - enqueue_reassembly(t, recvmsg, (int)data_length); - wake_up_interruptible(&t->wait_reassembly_queue); - - spin_lock(&t->receive_credit_lock); - receive_credits = --(t->recv_credits); - avail_recvmsg_count = t->count_avail_recvmsg; - spin_unlock(&t->receive_credit_lock); - } else { - put_empty_recvmsg(t, recvmsg); - - spin_lock(&t->receive_credit_lock); - receive_credits = --(t->recv_credits); - avail_recvmsg_count = ++(t->count_avail_recvmsg); - spin_unlock(&t->receive_credit_lock); - } - - t->recv_credit_target = - le16_to_cpu(data_transfer->credits_requested); - atomic_add(le16_to_cpu(data_transfer->credits_granted), - &t->send_credits); - - if (le16_to_cpu(data_transfer->flags) & - SMB_DIRECT_RESPONSE_REQUESTED) - queue_work(smb_direct_wq, &t->send_immediate_work); - - if (atomic_read(&t->send_credits) > 0) - wake_up_interruptible(&t->wait_send_credits); - - if (is_receive_credit_post_required(receive_credits, avail_recvmsg_count)) - mod_delayed_work(smb_direct_wq, - &t->post_recv_credits_work, 0); - break; - } - default: - break; - } -} - -static int smb_direct_post_recv(struct smb_direct_transport *t, - struct smb_direct_recvmsg *recvmsg) -{ - struct ib_recv_wr wr; - int ret; - - recvmsg->sge.addr = ib_dma_map_single(t->cm_id->device, - recvmsg->packet, t->max_recv_size, - DMA_FROM_DEVICE); - ret = ib_dma_mapping_error(t->cm_id->device, recvmsg->sge.addr); - if (ret) - return ret; - recvmsg->sge.length = t->max_recv_size; - recvmsg->sge.lkey = t->pd->local_dma_lkey; - recvmsg->cqe.done = recv_done; - - wr.wr_cqe = &recvmsg->cqe; - wr.next = NULL; - wr.sg_list = &recvmsg->sge; - wr.num_sge = 1; - - ret = ib_post_recv(t->qp, &wr, NULL); - if (ret) { - pr_err("Can't post recv: %d\n", ret); - ib_dma_unmap_single(t->cm_id->device, - recvmsg->sge.addr, recvmsg->sge.length, - DMA_FROM_DEVICE); - smb_direct_disconnect_rdma_connection(t); - return ret; - } - return ret; -} - -static int smb_direct_read(struct ksmbd_transport *t, char *buf, - unsigned int size, int unused) -{ - struct smb_direct_recvmsg *recvmsg; - struct smb_direct_data_transfer *data_transfer; - int to_copy, to_read, data_read, offset; - u32 data_length, remaining_data_length, data_offset; - int rc; - struct smb_direct_transport *st = smb_trans_direct_transfort(t); - -again: - if (st->status != SMB_DIRECT_CS_CONNECTED) { - pr_err("disconnected\n"); - return -ENOTCONN; - } - - /* - * No need to hold the reassembly queue lock all the time as we are - * the only one reading from the front of the queue. The transport - * may add more entries to the back of the queue at the same time - */ - if (st->reassembly_data_length >= size) { - int queue_length; - int queue_removed = 0; - - /* - * Need to make sure reassembly_data_length is read before - * reading reassembly_queue_length and calling - * get_first_reassembly. This call is lock free - * as we never read at the end of the queue which are being - * updated in SOFTIRQ as more data is received - */ - virt_rmb(); - queue_length = st->reassembly_queue_length; - data_read = 0; - to_read = size; - offset = st->first_entry_offset; - while (data_read < size) { - recvmsg = get_first_reassembly(st); - data_transfer = smb_direct_recvmsg_payload(recvmsg); - data_length = le32_to_cpu(data_transfer->data_length); - remaining_data_length = - le32_to_cpu(data_transfer->remaining_data_length); - data_offset = le32_to_cpu(data_transfer->data_offset); - - /* - * The upper layer expects RFC1002 length at the - * beginning of the payload. Return it to indicate - * the total length of the packet. This minimize the - * change to upper layer packet processing logic. This - * will be eventually remove when an intermediate - * transport layer is added - */ - if (recvmsg->first_segment && size == 4) { - unsigned int rfc1002_len = - data_length + remaining_data_length; - *((__be32 *)buf) = cpu_to_be32(rfc1002_len); - data_read = 4; - recvmsg->first_segment = false; - ksmbd_debug(RDMA, - "returning rfc1002 length %d\n", - rfc1002_len); - goto read_rfc1002_done; - } - - to_copy = min_t(int, data_length - offset, to_read); - memcpy(buf + data_read, (char *)data_transfer + data_offset + offset, - to_copy); - - /* move on to the next buffer? */ - if (to_copy == data_length - offset) { - queue_length--; - /* - * No need to lock if we are not at the - * end of the queue - */ - if (queue_length) { - list_del(&recvmsg->list); - } else { - spin_lock_irq(&st->reassembly_queue_lock); - list_del(&recvmsg->list); - spin_unlock_irq(&st->reassembly_queue_lock); - } - queue_removed++; - put_recvmsg(st, recvmsg); - offset = 0; - } else { - offset += to_copy; - } - - to_read -= to_copy; - data_read += to_copy; - } - - spin_lock_irq(&st->reassembly_queue_lock); - st->reassembly_data_length -= data_read; - st->reassembly_queue_length -= queue_removed; - spin_unlock_irq(&st->reassembly_queue_lock); - - spin_lock(&st->receive_credit_lock); - st->count_avail_recvmsg += queue_removed; - if (is_receive_credit_post_required(st->recv_credits, st->count_avail_recvmsg)) { - spin_unlock(&st->receive_credit_lock); - mod_delayed_work(smb_direct_wq, - &st->post_recv_credits_work, 0); - } else { - spin_unlock(&st->receive_credit_lock); - } - - st->first_entry_offset = offset; - ksmbd_debug(RDMA, - "returning to thread data_read=%d reassembly_data_length=%d first_entry_offset=%d\n", - data_read, st->reassembly_data_length, - st->first_entry_offset); -read_rfc1002_done: - return data_read; - } - - ksmbd_debug(RDMA, "wait_event on more data\n"); - rc = wait_event_interruptible(st->wait_reassembly_queue, - st->reassembly_data_length >= size || - st->status != SMB_DIRECT_CS_CONNECTED); - if (rc) - return -EINTR; - - goto again; -} - -static void smb_direct_post_recv_credits(struct work_struct *work) -{ - struct smb_direct_transport *t = container_of(work, - struct smb_direct_transport, post_recv_credits_work.work); - struct smb_direct_recvmsg *recvmsg; - int receive_credits, credits = 0; - int ret; - int use_free = 1; - - spin_lock(&t->receive_credit_lock); - receive_credits = t->recv_credits; - spin_unlock(&t->receive_credit_lock); - - if (receive_credits < t->recv_credit_target) { - while (true) { - if (use_free) - recvmsg = get_free_recvmsg(t); - else - recvmsg = get_empty_recvmsg(t); - if (!recvmsg) { - if (use_free) { - use_free = 0; - continue; - } else { - break; - } - } - - recvmsg->type = SMB_DIRECT_MSG_DATA_TRANSFER; - recvmsg->first_segment = false; - - ret = smb_direct_post_recv(t, recvmsg); - if (ret) { - pr_err("Can't post recv: %d\n", ret); - put_recvmsg(t, recvmsg); - break; - } - credits++; - } - } - - spin_lock(&t->receive_credit_lock); - t->recv_credits += credits; - t->count_avail_recvmsg -= credits; - spin_unlock(&t->receive_credit_lock); - - spin_lock(&t->lock_new_recv_credits); - t->new_recv_credits += credits; - spin_unlock(&t->lock_new_recv_credits); - - if (credits) - queue_work(smb_direct_wq, &t->send_immediate_work); -} - -static void send_done(struct ib_cq *cq, struct ib_wc *wc) -{ - struct smb_direct_sendmsg *sendmsg, *sibling; - struct smb_direct_transport *t; - struct list_head *pos, *prev, *end; - - sendmsg = container_of(wc->wr_cqe, struct smb_direct_sendmsg, cqe); - t = sendmsg->transport; - - ksmbd_debug(RDMA, "Send completed. status='%s (%d)', opcode=%d\n", - ib_wc_status_msg(wc->status), wc->status, - wc->opcode); - - if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_SEND) { - pr_err("Send error. status='%s (%d)', opcode=%d\n", - ib_wc_status_msg(wc->status), wc->status, - wc->opcode); - smb_direct_disconnect_rdma_connection(t); - } - - if (atomic_dec_and_test(&t->send_pending)) - wake_up(&t->wait_send_pending); - - /* iterate and free the list of messages in reverse. the list's head - * is invalid. - */ - for (pos = &sendmsg->list, prev = pos->prev, end = sendmsg->list.next; - prev != end; pos = prev, prev = prev->prev) { - sibling = container_of(pos, struct smb_direct_sendmsg, list); - smb_direct_free_sendmsg(t, sibling); - } - - sibling = container_of(pos, struct smb_direct_sendmsg, list); - smb_direct_free_sendmsg(t, sibling); -} - -static int manage_credits_prior_sending(struct smb_direct_transport *t) -{ - int new_credits; - - spin_lock(&t->lock_new_recv_credits); - new_credits = t->new_recv_credits; - t->new_recv_credits = 0; - spin_unlock(&t->lock_new_recv_credits); - - return new_credits; -} - -static int smb_direct_post_send(struct smb_direct_transport *t, - struct ib_send_wr *wr) -{ - int ret; - - atomic_inc(&t->send_pending); - ret = ib_post_send(t->qp, wr, NULL); - if (ret) { - pr_err("failed to post send: %d\n", ret); - if (atomic_dec_and_test(&t->send_pending)) - wake_up(&t->wait_send_pending); - smb_direct_disconnect_rdma_connection(t); - } - return ret; -} - -static void smb_direct_send_ctx_init(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx, - bool need_invalidate_rkey, - unsigned int remote_key) -{ - INIT_LIST_HEAD(&send_ctx->msg_list); - send_ctx->wr_cnt = 0; - send_ctx->need_invalidate_rkey = need_invalidate_rkey; - send_ctx->remote_key = remote_key; -} - -static int smb_direct_flush_send_list(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx, - bool is_last) -{ - struct smb_direct_sendmsg *first, *last; - int ret; - - if (list_empty(&send_ctx->msg_list)) - return 0; - - first = list_first_entry(&send_ctx->msg_list, - struct smb_direct_sendmsg, - list); - last = list_last_entry(&send_ctx->msg_list, - struct smb_direct_sendmsg, - list); - - last->wr.send_flags = IB_SEND_SIGNALED; - last->wr.wr_cqe = &last->cqe; - if (is_last && send_ctx->need_invalidate_rkey) { - last->wr.opcode = IB_WR_SEND_WITH_INV; - last->wr.ex.invalidate_rkey = send_ctx->remote_key; - } - - ret = smb_direct_post_send(t, &first->wr); - if (!ret) { - smb_direct_send_ctx_init(t, send_ctx, - send_ctx->need_invalidate_rkey, - send_ctx->remote_key); - } else { - atomic_add(send_ctx->wr_cnt, &t->send_credits); - wake_up(&t->wait_send_credits); - list_for_each_entry_safe(first, last, &send_ctx->msg_list, - list) { - smb_direct_free_sendmsg(t, first); - } - } - return ret; -} - -static int wait_for_credits(struct smb_direct_transport *t, - wait_queue_head_t *waitq, atomic_t *total_credits, - int needed) -{ - int ret; - - do { - if (atomic_sub_return(needed, total_credits) >= 0) - return 0; - - atomic_add(needed, total_credits); - ret = wait_event_interruptible(*waitq, - atomic_read(total_credits) >= needed || - t->status != SMB_DIRECT_CS_CONNECTED); - - if (t->status != SMB_DIRECT_CS_CONNECTED) - return -ENOTCONN; - else if (ret < 0) - return ret; - } while (true); -} - -static int wait_for_send_credits(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx) -{ - int ret; - - if (send_ctx && - (send_ctx->wr_cnt >= 16 || atomic_read(&t->send_credits) <= 1)) { - ret = smb_direct_flush_send_list(t, send_ctx, false); - if (ret) - return ret; - } - - return wait_for_credits(t, &t->wait_send_credits, &t->send_credits, 1); -} - -static int wait_for_rw_credits(struct smb_direct_transport *t, int credits) -{ - return wait_for_credits(t, &t->wait_rw_credits, &t->rw_credits, credits); -} - -static int calc_rw_credits(struct smb_direct_transport *t, - char *buf, unsigned int len) -{ - return DIV_ROUND_UP(get_buf_page_count(buf, len), - t->pages_per_rw_credit); -} - -static int smb_direct_create_header(struct smb_direct_transport *t, - int size, int remaining_data_length, - struct smb_direct_sendmsg **sendmsg_out) -{ - struct smb_direct_sendmsg *sendmsg; - struct smb_direct_data_transfer *packet; - int header_length; - int ret; - - sendmsg = smb_direct_alloc_sendmsg(t); - if (IS_ERR(sendmsg)) - return PTR_ERR(sendmsg); - - /* Fill in the packet header */ - packet = (struct smb_direct_data_transfer *)sendmsg->packet; - packet->credits_requested = cpu_to_le16(t->send_credit_target); - packet->credits_granted = cpu_to_le16(manage_credits_prior_sending(t)); - - packet->flags = 0; - packet->reserved = 0; - if (!size) - packet->data_offset = 0; - else - packet->data_offset = cpu_to_le32(24); - packet->data_length = cpu_to_le32(size); - packet->remaining_data_length = cpu_to_le32(remaining_data_length); - packet->padding = 0; - - ksmbd_debug(RDMA, - "credits_requested=%d credits_granted=%d data_offset=%d data_length=%d remaining_data_length=%d\n", - le16_to_cpu(packet->credits_requested), - le16_to_cpu(packet->credits_granted), - le32_to_cpu(packet->data_offset), - le32_to_cpu(packet->data_length), - le32_to_cpu(packet->remaining_data_length)); - - /* Map the packet to DMA */ - header_length = sizeof(struct smb_direct_data_transfer); - /* If this is a packet without payload, don't send padding */ - if (!size) - header_length = - offsetof(struct smb_direct_data_transfer, padding); - - sendmsg->sge[0].addr = ib_dma_map_single(t->cm_id->device, - (void *)packet, - header_length, - DMA_TO_DEVICE); - ret = ib_dma_mapping_error(t->cm_id->device, sendmsg->sge[0].addr); - if (ret) { - smb_direct_free_sendmsg(t, sendmsg); - return ret; - } - - sendmsg->num_sge = 1; - sendmsg->sge[0].length = header_length; - sendmsg->sge[0].lkey = t->pd->local_dma_lkey; - - *sendmsg_out = sendmsg; - return 0; -} - -static int get_sg_list(void *buf, int size, struct scatterlist *sg_list, int nentries) -{ - bool high = is_vmalloc_addr(buf); - struct page *page; - int offset, len; - int i = 0; - - if (size <= 0 || nentries < get_buf_page_count(buf, size)) - return -EINVAL; - - offset = offset_in_page(buf); - buf -= offset; - while (size > 0) { - len = min_t(int, PAGE_SIZE - offset, size); - if (high) - page = vmalloc_to_page(buf); - else - page = kmap_to_page(buf); - - if (!sg_list) - return -EINVAL; - sg_set_page(sg_list, page, len, offset); - sg_list = sg_next(sg_list); - - buf += PAGE_SIZE; - size -= len; - offset = 0; - i++; - } - return i; -} - -static int get_mapped_sg_list(struct ib_device *device, void *buf, int size, - struct scatterlist *sg_list, int nentries, - enum dma_data_direction dir) -{ - int npages; - - npages = get_sg_list(buf, size, sg_list, nentries); - if (npages < 0) - return -EINVAL; - return ib_dma_map_sg(device, sg_list, npages, dir); -} - -static int post_sendmsg(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx, - struct smb_direct_sendmsg *msg) -{ - int i; - - for (i = 0; i < msg->num_sge; i++) - ib_dma_sync_single_for_device(t->cm_id->device, - msg->sge[i].addr, msg->sge[i].length, - DMA_TO_DEVICE); - - msg->cqe.done = send_done; - msg->wr.opcode = IB_WR_SEND; - msg->wr.sg_list = &msg->sge[0]; - msg->wr.num_sge = msg->num_sge; - msg->wr.next = NULL; - - if (send_ctx) { - msg->wr.wr_cqe = NULL; - msg->wr.send_flags = 0; - if (!list_empty(&send_ctx->msg_list)) { - struct smb_direct_sendmsg *last; - - last = list_last_entry(&send_ctx->msg_list, - struct smb_direct_sendmsg, - list); - last->wr.next = &msg->wr; - } - list_add_tail(&msg->list, &send_ctx->msg_list); - send_ctx->wr_cnt++; - return 0; - } - - msg->wr.wr_cqe = &msg->cqe; - msg->wr.send_flags = IB_SEND_SIGNALED; - return smb_direct_post_send(t, &msg->wr); -} - -static int smb_direct_post_send_data(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx, - struct kvec *iov, int niov, - int remaining_data_length) -{ - int i, j, ret; - struct smb_direct_sendmsg *msg; - int data_length; - struct scatterlist sg[SMB_DIRECT_MAX_SEND_SGES - 1]; - - ret = wait_for_send_credits(t, send_ctx); - if (ret) - return ret; - - data_length = 0; - for (i = 0; i < niov; i++) - data_length += iov[i].iov_len; - - ret = smb_direct_create_header(t, data_length, remaining_data_length, - &msg); - if (ret) { - atomic_inc(&t->send_credits); - return ret; - } - - for (i = 0; i < niov; i++) { - struct ib_sge *sge; - int sg_cnt; - - sg_init_table(sg, SMB_DIRECT_MAX_SEND_SGES - 1); - sg_cnt = get_mapped_sg_list(t->cm_id->device, - iov[i].iov_base, iov[i].iov_len, - sg, SMB_DIRECT_MAX_SEND_SGES - 1, - DMA_TO_DEVICE); - if (sg_cnt <= 0) { - pr_err("failed to map buffer\n"); - ret = -ENOMEM; - goto err; - } else if (sg_cnt + msg->num_sge > SMB_DIRECT_MAX_SEND_SGES) { - pr_err("buffer not fitted into sges\n"); - ret = -E2BIG; - ib_dma_unmap_sg(t->cm_id->device, sg, sg_cnt, - DMA_TO_DEVICE); - goto err; - } - - for (j = 0; j < sg_cnt; j++) { - sge = &msg->sge[msg->num_sge]; - sge->addr = sg_dma_address(&sg[j]); - sge->length = sg_dma_len(&sg[j]); - sge->lkey = t->pd->local_dma_lkey; - msg->num_sge++; - } - } - - ret = post_sendmsg(t, send_ctx, msg); - if (ret) - goto err; - return 0; -err: - smb_direct_free_sendmsg(t, msg); - atomic_inc(&t->send_credits); - return ret; -} - -static int smb_direct_writev(struct ksmbd_transport *t, - struct kvec *iov, int niovs, int buflen, - bool need_invalidate, unsigned int remote_key) -{ - struct smb_direct_transport *st = smb_trans_direct_transfort(t); - int remaining_data_length; - int start, i, j; - int max_iov_size = st->max_send_size - - sizeof(struct smb_direct_data_transfer); - int ret; - struct kvec vec; - struct smb_direct_send_ctx send_ctx; - - if (st->status != SMB_DIRECT_CS_CONNECTED) - return -ENOTCONN; - - //FIXME: skip RFC1002 header.. - buflen -= 4; - iov[0].iov_base += 4; - iov[0].iov_len -= 4; - - remaining_data_length = buflen; - ksmbd_debug(RDMA, "Sending smb (RDMA): smb_len=%u\n", buflen); - - smb_direct_send_ctx_init(st, &send_ctx, need_invalidate, remote_key); - start = i = 0; - buflen = 0; - while (true) { - buflen += iov[i].iov_len; - if (buflen > max_iov_size) { - if (i > start) { - remaining_data_length -= - (buflen - iov[i].iov_len); - ret = smb_direct_post_send_data(st, &send_ctx, - &iov[start], i - start, - remaining_data_length); - if (ret) - goto done; - } else { - /* iov[start] is too big, break it */ - int nvec = (buflen + max_iov_size - 1) / - max_iov_size; - - for (j = 0; j < nvec; j++) { - vec.iov_base = - (char *)iov[start].iov_base + - j * max_iov_size; - vec.iov_len = - min_t(int, max_iov_size, - buflen - max_iov_size * j); - remaining_data_length -= vec.iov_len; - ret = smb_direct_post_send_data(st, &send_ctx, &vec, 1, - remaining_data_length); - if (ret) - goto done; - } - i++; - if (i == niovs) - break; - } - start = i; - buflen = 0; - } else { - i++; - if (i == niovs) { - /* send out all remaining vecs */ - remaining_data_length -= buflen; - ret = smb_direct_post_send_data(st, &send_ctx, - &iov[start], i - start, - remaining_data_length); - if (ret) - goto done; - break; - } - } - } - -done: - ret = smb_direct_flush_send_list(st, &send_ctx, true); - - /* - * As an optimization, we don't wait for individual I/O to finish - * before sending the next one. - * Send them all and wait for pending send count to get to 0 - * that means all the I/Os have been out and we are good to return - */ - - wait_event(st->wait_send_pending, - atomic_read(&st->send_pending) == 0); - return ret; -} - -static void smb_direct_free_rdma_rw_msg(struct smb_direct_transport *t, - struct smb_direct_rdma_rw_msg *msg, - enum dma_data_direction dir) -{ - rdma_rw_ctx_destroy(&msg->rw_ctx, t->qp, t->qp->port, - msg->sgt.sgl, msg->sgt.nents, dir); - sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE); - kfree(msg); -} - -static void read_write_done(struct ib_cq *cq, struct ib_wc *wc, - enum dma_data_direction dir) -{ - struct smb_direct_rdma_rw_msg *msg = container_of(wc->wr_cqe, - struct smb_direct_rdma_rw_msg, cqe); - struct smb_direct_transport *t = msg->t; - - if (wc->status != IB_WC_SUCCESS) { - msg->status = -EIO; - pr_err("read/write error. opcode = %d, status = %s(%d)\n", - wc->opcode, ib_wc_status_msg(wc->status), wc->status); - if (wc->status != IB_WC_WR_FLUSH_ERR) - smb_direct_disconnect_rdma_connection(t); - } - - complete(msg->completion); -} - -static void read_done(struct ib_cq *cq, struct ib_wc *wc) -{ - read_write_done(cq, wc, DMA_FROM_DEVICE); -} - -static void write_done(struct ib_cq *cq, struct ib_wc *wc) -{ - read_write_done(cq, wc, DMA_TO_DEVICE); -} - -static int smb_direct_rdma_xmit(struct smb_direct_transport *t, - void *buf, int buf_len, - struct smb2_buffer_desc_v1 *desc, - unsigned int desc_len, - bool is_read) -{ - struct smb_direct_rdma_rw_msg *msg, *next_msg; - int i, ret; - DECLARE_COMPLETION_ONSTACK(completion); - struct ib_send_wr *first_wr; - LIST_HEAD(msg_list); - char *desc_buf; - int credits_needed; - unsigned int desc_buf_len; - size_t total_length = 0; - - if (t->status != SMB_DIRECT_CS_CONNECTED) - return -ENOTCONN; - - /* calculate needed credits */ - credits_needed = 0; - desc_buf = buf; - for (i = 0; i < desc_len / sizeof(*desc); i++) { - desc_buf_len = le32_to_cpu(desc[i].length); - - credits_needed += calc_rw_credits(t, desc_buf, desc_buf_len); - desc_buf += desc_buf_len; - total_length += desc_buf_len; - if (desc_buf_len == 0 || total_length > buf_len || - total_length > t->max_rdma_rw_size) - return -EINVAL; - } - - ksmbd_debug(RDMA, "RDMA %s, len %#x, needed credits %#x\n", - is_read ? "read" : "write", buf_len, credits_needed); - - ret = wait_for_rw_credits(t, credits_needed); - if (ret < 0) - return ret; - - /* build rdma_rw_ctx for each descriptor */ - desc_buf = buf; - for (i = 0; i < desc_len / sizeof(*desc); i++) { - msg = kzalloc(offsetof(struct smb_direct_rdma_rw_msg, sg_list) + - sizeof(struct scatterlist) * SG_CHUNK_SIZE, GFP_KERNEL); - if (!msg) { - ret = -ENOMEM; - goto out; - } - - desc_buf_len = le32_to_cpu(desc[i].length); - - msg->t = t; - msg->cqe.done = is_read ? read_done : write_done; - msg->completion = &completion; - - msg->sgt.sgl = &msg->sg_list[0]; - ret = sg_alloc_table_chained(&msg->sgt, - get_buf_page_count(desc_buf, desc_buf_len), - msg->sg_list, SG_CHUNK_SIZE); - if (ret) { - kfree(msg); - ret = -ENOMEM; - goto out; - } - - ret = get_sg_list(desc_buf, desc_buf_len, - msg->sgt.sgl, msg->sgt.orig_nents); - if (ret < 0) { - sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE); - kfree(msg); - goto out; - } - - ret = rdma_rw_ctx_init(&msg->rw_ctx, t->qp, t->qp->port, - msg->sgt.sgl, - get_buf_page_count(desc_buf, desc_buf_len), - 0, - le64_to_cpu(desc[i].offset), - le32_to_cpu(desc[i].token), - is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (ret < 0) { - pr_err("failed to init rdma_rw_ctx: %d\n", ret); - sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE); - kfree(msg); - goto out; - } - - list_add_tail(&msg->list, &msg_list); - desc_buf += desc_buf_len; - } - - /* concatenate work requests of rdma_rw_ctxs */ - first_wr = NULL; - list_for_each_entry_reverse(msg, &msg_list, list) { - first_wr = rdma_rw_ctx_wrs(&msg->rw_ctx, t->qp, t->qp->port, - &msg->cqe, first_wr); - } - - ret = ib_post_send(t->qp, first_wr, NULL); - if (ret) { - pr_err("failed to post send wr for RDMA R/W: %d\n", ret); - goto out; - } - - msg = list_last_entry(&msg_list, struct smb_direct_rdma_rw_msg, list); - wait_for_completion(&completion); - ret = msg->status; -out: - list_for_each_entry_safe(msg, next_msg, &msg_list, list) { - list_del(&msg->list); - smb_direct_free_rdma_rw_msg(t, msg, - is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - } - atomic_add(credits_needed, &t->rw_credits); - wake_up(&t->wait_rw_credits); - return ret; -} - -static int smb_direct_rdma_write(struct ksmbd_transport *t, - void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, - unsigned int desc_len) -{ - return smb_direct_rdma_xmit(smb_trans_direct_transfort(t), buf, buflen, - desc, desc_len, false); -} - -static int smb_direct_rdma_read(struct ksmbd_transport *t, - void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, - unsigned int desc_len) -{ - return smb_direct_rdma_xmit(smb_trans_direct_transfort(t), buf, buflen, - desc, desc_len, true); -} - -static void smb_direct_disconnect(struct ksmbd_transport *t) -{ - struct smb_direct_transport *st = smb_trans_direct_transfort(t); - - ksmbd_debug(RDMA, "Disconnecting cm_id=%p\n", st->cm_id); - - smb_direct_disconnect_rdma_work(&st->disconnect_work); - wait_event_interruptible(st->wait_status, - st->status == SMB_DIRECT_CS_DISCONNECTED); - free_transport(st); -} - -static void smb_direct_shutdown(struct ksmbd_transport *t) -{ - struct smb_direct_transport *st = smb_trans_direct_transfort(t); - - ksmbd_debug(RDMA, "smb-direct shutdown cm_id=%p\n", st->cm_id); - - smb_direct_disconnect_rdma_work(&st->disconnect_work); -} - -static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, - struct rdma_cm_event *event) -{ - struct smb_direct_transport *t = cm_id->context; - - ksmbd_debug(RDMA, "RDMA CM event. cm_id=%p event=%s (%d)\n", - cm_id, rdma_event_msg(event->event), event->event); - - switch (event->event) { - case RDMA_CM_EVENT_ESTABLISHED: { - t->status = SMB_DIRECT_CS_CONNECTED; - wake_up_interruptible(&t->wait_status); - break; - } - case RDMA_CM_EVENT_DEVICE_REMOVAL: - case RDMA_CM_EVENT_DISCONNECTED: { - ib_drain_qp(t->qp); - - t->status = SMB_DIRECT_CS_DISCONNECTED; - wake_up_interruptible(&t->wait_status); - wake_up_interruptible(&t->wait_reassembly_queue); - wake_up(&t->wait_send_credits); - break; - } - case RDMA_CM_EVENT_CONNECT_ERROR: { - t->status = SMB_DIRECT_CS_DISCONNECTED; - wake_up_interruptible(&t->wait_status); - break; - } - default: - pr_err("Unexpected RDMA CM event. cm_id=%p, event=%s (%d)\n", - cm_id, rdma_event_msg(event->event), - event->event); - break; - } - return 0; -} - -static void smb_direct_qpair_handler(struct ib_event *event, void *context) -{ - struct smb_direct_transport *t = context; - - ksmbd_debug(RDMA, "Received QP event. cm_id=%p, event=%s (%d)\n", - t->cm_id, ib_event_msg(event->event), event->event); - - switch (event->event) { - case IB_EVENT_CQ_ERR: - case IB_EVENT_QP_FATAL: - smb_direct_disconnect_rdma_connection(t); - break; - default: - break; - } -} - -static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, - int failed) -{ - struct smb_direct_sendmsg *sendmsg; - struct smb_direct_negotiate_resp *resp; - int ret; - - sendmsg = smb_direct_alloc_sendmsg(t); - if (IS_ERR(sendmsg)) - return -ENOMEM; - - resp = (struct smb_direct_negotiate_resp *)sendmsg->packet; - if (failed) { - memset(resp, 0, sizeof(*resp)); - resp->min_version = cpu_to_le16(0x0100); - resp->max_version = cpu_to_le16(0x0100); - resp->status = STATUS_NOT_SUPPORTED; - } else { - resp->status = STATUS_SUCCESS; - resp->min_version = SMB_DIRECT_VERSION_LE; - resp->max_version = SMB_DIRECT_VERSION_LE; - resp->negotiated_version = SMB_DIRECT_VERSION_LE; - resp->reserved = 0; - resp->credits_requested = - cpu_to_le16(t->send_credit_target); - resp->credits_granted = cpu_to_le16(manage_credits_prior_sending(t)); - resp->max_readwrite_size = cpu_to_le32(t->max_rdma_rw_size); - resp->preferred_send_size = cpu_to_le32(t->max_send_size); - resp->max_receive_size = cpu_to_le32(t->max_recv_size); - resp->max_fragmented_size = - cpu_to_le32(t->max_fragmented_recv_size); - } - - sendmsg->sge[0].addr = ib_dma_map_single(t->cm_id->device, - (void *)resp, sizeof(*resp), - DMA_TO_DEVICE); - ret = ib_dma_mapping_error(t->cm_id->device, sendmsg->sge[0].addr); - if (ret) { - smb_direct_free_sendmsg(t, sendmsg); - return ret; - } - - sendmsg->num_sge = 1; - sendmsg->sge[0].length = sizeof(*resp); - sendmsg->sge[0].lkey = t->pd->local_dma_lkey; - - ret = post_sendmsg(t, NULL, sendmsg); - if (ret) { - smb_direct_free_sendmsg(t, sendmsg); - return ret; - } - - wait_event(t->wait_send_pending, - atomic_read(&t->send_pending) == 0); - return 0; -} - -static int smb_direct_accept_client(struct smb_direct_transport *t) -{ - struct rdma_conn_param conn_param; - struct ib_port_immutable port_immutable; - u32 ird_ord_hdr[2]; - int ret; - - memset(&conn_param, 0, sizeof(conn_param)); - conn_param.initiator_depth = min_t(u8, t->cm_id->device->attrs.max_qp_rd_atom, - SMB_DIRECT_CM_INITIATOR_DEPTH); - conn_param.responder_resources = 0; - - t->cm_id->device->ops.get_port_immutable(t->cm_id->device, - t->cm_id->port_num, - &port_immutable); - if (port_immutable.core_cap_flags & RDMA_CORE_PORT_IWARP) { - ird_ord_hdr[0] = conn_param.responder_resources; - ird_ord_hdr[1] = 1; - conn_param.private_data = ird_ord_hdr; - conn_param.private_data_len = sizeof(ird_ord_hdr); - } else { - conn_param.private_data = NULL; - conn_param.private_data_len = 0; - } - conn_param.retry_count = SMB_DIRECT_CM_RETRY; - conn_param.rnr_retry_count = SMB_DIRECT_CM_RNR_RETRY; - conn_param.flow_control = 0; - - ret = rdma_accept(t->cm_id, &conn_param); - if (ret) { - pr_err("error at rdma_accept: %d\n", ret); - return ret; - } - return 0; -} - -static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) -{ - int ret; - struct smb_direct_recvmsg *recvmsg; - - recvmsg = get_free_recvmsg(t); - if (!recvmsg) - return -ENOMEM; - recvmsg->type = SMB_DIRECT_MSG_NEGOTIATE_REQ; - - ret = smb_direct_post_recv(t, recvmsg); - if (ret) { - pr_err("Can't post recv: %d\n", ret); - goto out_err; - } - - t->negotiation_requested = false; - ret = smb_direct_accept_client(t); - if (ret) { - pr_err("Can't accept client\n"); - goto out_err; - } - - smb_direct_post_recv_credits(&t->post_recv_credits_work.work); - return 0; -out_err: - put_recvmsg(t, recvmsg); - return ret; -} - -static unsigned int smb_direct_get_max_fr_pages(struct smb_direct_transport *t) -{ - return min_t(unsigned int, - t->cm_id->device->attrs.max_fast_reg_page_list_len, - 256); -} - -static int smb_direct_init_params(struct smb_direct_transport *t, - struct ib_qp_cap *cap) -{ - struct ib_device *device = t->cm_id->device; - int max_send_sges, max_rw_wrs, max_send_wrs; - unsigned int max_sge_per_wr, wrs_per_credit; - - /* need 3 more sge. because a SMB_DIRECT header, SMB2 header, - * SMB2 response could be mapped. - */ - t->max_send_size = smb_direct_max_send_size; - max_send_sges = DIV_ROUND_UP(t->max_send_size, PAGE_SIZE) + 3; - if (max_send_sges > SMB_DIRECT_MAX_SEND_SGES) { - pr_err("max_send_size %d is too large\n", t->max_send_size); - return -EINVAL; - } - - /* Calculate the number of work requests for RDMA R/W. - * The maximum number of pages which can be registered - * with one Memory region can be transferred with one - * R/W credit. And at least 4 work requests for each credit - * are needed for MR registration, RDMA R/W, local & remote - * MR invalidation. - */ - t->max_rdma_rw_size = smb_direct_max_read_write_size; - t->pages_per_rw_credit = smb_direct_get_max_fr_pages(t); - t->max_rw_credits = DIV_ROUND_UP(t->max_rdma_rw_size, - (t->pages_per_rw_credit - 1) * - PAGE_SIZE); - - max_sge_per_wr = min_t(unsigned int, device->attrs.max_send_sge, - device->attrs.max_sge_rd); - max_sge_per_wr = max_t(unsigned int, max_sge_per_wr, - max_send_sges); - wrs_per_credit = max_t(unsigned int, 4, - DIV_ROUND_UP(t->pages_per_rw_credit, - max_sge_per_wr) + 1); - max_rw_wrs = t->max_rw_credits * wrs_per_credit; - - max_send_wrs = smb_direct_send_credit_target + max_rw_wrs; - if (max_send_wrs > device->attrs.max_cqe || - max_send_wrs > device->attrs.max_qp_wr) { - pr_err("consider lowering send_credit_target = %d\n", - smb_direct_send_credit_target); - pr_err("Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n", - device->attrs.max_cqe, device->attrs.max_qp_wr); - return -EINVAL; - } - - if (smb_direct_receive_credit_max > device->attrs.max_cqe || - smb_direct_receive_credit_max > device->attrs.max_qp_wr) { - pr_err("consider lowering receive_credit_max = %d\n", - smb_direct_receive_credit_max); - pr_err("Possible CQE overrun, device reporting max_cpe %d max_qp_wr %d\n", - device->attrs.max_cqe, device->attrs.max_qp_wr); - return -EINVAL; - } - - if (device->attrs.max_recv_sge < SMB_DIRECT_MAX_RECV_SGES) { - pr_err("warning: device max_recv_sge = %d too small\n", - device->attrs.max_recv_sge); - return -EINVAL; - } - - t->recv_credits = 0; - t->count_avail_recvmsg = 0; - - t->recv_credit_max = smb_direct_receive_credit_max; - t->recv_credit_target = 10; - t->new_recv_credits = 0; - - t->send_credit_target = smb_direct_send_credit_target; - atomic_set(&t->send_credits, 0); - atomic_set(&t->rw_credits, t->max_rw_credits); - - t->max_send_size = smb_direct_max_send_size; - t->max_recv_size = smb_direct_max_receive_size; - t->max_fragmented_recv_size = smb_direct_max_fragmented_recv_size; - - cap->max_send_wr = max_send_wrs; - cap->max_recv_wr = t->recv_credit_max; - cap->max_send_sge = max_sge_per_wr; - cap->max_recv_sge = SMB_DIRECT_MAX_RECV_SGES; - cap->max_inline_data = 0; - cap->max_rdma_ctxs = t->max_rw_credits; - return 0; -} - -static void smb_direct_destroy_pools(struct smb_direct_transport *t) -{ - struct smb_direct_recvmsg *recvmsg; - - while ((recvmsg = get_free_recvmsg(t))) - mempool_free(recvmsg, t->recvmsg_mempool); - while ((recvmsg = get_empty_recvmsg(t))) - mempool_free(recvmsg, t->recvmsg_mempool); - - mempool_destroy(t->recvmsg_mempool); - t->recvmsg_mempool = NULL; - - kmem_cache_destroy(t->recvmsg_cache); - t->recvmsg_cache = NULL; - - mempool_destroy(t->sendmsg_mempool); - t->sendmsg_mempool = NULL; - - kmem_cache_destroy(t->sendmsg_cache); - t->sendmsg_cache = NULL; -} - -static int smb_direct_create_pools(struct smb_direct_transport *t) -{ - char name[80]; - int i; - struct smb_direct_recvmsg *recvmsg; - - snprintf(name, sizeof(name), "smb_direct_rqst_pool_%p", t); - t->sendmsg_cache = kmem_cache_create(name, - sizeof(struct smb_direct_sendmsg) + - sizeof(struct smb_direct_negotiate_resp), - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!t->sendmsg_cache) - return -ENOMEM; - - t->sendmsg_mempool = mempool_create(t->send_credit_target, - mempool_alloc_slab, mempool_free_slab, - t->sendmsg_cache); - if (!t->sendmsg_mempool) - goto err; - - snprintf(name, sizeof(name), "smb_direct_resp_%p", t); - t->recvmsg_cache = kmem_cache_create(name, - sizeof(struct smb_direct_recvmsg) + - t->max_recv_size, - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!t->recvmsg_cache) - goto err; - - t->recvmsg_mempool = - mempool_create(t->recv_credit_max, mempool_alloc_slab, - mempool_free_slab, t->recvmsg_cache); - if (!t->recvmsg_mempool) - goto err; - - INIT_LIST_HEAD(&t->recvmsg_queue); - - for (i = 0; i < t->recv_credit_max; i++) { - recvmsg = mempool_alloc(t->recvmsg_mempool, GFP_KERNEL); - if (!recvmsg) - goto err; - recvmsg->transport = t; - list_add(&recvmsg->list, &t->recvmsg_queue); - } - t->count_avail_recvmsg = t->recv_credit_max; - - return 0; -err: - smb_direct_destroy_pools(t); - return -ENOMEM; -} - -static int smb_direct_create_qpair(struct smb_direct_transport *t, - struct ib_qp_cap *cap) -{ - int ret; - struct ib_qp_init_attr qp_attr; - int pages_per_rw; - - t->pd = ib_alloc_pd(t->cm_id->device, 0); - if (IS_ERR(t->pd)) { - pr_err("Can't create RDMA PD\n"); - ret = PTR_ERR(t->pd); - t->pd = NULL; - return ret; - } - - t->send_cq = ib_alloc_cq(t->cm_id->device, t, - smb_direct_send_credit_target + cap->max_rdma_ctxs, - 0, IB_POLL_WORKQUEUE); - if (IS_ERR(t->send_cq)) { - pr_err("Can't create RDMA send CQ\n"); - ret = PTR_ERR(t->send_cq); - t->send_cq = NULL; - goto err; - } - - t->recv_cq = ib_alloc_cq(t->cm_id->device, t, - t->recv_credit_max, 0, IB_POLL_WORKQUEUE); - if (IS_ERR(t->recv_cq)) { - pr_err("Can't create RDMA recv CQ\n"); - ret = PTR_ERR(t->recv_cq); - t->recv_cq = NULL; - goto err; - } - - memset(&qp_attr, 0, sizeof(qp_attr)); - qp_attr.event_handler = smb_direct_qpair_handler; - qp_attr.qp_context = t; - qp_attr.cap = *cap; - qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR; - qp_attr.qp_type = IB_QPT_RC; - qp_attr.send_cq = t->send_cq; - qp_attr.recv_cq = t->recv_cq; - qp_attr.port_num = ~0; - - ret = rdma_create_qp(t->cm_id, t->pd, &qp_attr); - if (ret) { - pr_err("Can't create RDMA QP: %d\n", ret); - goto err; - } - - t->qp = t->cm_id->qp; - t->cm_id->event_handler = smb_direct_cm_handler; - - pages_per_rw = DIV_ROUND_UP(t->max_rdma_rw_size, PAGE_SIZE) + 1; - if (pages_per_rw > t->cm_id->device->attrs.max_sgl_rd) { - ret = ib_mr_pool_init(t->qp, &t->qp->rdma_mrs, - t->max_rw_credits, IB_MR_TYPE_MEM_REG, - t->pages_per_rw_credit, 0); - if (ret) { - pr_err("failed to init mr pool count %d pages %d\n", - t->max_rw_credits, t->pages_per_rw_credit); - goto err; - } - } - - return 0; -err: - if (t->qp) { - ib_destroy_qp(t->qp); - t->qp = NULL; - } - if (t->recv_cq) { - ib_destroy_cq(t->recv_cq); - t->recv_cq = NULL; - } - if (t->send_cq) { - ib_destroy_cq(t->send_cq); - t->send_cq = NULL; - } - if (t->pd) { - ib_dealloc_pd(t->pd); - t->pd = NULL; - } - return ret; -} - -static int smb_direct_prepare(struct ksmbd_transport *t) -{ - struct smb_direct_transport *st = smb_trans_direct_transfort(t); - struct smb_direct_recvmsg *recvmsg; - struct smb_direct_negotiate_req *req; - int ret; - - ksmbd_debug(RDMA, "Waiting for SMB_DIRECT negotiate request\n"); - ret = wait_event_interruptible_timeout(st->wait_status, - st->negotiation_requested || - st->status == SMB_DIRECT_CS_DISCONNECTED, - SMB_DIRECT_NEGOTIATE_TIMEOUT * HZ); - if (ret <= 0 || st->status == SMB_DIRECT_CS_DISCONNECTED) - return ret < 0 ? ret : -ETIMEDOUT; - - recvmsg = get_first_reassembly(st); - if (!recvmsg) - return -ECONNABORTED; - - ret = smb_direct_check_recvmsg(recvmsg); - if (ret == -ECONNABORTED) - goto out; - - req = (struct smb_direct_negotiate_req *)recvmsg->packet; - st->max_recv_size = min_t(int, st->max_recv_size, - le32_to_cpu(req->preferred_send_size)); - st->max_send_size = min_t(int, st->max_send_size, - le32_to_cpu(req->max_receive_size)); - st->max_fragmented_send_size = - le32_to_cpu(req->max_fragmented_size); - st->max_fragmented_recv_size = - (st->recv_credit_max * st->max_recv_size) / 2; - - ret = smb_direct_send_negotiate_response(st, ret); -out: - spin_lock_irq(&st->reassembly_queue_lock); - st->reassembly_queue_length--; - list_del(&recvmsg->list); - spin_unlock_irq(&st->reassembly_queue_lock); - put_recvmsg(st, recvmsg); - - return ret; -} - -static int smb_direct_connect(struct smb_direct_transport *st) -{ - int ret; - struct ib_qp_cap qp_cap; - - ret = smb_direct_init_params(st, &qp_cap); - if (ret) { - pr_err("Can't configure RDMA parameters\n"); - return ret; - } - - ret = smb_direct_create_pools(st); - if (ret) { - pr_err("Can't init RDMA pool: %d\n", ret); - return ret; - } - - ret = smb_direct_create_qpair(st, &qp_cap); - if (ret) { - pr_err("Can't accept RDMA client: %d\n", ret); - return ret; - } - - ret = smb_direct_prepare_negotiation(st); - if (ret) { - pr_err("Can't negotiate: %d\n", ret); - return ret; - } - return 0; -} - -static bool rdma_frwr_is_supported(struct ib_device_attr *attrs) -{ - if (!(attrs->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS)) - return false; - if (attrs->max_fast_reg_page_list_len == 0) - return false; - return true; -} - -static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id) -{ - struct smb_direct_transport *t; - int ret; - - if (!rdma_frwr_is_supported(&new_cm_id->device->attrs)) { - ksmbd_debug(RDMA, - "Fast Registration Work Requests is not supported. device capabilities=%llx\n", - new_cm_id->device->attrs.device_cap_flags); - return -EPROTONOSUPPORT; - } - - t = alloc_transport(new_cm_id); - if (!t) - return -ENOMEM; - - ret = smb_direct_connect(t); - if (ret) - goto out_err; - - KSMBD_TRANS(t)->handler = kthread_run(ksmbd_conn_handler_loop, - KSMBD_TRANS(t)->conn, "ksmbd:r%u", - smb_direct_port); - if (IS_ERR(KSMBD_TRANS(t)->handler)) { - ret = PTR_ERR(KSMBD_TRANS(t)->handler); - pr_err("Can't start thread\n"); - goto out_err; - } - - return 0; -out_err: - free_transport(t); - return ret; -} - -static int smb_direct_listen_handler(struct rdma_cm_id *cm_id, - struct rdma_cm_event *event) -{ - switch (event->event) { - case RDMA_CM_EVENT_CONNECT_REQUEST: { - int ret = smb_direct_handle_connect_request(cm_id); - - if (ret) { - pr_err("Can't create transport: %d\n", ret); - return ret; - } - - ksmbd_debug(RDMA, "Received connection request. cm_id=%p\n", - cm_id); - break; - } - default: - pr_err("Unexpected listen event. cm_id=%p, event=%s (%d)\n", - cm_id, rdma_event_msg(event->event), event->event); - break; - } - return 0; -} - -static int smb_direct_listen(int port) -{ - int ret; - struct rdma_cm_id *cm_id; - struct sockaddr_in sin = { - .sin_family = AF_INET, - .sin_addr.s_addr = htonl(INADDR_ANY), - .sin_port = htons(port), - }; - - cm_id = rdma_create_id(&init_net, smb_direct_listen_handler, - &smb_direct_listener, RDMA_PS_TCP, IB_QPT_RC); - if (IS_ERR(cm_id)) { - pr_err("Can't create cm id: %ld\n", PTR_ERR(cm_id)); - return PTR_ERR(cm_id); - } - - ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin); - if (ret) { - pr_err("Can't bind: %d\n", ret); - goto err; - } - - smb_direct_listener.cm_id = cm_id; - - ret = rdma_listen(cm_id, 10); - if (ret) { - pr_err("Can't listen: %d\n", ret); - goto err; - } - return 0; -err: - smb_direct_listener.cm_id = NULL; - rdma_destroy_id(cm_id); - return ret; -} - -static int smb_direct_ib_client_add(struct ib_device *ib_dev) -{ - struct smb_direct_device *smb_dev; - - /* Set 5445 port if device type is iWARP(No IB) */ - if (ib_dev->node_type != RDMA_NODE_IB_CA) - smb_direct_port = SMB_DIRECT_PORT_IWARP; - - if (!ib_dev->ops.get_netdev || - !rdma_frwr_is_supported(&ib_dev->attrs)) - return 0; - - smb_dev = kzalloc(sizeof(*smb_dev), GFP_KERNEL); - if (!smb_dev) - return -ENOMEM; - smb_dev->ib_dev = ib_dev; - - write_lock(&smb_direct_device_lock); - list_add(&smb_dev->list, &smb_direct_device_list); - write_unlock(&smb_direct_device_lock); - - ksmbd_debug(RDMA, "ib device added: name %s\n", ib_dev->name); - return 0; -} - -static void smb_direct_ib_client_remove(struct ib_device *ib_dev, - void *client_data) -{ - struct smb_direct_device *smb_dev, *tmp; - - write_lock(&smb_direct_device_lock); - list_for_each_entry_safe(smb_dev, tmp, &smb_direct_device_list, list) { - if (smb_dev->ib_dev == ib_dev) { - list_del(&smb_dev->list); - kfree(smb_dev); - break; - } - } - write_unlock(&smb_direct_device_lock); -} - -static struct ib_client smb_direct_ib_client = { - .name = "ksmbd_smb_direct_ib", - .add = smb_direct_ib_client_add, - .remove = smb_direct_ib_client_remove, -}; - -int ksmbd_rdma_init(void) -{ - int ret; - - smb_direct_listener.cm_id = NULL; - - ret = ib_register_client(&smb_direct_ib_client); - if (ret) { - pr_err("failed to ib_register_client\n"); - return ret; - } - - /* When a client is running out of send credits, the credits are - * granted by the server's sending a packet using this queue. - * This avoids the situation that a clients cannot send packets - * for lack of credits - */ - smb_direct_wq = alloc_workqueue("ksmbd-smb_direct-wq", - WQ_HIGHPRI | WQ_MEM_RECLAIM, 0); - if (!smb_direct_wq) - return -ENOMEM; - - ret = smb_direct_listen(smb_direct_port); - if (ret) { - destroy_workqueue(smb_direct_wq); - smb_direct_wq = NULL; - pr_err("Can't listen: %d\n", ret); - return ret; - } - - ksmbd_debug(RDMA, "init RDMA listener. cm_id=%p\n", - smb_direct_listener.cm_id); - return 0; -} - -void ksmbd_rdma_destroy(void) -{ - if (!smb_direct_listener.cm_id) - return; - - ib_unregister_client(&smb_direct_ib_client); - rdma_destroy_id(smb_direct_listener.cm_id); - - smb_direct_listener.cm_id = NULL; - - if (smb_direct_wq) { - destroy_workqueue(smb_direct_wq); - smb_direct_wq = NULL; - } -} - -bool ksmbd_rdma_capable_netdev(struct net_device *netdev) -{ - struct smb_direct_device *smb_dev; - int i; - bool rdma_capable = false; - - read_lock(&smb_direct_device_lock); - list_for_each_entry(smb_dev, &smb_direct_device_list, list) { - for (i = 0; i < smb_dev->ib_dev->phys_port_cnt; i++) { - struct net_device *ndev; - - ndev = smb_dev->ib_dev->ops.get_netdev(smb_dev->ib_dev, - i + 1); - if (!ndev) - continue; - - if (ndev == netdev) { - dev_put(ndev); - rdma_capable = true; - goto out; - } - dev_put(ndev); - } - } -out: - read_unlock(&smb_direct_device_lock); - - if (rdma_capable == false) { - struct ib_device *ibdev; - - ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_UNKNOWN); - if (ibdev) { - if (rdma_frwr_is_supported(&ibdev->attrs)) - rdma_capable = true; - ib_device_put(ibdev); - } - } - - return rdma_capable; -} - -static struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops = { - .prepare = smb_direct_prepare, - .disconnect = smb_direct_disconnect, - .shutdown = smb_direct_shutdown, - .writev = smb_direct_writev, - .read = smb_direct_read, - .rdma_read = smb_direct_rdma_read, - .rdma_write = smb_direct_rdma_write, -}; diff --git a/fs/ksmbd/transport_rdma.h b/fs/ksmbd/transport_rdma.h deleted file mode 100644 index 77aee4e5c9dc..000000000000 --- a/fs/ksmbd/transport_rdma.h +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2017, Microsoft Corporation. - * Copyright (C) 2018, LG Electronics. - */ - -#ifndef __KSMBD_TRANSPORT_RDMA_H__ -#define __KSMBD_TRANSPORT_RDMA_H__ - -#define SMBD_DEFAULT_IOSIZE (8 * 1024 * 1024) -#define SMBD_MIN_IOSIZE (512 * 1024) -#define SMBD_MAX_IOSIZE (16 * 1024 * 1024) - -/* SMB DIRECT negotiation request packet [MS-SMBD] 2.2.1 */ -struct smb_direct_negotiate_req { - __le16 min_version; - __le16 max_version; - __le16 reserved; - __le16 credits_requested; - __le32 preferred_send_size; - __le32 max_receive_size; - __le32 max_fragmented_size; -} __packed; - -/* SMB DIRECT negotiation response packet [MS-SMBD] 2.2.2 */ -struct smb_direct_negotiate_resp { - __le16 min_version; - __le16 max_version; - __le16 negotiated_version; - __le16 reserved; - __le16 credits_requested; - __le16 credits_granted; - __le32 status; - __le32 max_readwrite_size; - __le32 preferred_send_size; - __le32 max_receive_size; - __le32 max_fragmented_size; -} __packed; - -#define SMB_DIRECT_RESPONSE_REQUESTED 0x0001 - -/* SMB DIRECT data transfer packet with payload [MS-SMBD] 2.2.3 */ -struct smb_direct_data_transfer { - __le16 credits_requested; - __le16 credits_granted; - __le16 flags; - __le16 reserved; - __le32 remaining_data_length; - __le32 data_offset; - __le32 data_length; - __le32 padding; - __u8 buffer[]; -} __packed; - -#ifdef CONFIG_SMB_SERVER_SMBDIRECT -int ksmbd_rdma_init(void); -void ksmbd_rdma_destroy(void); -bool ksmbd_rdma_capable_netdev(struct net_device *netdev); -void init_smbd_max_io_size(unsigned int sz); -unsigned int get_smbd_max_read_write_size(void); -#else -static inline int ksmbd_rdma_init(void) { return 0; } -static inline int ksmbd_rdma_destroy(void) { return 0; } -static inline bool ksmbd_rdma_capable_netdev(struct net_device *netdev) { return false; } -static inline void init_smbd_max_io_size(unsigned int sz) { } -static inline unsigned int get_smbd_max_read_write_size(void) { return 0; } -#endif - -#endif /* __KSMBD_TRANSPORT_RDMA_H__ */ diff --git a/fs/ksmbd/transport_tcp.c b/fs/ksmbd/transport_tcp.c deleted file mode 100644 index eff7a1d793f0..000000000000 --- a/fs/ksmbd/transport_tcp.c +++ /dev/null @@ -1,649 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/freezer.h> - -#include "smb_common.h" -#include "server.h" -#include "auth.h" -#include "connection.h" -#include "transport_tcp.h" - -#define IFACE_STATE_DOWN BIT(0) -#define IFACE_STATE_CONFIGURED BIT(1) - -static atomic_t active_num_conn; - -struct interface { - struct task_struct *ksmbd_kthread; - struct socket *ksmbd_socket; - struct list_head entry; - char *name; - struct mutex sock_release_lock; - int state; -}; - -static LIST_HEAD(iface_list); - -static int bind_additional_ifaces; - -struct tcp_transport { - struct ksmbd_transport transport; - struct socket *sock; - struct kvec *iov; - unsigned int nr_iov; -}; - -static struct ksmbd_transport_ops ksmbd_tcp_transport_ops; - -static void tcp_stop_kthread(struct task_struct *kthread); -static struct interface *alloc_iface(char *ifname); - -#define KSMBD_TRANS(t) (&(t)->transport) -#define TCP_TRANS(t) ((struct tcp_transport *)container_of(t, \ - struct tcp_transport, transport)) - -static inline void ksmbd_tcp_nodelay(struct socket *sock) -{ - tcp_sock_set_nodelay(sock->sk); -} - -static inline void ksmbd_tcp_reuseaddr(struct socket *sock) -{ - sock_set_reuseaddr(sock->sk); -} - -static inline void ksmbd_tcp_rcv_timeout(struct socket *sock, s64 secs) -{ - lock_sock(sock->sk); - if (secs && secs < MAX_SCHEDULE_TIMEOUT / HZ - 1) - sock->sk->sk_rcvtimeo = secs * HZ; - else - sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; - release_sock(sock->sk); -} - -static inline void ksmbd_tcp_snd_timeout(struct socket *sock, s64 secs) -{ - sock_set_sndtimeo(sock->sk, secs); -} - -static struct tcp_transport *alloc_transport(struct socket *client_sk) -{ - struct tcp_transport *t; - struct ksmbd_conn *conn; - - t = kzalloc(sizeof(*t), GFP_KERNEL); - if (!t) - return NULL; - t->sock = client_sk; - - conn = ksmbd_conn_alloc(); - if (!conn) { - kfree(t); - return NULL; - } - - conn->transport = KSMBD_TRANS(t); - KSMBD_TRANS(t)->conn = conn; - KSMBD_TRANS(t)->ops = &ksmbd_tcp_transport_ops; - return t; -} - -static void free_transport(struct tcp_transport *t) -{ - kernel_sock_shutdown(t->sock, SHUT_RDWR); - sock_release(t->sock); - t->sock = NULL; - - ksmbd_conn_free(KSMBD_TRANS(t)->conn); - kfree(t->iov); - kfree(t); -} - -/** - * kvec_array_init() - initialize a IO vector segment - * @new: IO vector to be initialized - * @iov: base IO vector - * @nr_segs: number of segments in base iov - * @bytes: total iovec length so far for read - * - * Return: Number of IO segments - */ -static unsigned int kvec_array_init(struct kvec *new, struct kvec *iov, - unsigned int nr_segs, size_t bytes) -{ - size_t base = 0; - - while (bytes || !iov->iov_len) { - int copy = min(bytes, iov->iov_len); - - bytes -= copy; - base += copy; - if (iov->iov_len == base) { - iov++; - nr_segs--; - base = 0; - } - } - - memcpy(new, iov, sizeof(*iov) * nr_segs); - new->iov_base += base; - new->iov_len -= base; - return nr_segs; -} - -/** - * get_conn_iovec() - get connection iovec for reading from socket - * @t: TCP transport instance - * @nr_segs: number of segments in iov - * - * Return: return existing or newly allocate iovec - */ -static struct kvec *get_conn_iovec(struct tcp_transport *t, unsigned int nr_segs) -{ - struct kvec *new_iov; - - if (t->iov && nr_segs <= t->nr_iov) - return t->iov; - - /* not big enough -- allocate a new one and release the old */ - new_iov = kmalloc_array(nr_segs, sizeof(*new_iov), GFP_KERNEL); - if (new_iov) { - kfree(t->iov); - t->iov = new_iov; - t->nr_iov = nr_segs; - } - return new_iov; -} - -static unsigned short ksmbd_tcp_get_port(const struct sockaddr *sa) -{ - switch (sa->sa_family) { - case AF_INET: - return ntohs(((struct sockaddr_in *)sa)->sin_port); - case AF_INET6: - return ntohs(((struct sockaddr_in6 *)sa)->sin6_port); - } - return 0; -} - -/** - * ksmbd_tcp_new_connection() - create a new tcp session on mount - * @client_sk: socket associated with new connection - * - * whenever a new connection is requested, create a conn thread - * (session thread) to handle new incoming smb requests from the connection - * - * Return: 0 on success, otherwise error - */ -static int ksmbd_tcp_new_connection(struct socket *client_sk) -{ - struct sockaddr *csin; - int rc = 0; - struct tcp_transport *t; - - t = alloc_transport(client_sk); - if (!t) { - sock_release(client_sk); - return -ENOMEM; - } - - csin = KSMBD_TCP_PEER_SOCKADDR(KSMBD_TRANS(t)->conn); - if (kernel_getpeername(client_sk, csin) < 0) { - pr_err("client ip resolution failed\n"); - rc = -EINVAL; - goto out_error; - } - - KSMBD_TRANS(t)->handler = kthread_run(ksmbd_conn_handler_loop, - KSMBD_TRANS(t)->conn, - "ksmbd:%u", - ksmbd_tcp_get_port(csin)); - if (IS_ERR(KSMBD_TRANS(t)->handler)) { - pr_err("cannot start conn thread\n"); - rc = PTR_ERR(KSMBD_TRANS(t)->handler); - free_transport(t); - } - return rc; - -out_error: - free_transport(t); - return rc; -} - -/** - * ksmbd_kthread_fn() - listen to new SMB connections and callback server - * @p: arguments to forker thread - * - * Return: 0 on success, error number otherwise - */ -static int ksmbd_kthread_fn(void *p) -{ - struct socket *client_sk = NULL; - struct interface *iface = (struct interface *)p; - int ret; - - while (!kthread_should_stop()) { - mutex_lock(&iface->sock_release_lock); - if (!iface->ksmbd_socket) { - mutex_unlock(&iface->sock_release_lock); - break; - } - ret = kernel_accept(iface->ksmbd_socket, &client_sk, - SOCK_NONBLOCK); - mutex_unlock(&iface->sock_release_lock); - if (ret) { - if (ret == -EAGAIN) - /* check for new connections every 100 msecs */ - schedule_timeout_interruptible(HZ / 10); - continue; - } - - if (server_conf.max_connections && - atomic_inc_return(&active_num_conn) >= server_conf.max_connections) { - pr_info_ratelimited("Limit the maximum number of connections(%u)\n", - atomic_read(&active_num_conn)); - atomic_dec(&active_num_conn); - sock_release(client_sk); - continue; - } - - ksmbd_debug(CONN, "connect success: accepted new connection\n"); - client_sk->sk->sk_rcvtimeo = KSMBD_TCP_RECV_TIMEOUT; - client_sk->sk->sk_sndtimeo = KSMBD_TCP_SEND_TIMEOUT; - - ksmbd_tcp_new_connection(client_sk); - } - - ksmbd_debug(CONN, "releasing socket\n"); - return 0; -} - -/** - * ksmbd_tcp_run_kthread() - start forker thread - * @iface: pointer to struct interface - * - * start forker thread(ksmbd/0) at module init time to listen - * on port 445 for new SMB connection requests. It creates per connection - * server threads(ksmbd/x) - * - * Return: 0 on success or error number - */ -static int ksmbd_tcp_run_kthread(struct interface *iface) -{ - int rc; - struct task_struct *kthread; - - kthread = kthread_run(ksmbd_kthread_fn, (void *)iface, "ksmbd-%s", - iface->name); - if (IS_ERR(kthread)) { - rc = PTR_ERR(kthread); - return rc; - } - iface->ksmbd_kthread = kthread; - - return 0; -} - -/** - * ksmbd_tcp_readv() - read data from socket in given iovec - * @t: TCP transport instance - * @iov_orig: base IO vector - * @nr_segs: number of segments in base iov - * @to_read: number of bytes to read from socket - * @max_retries: maximum retry count - * - * Return: on success return number of bytes read from socket, - * otherwise return error number - */ -static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig, - unsigned int nr_segs, unsigned int to_read, - int max_retries) -{ - int length = 0; - int total_read; - unsigned int segs; - struct msghdr ksmbd_msg; - struct kvec *iov; - struct ksmbd_conn *conn = KSMBD_TRANS(t)->conn; - - iov = get_conn_iovec(t, nr_segs); - if (!iov) - return -ENOMEM; - - ksmbd_msg.msg_control = NULL; - ksmbd_msg.msg_controllen = 0; - - for (total_read = 0; to_read; total_read += length, to_read -= length) { - try_to_freeze(); - - if (!ksmbd_conn_alive(conn)) { - total_read = -ESHUTDOWN; - break; - } - segs = kvec_array_init(iov, iov_orig, nr_segs, total_read); - - length = kernel_recvmsg(t->sock, &ksmbd_msg, - iov, segs, to_read, 0); - - if (length == -EINTR) { - total_read = -ESHUTDOWN; - break; - } else if (ksmbd_conn_need_reconnect(conn)) { - total_read = -EAGAIN; - break; - } else if (length == -ERESTARTSYS || length == -EAGAIN) { - /* - * If max_retries is negative, Allow unlimited - * retries to keep connection with inactive sessions. - */ - if (max_retries == 0) { - total_read = length; - break; - } else if (max_retries > 0) { - max_retries--; - } - - usleep_range(1000, 2000); - length = 0; - continue; - } else if (length <= 0) { - total_read = length; - break; - } - } - return total_read; -} - -/** - * ksmbd_tcp_read() - read data from socket in given buffer - * @t: TCP transport instance - * @buf: buffer to store read data from socket - * @to_read: number of bytes to read from socket - * - * Return: on success return number of bytes read from socket, - * otherwise return error number - */ -static int ksmbd_tcp_read(struct ksmbd_transport *t, char *buf, - unsigned int to_read, int max_retries) -{ - struct kvec iov; - - iov.iov_base = buf; - iov.iov_len = to_read; - - return ksmbd_tcp_readv(TCP_TRANS(t), &iov, 1, to_read, max_retries); -} - -static int ksmbd_tcp_writev(struct ksmbd_transport *t, struct kvec *iov, - int nvecs, int size, bool need_invalidate, - unsigned int remote_key) - -{ - struct msghdr smb_msg = {.msg_flags = MSG_NOSIGNAL}; - - return kernel_sendmsg(TCP_TRANS(t)->sock, &smb_msg, iov, nvecs, size); -} - -static void ksmbd_tcp_disconnect(struct ksmbd_transport *t) -{ - free_transport(TCP_TRANS(t)); - if (server_conf.max_connections) - atomic_dec(&active_num_conn); -} - -static void tcp_destroy_socket(struct socket *ksmbd_socket) -{ - int ret; - - if (!ksmbd_socket) - return; - - /* set zero to timeout */ - ksmbd_tcp_rcv_timeout(ksmbd_socket, 0); - ksmbd_tcp_snd_timeout(ksmbd_socket, 0); - - ret = kernel_sock_shutdown(ksmbd_socket, SHUT_RDWR); - if (ret) - pr_err("Failed to shutdown socket: %d\n", ret); - sock_release(ksmbd_socket); -} - -/** - * create_socket - create socket for ksmbd/0 - * - * Return: 0 on success, error number otherwise - */ -static int create_socket(struct interface *iface) -{ - int ret; - struct sockaddr_in6 sin6; - struct sockaddr_in sin; - struct socket *ksmbd_socket; - bool ipv4 = false; - - ret = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &ksmbd_socket); - if (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, - &ksmbd_socket); - if (ret) { - pr_err("Can't create socket for ipv4: %d\n", ret); - goto out_clear; - } - - sin.sin_family = PF_INET; - sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_port = htons(server_conf.tcp_port); - ipv4 = true; - } else { - sin6.sin6_family = PF_INET6; - sin6.sin6_addr = in6addr_any; - sin6.sin6_port = htons(server_conf.tcp_port); - } - - ksmbd_tcp_nodelay(ksmbd_socket); - ksmbd_tcp_reuseaddr(ksmbd_socket); - - ret = sock_setsockopt(ksmbd_socket, - SOL_SOCKET, - SO_BINDTODEVICE, - KERNEL_SOCKPTR(iface->name), - strlen(iface->name)); - if (ret != -ENODEV && ret < 0) { - pr_err("Failed to set SO_BINDTODEVICE: %d\n", ret); - goto out_error; - } - - if (ipv4) - ret = kernel_bind(ksmbd_socket, (struct sockaddr *)&sin, - sizeof(sin)); - else - ret = kernel_bind(ksmbd_socket, (struct sockaddr *)&sin6, - sizeof(sin6)); - if (ret) { - pr_err("Failed to bind socket: %d\n", ret); - goto out_error; - } - - ksmbd_socket->sk->sk_rcvtimeo = KSMBD_TCP_RECV_TIMEOUT; - ksmbd_socket->sk->sk_sndtimeo = KSMBD_TCP_SEND_TIMEOUT; - - ret = kernel_listen(ksmbd_socket, KSMBD_SOCKET_BACKLOG); - if (ret) { - pr_err("Port listen() error: %d\n", ret); - goto out_error; - } - - iface->ksmbd_socket = ksmbd_socket; - ret = ksmbd_tcp_run_kthread(iface); - if (ret) { - pr_err("Can't start ksmbd main kthread: %d\n", ret); - goto out_error; - } - iface->state = IFACE_STATE_CONFIGURED; - - return 0; - -out_error: - tcp_destroy_socket(ksmbd_socket); -out_clear: - iface->ksmbd_socket = NULL; - return ret; -} - -static int ksmbd_netdev_event(struct notifier_block *nb, unsigned long event, - void *ptr) -{ - struct net_device *netdev = netdev_notifier_info_to_dev(ptr); - struct interface *iface; - int ret, found = 0; - - switch (event) { - case NETDEV_UP: - if (netif_is_bridge_port(netdev)) - return NOTIFY_OK; - - list_for_each_entry(iface, &iface_list, entry) { - if (!strcmp(iface->name, netdev->name)) { - found = 1; - if (iface->state != IFACE_STATE_DOWN) - break; - ret = create_socket(iface); - if (ret) - return NOTIFY_OK; - break; - } - } - if (!found && bind_additional_ifaces) { - iface = alloc_iface(kstrdup(netdev->name, GFP_KERNEL)); - if (!iface) - return NOTIFY_OK; - ret = create_socket(iface); - if (ret) - break; - } - break; - case NETDEV_DOWN: - list_for_each_entry(iface, &iface_list, entry) { - if (!strcmp(iface->name, netdev->name) && - iface->state == IFACE_STATE_CONFIGURED) { - tcp_stop_kthread(iface->ksmbd_kthread); - iface->ksmbd_kthread = NULL; - mutex_lock(&iface->sock_release_lock); - tcp_destroy_socket(iface->ksmbd_socket); - iface->ksmbd_socket = NULL; - mutex_unlock(&iface->sock_release_lock); - - iface->state = IFACE_STATE_DOWN; - break; - } - } - break; - } - - return NOTIFY_DONE; -} - -static struct notifier_block ksmbd_netdev_notifier = { - .notifier_call = ksmbd_netdev_event, -}; - -int ksmbd_tcp_init(void) -{ - register_netdevice_notifier(&ksmbd_netdev_notifier); - - return 0; -} - -static void tcp_stop_kthread(struct task_struct *kthread) -{ - int ret; - - if (!kthread) - return; - - ret = kthread_stop(kthread); - if (ret) - pr_err("failed to stop forker thread\n"); -} - -void ksmbd_tcp_destroy(void) -{ - struct interface *iface, *tmp; - - unregister_netdevice_notifier(&ksmbd_netdev_notifier); - - list_for_each_entry_safe(iface, tmp, &iface_list, entry) { - list_del(&iface->entry); - kfree(iface->name); - kfree(iface); - } -} - -static struct interface *alloc_iface(char *ifname) -{ - struct interface *iface; - - if (!ifname) - return NULL; - - iface = kzalloc(sizeof(struct interface), GFP_KERNEL); - if (!iface) { - kfree(ifname); - return NULL; - } - - iface->name = ifname; - iface->state = IFACE_STATE_DOWN; - list_add(&iface->entry, &iface_list); - mutex_init(&iface->sock_release_lock); - return iface; -} - -int ksmbd_tcp_set_interfaces(char *ifc_list, int ifc_list_sz) -{ - int sz = 0; - - if (!ifc_list_sz) { - struct net_device *netdev; - - rtnl_lock(); - for_each_netdev(&init_net, netdev) { - if (netif_is_bridge_port(netdev)) - continue; - if (!alloc_iface(kstrdup(netdev->name, GFP_KERNEL))) - return -ENOMEM; - } - rtnl_unlock(); - bind_additional_ifaces = 1; - return 0; - } - - while (ifc_list_sz > 0) { - if (!alloc_iface(kstrdup(ifc_list, GFP_KERNEL))) - return -ENOMEM; - - sz = strlen(ifc_list); - if (!sz) - break; - - ifc_list += sz + 1; - ifc_list_sz -= (sz + 1); - } - - bind_additional_ifaces = 0; - - return 0; -} - -static struct ksmbd_transport_ops ksmbd_tcp_transport_ops = { - .read = ksmbd_tcp_read, - .writev = ksmbd_tcp_writev, - .disconnect = ksmbd_tcp_disconnect, -}; diff --git a/fs/ksmbd/transport_tcp.h b/fs/ksmbd/transport_tcp.h deleted file mode 100644 index e338bebe322f..000000000000 --- a/fs/ksmbd/transport_tcp.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __KSMBD_TRANSPORT_TCP_H__ -#define __KSMBD_TRANSPORT_TCP_H__ - -int ksmbd_tcp_set_interfaces(char *ifc_list, int ifc_list_sz); -int ksmbd_tcp_init(void); -void ksmbd_tcp_destroy(void); - -#endif /* __KSMBD_TRANSPORT_TCP_H__ */ diff --git a/fs/ksmbd/unicode.c b/fs/ksmbd/unicode.c deleted file mode 100644 index a0db699ddafd..000000000000 --- a/fs/ksmbd/unicode.c +++ /dev/null @@ -1,384 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Some of the source code in this file came from fs/cifs/cifs_unicode.c - * - * Copyright (c) International Business Machines Corp., 2000,2009 - * Modified by Steve French (sfrench@us.ibm.com) - * Modified by Namjae Jeon (linkinjeon@kernel.org) - */ -#include <linux/fs.h> -#include <linux/slab.h> -#include <asm/unaligned.h> -#include "glob.h" -#include "unicode.h" -#include "uniupr.h" -#include "smb_common.h" - -/* - * smb_utf16_bytes() - how long will a string be after conversion? - * @from: pointer to input string - * @maxbytes: don't go past this many bytes of input string - * @codepage: destination codepage - * - * Walk a utf16le string and return the number of bytes that the string will - * be after being converted to the given charset, not including any null - * termination required. Don't walk past maxbytes in the source buffer. - * - * Return: string length after conversion - */ -static int smb_utf16_bytes(const __le16 *from, int maxbytes, - const struct nls_table *codepage) -{ - int i; - int charlen, outlen = 0; - int maxwords = maxbytes / 2; - char tmp[NLS_MAX_CHARSET_SIZE]; - __u16 ftmp; - - for (i = 0; i < maxwords; i++) { - ftmp = get_unaligned_le16(&from[i]); - if (ftmp == 0) - break; - - charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE); - if (charlen > 0) - outlen += charlen; - else - outlen++; - } - - return outlen; -} - -/* - * cifs_mapchar() - convert a host-endian char to proper char in codepage - * @target: where converted character should be copied - * @src_char: 2 byte host-endian source character - * @cp: codepage to which character should be converted - * @mapchar: should character be mapped according to mapchars mount option? - * - * This function handles the conversion of a single character. It is the - * responsibility of the caller to ensure that the target buffer is large - * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). - * - * Return: string length after conversion - */ -static int -cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, - bool mapchar) -{ - int len = 1; - - if (!mapchar) - goto cp_convert; - - /* - * BB: Cannot handle remapping UNI_SLASH until all the calls to - * build_path_from_dentry are modified, as they use slash as - * separator. - */ - switch (src_char) { - case UNI_COLON: - *target = ':'; - break; - case UNI_ASTERISK: - *target = '*'; - break; - case UNI_QUESTION: - *target = '?'; - break; - case UNI_PIPE: - *target = '|'; - break; - case UNI_GRTRTHAN: - *target = '>'; - break; - case UNI_LESSTHAN: - *target = '<'; - break; - default: - goto cp_convert; - } - -out: - return len; - -cp_convert: - len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); - if (len <= 0) { - *target = '?'; - len = 1; - } - - goto out; -} - -/* - * is_char_allowed() - check for valid character - * @ch: input character to be checked - * - * Return: 1 if char is allowed, otherwise 0 - */ -static inline int is_char_allowed(char *ch) -{ - /* check for control chars, wildcards etc. */ - if (!(*ch & 0x80) && - (*ch <= 0x1f || - *ch == '?' || *ch == '"' || *ch == '<' || - *ch == '>' || *ch == '|')) - return 0; - - return 1; -} - -/* - * smb_from_utf16() - convert utf16le string to local charset - * @to: destination buffer - * @from: source buffer - * @tolen: destination buffer size (in bytes) - * @fromlen: source buffer size (in bytes) - * @codepage: codepage to which characters should be converted - * @mapchar: should characters be remapped according to the mapchars option? - * - * Convert a little-endian utf16le string (as sent by the server) to a string - * in the provided codepage. The tolen and fromlen parameters are to ensure - * that the code doesn't walk off of the end of the buffer (which is always - * a danger if the alignment of the source buffer is off). The destination - * string is always properly null terminated and fits in the destination - * buffer. Returns the length of the destination string in bytes (including - * null terminator). - * - * Note that some windows versions actually send multiword UTF-16 characters - * instead of straight UTF16-2. The linux nls routines however aren't able to - * deal with those characters properly. In the event that we get some of - * those characters, they won't be translated properly. - * - * Return: string length after conversion - */ -static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, - const struct nls_table *codepage, bool mapchar) -{ - int i, charlen, safelen; - int outlen = 0; - int nullsize = nls_nullsize(codepage); - int fromwords = fromlen / 2; - char tmp[NLS_MAX_CHARSET_SIZE]; - __u16 ftmp; - - /* - * because the chars can be of varying widths, we need to take care - * not to overflow the destination buffer when we get close to the - * end of it. Until we get to this offset, we don't need to check - * for overflow however. - */ - safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); - - for (i = 0; i < fromwords; i++) { - ftmp = get_unaligned_le16(&from[i]); - if (ftmp == 0) - break; - - /* - * check to see if converting this character might make the - * conversion bleed into the null terminator - */ - if (outlen >= safelen) { - charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar); - if ((outlen + charlen) > (tolen - nullsize)) - break; - } - - /* put converted char into 'to' buffer */ - charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar); - outlen += charlen; - } - - /* properly null-terminate string */ - for (i = 0; i < nullsize; i++) - to[outlen++] = 0; - - return outlen; -} - -/* - * smb_strtoUTF16() - Convert character string to unicode string - * @to: destination buffer - * @from: source buffer - * @len: destination buffer size (in bytes) - * @codepage: codepage to which characters should be converted - * - * Return: string length after conversion - */ -int smb_strtoUTF16(__le16 *to, const char *from, int len, - const struct nls_table *codepage) -{ - int charlen; - int i; - wchar_t wchar_to; /* needed to quiet sparse */ - - /* special case for utf8 to handle no plane0 chars */ - if (!strcmp(codepage->charset, "utf8")) { - /* - * convert utf8 -> utf16, we assume we have enough space - * as caller should have assumed conversion does not overflow - * in destination len is length in wchar_t units (16bits) - */ - i = utf8s_to_utf16s(from, len, UTF16_LITTLE_ENDIAN, - (wchar_t *)to, len); - - /* if success terminate and exit */ - if (i >= 0) - goto success; - /* - * if fails fall back to UCS encoding as this - * function should not return negative values - * currently can fail only if source contains - * invalid encoded characters - */ - } - - for (i = 0; len > 0 && *from; i++, from += charlen, len -= charlen) { - charlen = codepage->char2uni(from, len, &wchar_to); - if (charlen < 1) { - /* A question mark */ - wchar_to = 0x003f; - charlen = 1; - } - put_unaligned_le16(wchar_to, &to[i]); - } - -success: - put_unaligned_le16(0, &to[i]); - return i; -} - -/* - * smb_strndup_from_utf16() - copy a string from wire format to the local - * codepage - * @src: source string - * @maxlen: don't walk past this many bytes in the source string - * @is_unicode: is this a unicode string? - * @codepage: destination codepage - * - * Take a string given by the server, convert it to the local codepage and - * put it in a new buffer. Returns a pointer to the new string or NULL on - * error. - * - * Return: destination string buffer or error ptr - */ -char *smb_strndup_from_utf16(const char *src, const int maxlen, - const bool is_unicode, - const struct nls_table *codepage) -{ - int len, ret; - char *dst; - - if (is_unicode) { - len = smb_utf16_bytes((__le16 *)src, maxlen, codepage); - len += nls_nullsize(codepage); - dst = kmalloc(len, GFP_KERNEL); - if (!dst) - return ERR_PTR(-ENOMEM); - ret = smb_from_utf16(dst, (__le16 *)src, len, maxlen, codepage, - false); - if (ret < 0) { - kfree(dst); - return ERR_PTR(-EINVAL); - } - } else { - len = strnlen(src, maxlen); - len++; - dst = kmalloc(len, GFP_KERNEL); - if (!dst) - return ERR_PTR(-ENOMEM); - strscpy(dst, src, len); - } - - return dst; -} - -/* - * Convert 16 bit Unicode pathname to wire format from string in current code - * page. Conversion may involve remapping up the six characters that are - * only legal in POSIX-like OS (if they are present in the string). Path - * names are little endian 16 bit Unicode on the wire - */ -/* - * smbConvertToUTF16() - convert string from local charset to utf16 - * @target: destination buffer - * @source: source buffer - * @srclen: source buffer size (in bytes) - * @cp: codepage to which characters should be converted - * @mapchar: should characters be remapped according to the mapchars option? - * - * Convert 16 bit Unicode pathname to wire format from string in current code - * page. Conversion may involve remapping up the six characters that are - * only legal in POSIX-like OS (if they are present in the string). Path - * names are little endian 16 bit Unicode on the wire - * - * Return: char length after conversion - */ -int smbConvertToUTF16(__le16 *target, const char *source, int srclen, - const struct nls_table *cp, int mapchars) -{ - int i, j, charlen; - char src_char; - __le16 dst_char; - wchar_t tmp; - - if (!mapchars) - return smb_strtoUTF16(target, source, srclen, cp); - - for (i = 0, j = 0; i < srclen; j++) { - src_char = source[i]; - charlen = 1; - switch (src_char) { - case 0: - put_unaligned(0, &target[j]); - return j; - case ':': - dst_char = cpu_to_le16(UNI_COLON); - break; - case '*': - dst_char = cpu_to_le16(UNI_ASTERISK); - break; - case '?': - dst_char = cpu_to_le16(UNI_QUESTION); - break; - case '<': - dst_char = cpu_to_le16(UNI_LESSTHAN); - break; - case '>': - dst_char = cpu_to_le16(UNI_GRTRTHAN); - break; - case '|': - dst_char = cpu_to_le16(UNI_PIPE); - break; - /* - * FIXME: We can not handle remapping backslash (UNI_SLASH) - * until all the calls to build_path_from_dentry are modified, - * as they use backslash as separator. - */ - default: - charlen = cp->char2uni(source + i, srclen - i, &tmp); - dst_char = cpu_to_le16(tmp); - - /* - * if no match, use question mark, which at least in - * some cases serves as wild card - */ - if (charlen < 1) { - dst_char = cpu_to_le16(0x003f); - charlen = 1; - } - } - /* - * character may take more than one byte in the source string, - * but will take exactly two bytes in the target string - */ - i += charlen; - put_unaligned(dst_char, &target[j]); - } - - return j; -} diff --git a/fs/ksmbd/unicode.h b/fs/ksmbd/unicode.h deleted file mode 100644 index 076f6034a789..000000000000 --- a/fs/ksmbd/unicode.h +++ /dev/null @@ -1,358 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Some of the source code in this file came from fs/cifs/cifs_unicode.c - * cifs_unicode: Unicode kernel case support - * - * Function: - * Convert a unicode character to upper or lower case using - * compressed tables. - * - * Copyright (c) International Business Machines Corp., 2000,2009 - * - * - * Notes: - * These APIs are based on the C library functions. The semantics - * should match the C functions but with expanded size operands. - * - * The upper/lower functions are based on a table created by mkupr. - * This is a compressed table of upper and lower case conversion. - * - */ -#ifndef _CIFS_UNICODE_H -#define _CIFS_UNICODE_H - -#include <asm/byteorder.h> -#include <linux/types.h> -#include <linux/nls.h> -#include <linux/unicode.h> - -#define UNIUPR_NOLOWER /* Example to not expand lower case tables */ - -/* - * Windows maps these to the user defined 16 bit Unicode range since they are - * reserved symbols (along with \ and /), otherwise illegal to store - * in filenames in NTFS - */ -#define UNI_ASTERISK ((__u16)('*' + 0xF000)) -#define UNI_QUESTION ((__u16)('?' + 0xF000)) -#define UNI_COLON ((__u16)(':' + 0xF000)) -#define UNI_GRTRTHAN ((__u16)('>' + 0xF000)) -#define UNI_LESSTHAN ((__u16)('<' + 0xF000)) -#define UNI_PIPE ((__u16)('|' + 0xF000)) -#define UNI_SLASH ((__u16)('\\' + 0xF000)) - -/* Just define what we want from uniupr.h. We don't want to define the tables - * in each source file. - */ -#ifndef UNICASERANGE_DEFINED -struct UniCaseRange { - wchar_t start; - wchar_t end; - signed char *table; -}; -#endif /* UNICASERANGE_DEFINED */ - -#ifndef UNIUPR_NOUPPER -extern signed char SmbUniUpperTable[512]; -extern const struct UniCaseRange SmbUniUpperRange[]; -#endif /* UNIUPR_NOUPPER */ - -#ifndef UNIUPR_NOLOWER -extern signed char CifsUniLowerTable[512]; -extern const struct UniCaseRange CifsUniLowerRange[]; -#endif /* UNIUPR_NOLOWER */ - -#ifdef __KERNEL__ -int smb_strtoUTF16(__le16 *to, const char *from, int len, - const struct nls_table *codepage); -char *smb_strndup_from_utf16(const char *src, const int maxlen, - const bool is_unicode, - const struct nls_table *codepage); -int smbConvertToUTF16(__le16 *target, const char *source, int srclen, - const struct nls_table *cp, int mapchars); -char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename); -#endif - -/* - * UniStrcat: Concatenate the second string to the first - * - * Returns: - * Address of the first string - */ -static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2) -{ - wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */ - - while (*ucs1++) - /*NULL*/; /* To end of first string */ - ucs1--; /* Return to the null */ - while ((*ucs1++ = *ucs2++)) - /*NULL*/; /* copy string 2 over */ - return anchor; -} - -/* - * UniStrchr: Find a character in a string - * - * Returns: - * Address of first occurrence of character in string - * or NULL if the character is not in the string - */ -static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc) -{ - while ((*ucs != uc) && *ucs) - ucs++; - - if (*ucs == uc) - return (wchar_t *)ucs; - return NULL; -} - -/* - * UniStrcmp: Compare two strings - * - * Returns: - * < 0: First string is less than second - * = 0: Strings are equal - * > 0: First string is greater than second - */ -static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2) -{ - while ((*ucs1 == *ucs2) && *ucs1) { - ucs1++; - ucs2++; - } - return (int)*ucs1 - (int)*ucs2; -} - -/* - * UniStrcpy: Copy a string - */ -static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2) -{ - wchar_t *anchor = ucs1; /* save the start of result string */ - - while ((*ucs1++ = *ucs2++)) - /*NULL*/; - return anchor; -} - -/* - * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes) - */ -static inline size_t UniStrlen(const wchar_t *ucs1) -{ - int i = 0; - - while (*ucs1++) - i++; - return i; -} - -/* - * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a - * string (length limited) - */ -static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen) -{ - int i = 0; - - while (*ucs1++) { - i++; - if (i >= maxlen) - break; - } - return i; -} - -/* - * UniStrncat: Concatenate length limited string - */ -static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n) -{ - wchar_t *anchor = ucs1; /* save pointer to string 1 */ - - while (*ucs1++) - /*NULL*/; - ucs1--; /* point to null terminator of s1 */ - while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */ - ucs1++; - ucs2++; - } - *ucs1 = 0; /* Null terminate the result */ - return anchor; -} - -/* - * UniStrncmp: Compare length limited string - */ -static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n) -{ - if (!n) - return 0; /* Null strings are equal */ - while ((*ucs1 == *ucs2) && *ucs1 && --n) { - ucs1++; - ucs2++; - } - return (int)*ucs1 - (int)*ucs2; -} - -/* - * UniStrncmp_le: Compare length limited string - native to little-endian - */ -static inline int -UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n) -{ - if (!n) - return 0; /* Null strings are equal */ - while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) { - ucs1++; - ucs2++; - } - return (int)*ucs1 - (int)__le16_to_cpu(*ucs2); -} - -/* - * UniStrncpy: Copy length limited string with pad - */ -static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n) -{ - wchar_t *anchor = ucs1; - - while (n-- && *ucs2) /* Copy the strings */ - *ucs1++ = *ucs2++; - - n++; - while (n--) /* Pad with nulls */ - *ucs1++ = 0; - return anchor; -} - -/* - * UniStrncpy_le: Copy length limited string with pad to little-endian - */ -static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n) -{ - wchar_t *anchor = ucs1; - - while (n-- && *ucs2) /* Copy the strings */ - *ucs1++ = __le16_to_cpu(*ucs2++); - - n++; - while (n--) /* Pad with nulls */ - *ucs1++ = 0; - return anchor; -} - -/* - * UniStrstr: Find a string in a string - * - * Returns: - * Address of first match found - * NULL if no matching string is found - */ -static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2) -{ - const wchar_t *anchor1 = ucs1; - const wchar_t *anchor2 = ucs2; - - while (*ucs1) { - if (*ucs1 == *ucs2) { - /* Partial match found */ - ucs1++; - ucs2++; - } else { - if (!*ucs2) /* Match found */ - return (wchar_t *)anchor1; - ucs1 = ++anchor1; /* No match */ - ucs2 = anchor2; - } - } - - if (!*ucs2) /* Both end together */ - return (wchar_t *)anchor1; /* Match found */ - return NULL; /* No match */ -} - -#ifndef UNIUPR_NOUPPER -/* - * UniToupper: Convert a unicode character to upper case - */ -static inline wchar_t UniToupper(register wchar_t uc) -{ - register const struct UniCaseRange *rp; - - if (uc < sizeof(SmbUniUpperTable)) { - /* Latin characters */ - return uc + SmbUniUpperTable[uc]; /* Use base tables */ - } - - rp = SmbUniUpperRange; /* Use range tables */ - while (rp->start) { - if (uc < rp->start) /* Before start of range */ - return uc; /* Uppercase = input */ - if (uc <= rp->end) /* In range */ - return uc + rp->table[uc - rp->start]; - rp++; /* Try next range */ - } - return uc; /* Past last range */ -} - -/* - * UniStrupr: Upper case a unicode string - */ -static inline __le16 *UniStrupr(register __le16 *upin) -{ - register __le16 *up; - - up = upin; - while (*up) { /* For all characters */ - *up = cpu_to_le16(UniToupper(le16_to_cpu(*up))); - up++; - } - return upin; /* Return input pointer */ -} -#endif /* UNIUPR_NOUPPER */ - -#ifndef UNIUPR_NOLOWER -/* - * UniTolower: Convert a unicode character to lower case - */ -static inline wchar_t UniTolower(register wchar_t uc) -{ - register const struct UniCaseRange *rp; - - if (uc < sizeof(CifsUniLowerTable)) { - /* Latin characters */ - return uc + CifsUniLowerTable[uc]; /* Use base tables */ - } - - rp = CifsUniLowerRange; /* Use range tables */ - while (rp->start) { - if (uc < rp->start) /* Before start of range */ - return uc; /* Uppercase = input */ - if (uc <= rp->end) /* In range */ - return uc + rp->table[uc - rp->start]; - rp++; /* Try next range */ - } - return uc; /* Past last range */ -} - -/* - * UniStrlwr: Lower case a unicode string - */ -static inline wchar_t *UniStrlwr(register wchar_t *upin) -{ - register wchar_t *up; - - up = upin; - while (*up) { /* For all characters */ - *up = UniTolower(*up); - up++; - } - return upin; /* Return input pointer */ -} - -#endif - -#endif /* _CIFS_UNICODE_H */ diff --git a/fs/ksmbd/uniupr.h b/fs/ksmbd/uniupr.h deleted file mode 100644 index 26583b776897..000000000000 --- a/fs/ksmbd/uniupr.h +++ /dev/null @@ -1,268 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Some of the source code in this file came from fs/cifs/uniupr.h - * Copyright (c) International Business Machines Corp., 2000,2002 - * - * uniupr.h - Unicode compressed case ranges - * - */ -#ifndef __KSMBD_UNIUPR_H -#define __KSMBD_UNIUPR_H - -#ifndef UNIUPR_NOUPPER -/* - * Latin upper case - */ -signed char SmbUniUpperTable[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */ - 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, /* 060-06f */ - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, 0, 0, 0, 0, 0, /* 070-07f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */ - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, /* 0e0-0ef */ - -32, -32, -32, -32, -32, -32, -32, 0, -32, -32, - -32, -32, -32, -32, -32, 121, /* 0f0-0ff */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */ - 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */ - -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */ - 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */ - 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */ - 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */ - -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */ - 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */ - -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */ - 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */ -}; - -/* Upper case range - Greek */ -static signed char UniCaseRangeU03a0[47] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37, /* 3a0-3af */ - 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, /* 3b0-3bf */ - -32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64, - -63, -63, -}; - -/* Upper case range - Cyrillic */ -static signed char UniCaseRangeU0430[48] = { - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, /* 430-43f */ - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, /* 440-44f */ - 0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, 0, -80, -80, /* 450-45f */ -}; - -/* Upper case range - Extended cyrillic */ -static signed char UniCaseRangeU0490[61] = { - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */ - 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, -}; - -/* Upper case range - Extended latin and greek */ -static signed char UniCaseRangeU1e00[509] = { - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */ - 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1, /* 1e90-1e9f */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */ - 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */ - 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */ - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */ - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */ - 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */ - 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */ - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */ - 74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, - 126, 126, 0, 0, /* 1f70-1f7f */ - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */ - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */ - 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */ - 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */ - 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */ - 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */ - 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */ - 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -/* Upper case range - Wide latin */ -static signed char UniCaseRangeUff40[27] = { - 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, /* ff40-ff4f */ - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -}; - -/* - * Upper Case Range - */ -const struct UniCaseRange SmbUniUpperRange[] = { - {0x03a0, 0x03ce, UniCaseRangeU03a0}, - {0x0430, 0x045f, UniCaseRangeU0430}, - {0x0490, 0x04cc, UniCaseRangeU0490}, - {0x1e00, 0x1ffc, UniCaseRangeU1e00}, - {0xff40, 0xff5a, UniCaseRangeUff40}, - {0} -}; -#endif - -#ifndef UNIUPR_NOLOWER -/* - * Latin lower case - */ -signed char CifsUniLowerTable[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ - 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, /* 040-04f */ - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, - 0, 0, 0, /* 050-05f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, /* 0c0-0cf */ - 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, - 32, 32, 32, 0, /* 0d0-0df */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */ - 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */ - 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */ - 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, - 0, /* 170-17f */ - 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, - 0, /* 180-18f */ - 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */ - 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */ - 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */ - 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */ - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */ - 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */ -}; - -/* Lower case range - Greek */ -static signed char UniCaseRangeL0380[44] = { - 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */ - 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, /* 390-39f */ - 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, -}; - -/* Lower case range - Cyrillic */ -static signed char UniCaseRangeL0400[48] = { - 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 0, 80, 80, /* 400-40f */ - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, /* 410-41f */ - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, /* 420-42f */ -}; - -/* Lower case range - Extended cyrillic */ -static signed char UniCaseRangeL0490[60] = { - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */ - 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, -}; - -/* Lower case range - Extended latin and greek */ -static signed char UniCaseRangeL1e00[504] = { - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */ - 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */ - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */ - 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, - 0, 0, /* 1fc0-1fcf */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */ - 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, - 0, 0, /* 1fe0-1fef */ - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -/* Lower case range - Wide latin */ -static signed char UniCaseRangeLff20[27] = { - 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, /* ff20-ff2f */ - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, -}; - -/* - * Lower Case Range - */ -const struct UniCaseRange CifsUniLowerRange[] = { - {0x0380, 0x03ab, UniCaseRangeL0380}, - {0x0400, 0x042f, UniCaseRangeL0400}, - {0x0490, 0x04cb, UniCaseRangeL0490}, - {0x1e00, 0x1ff7, UniCaseRangeL1e00}, - {0xff20, 0xff3a, UniCaseRangeLff20}, - {0} -}; -#endif - -#endif /* __KSMBD_UNIUPR_H */ diff --git a/fs/ksmbd/vfs.c b/fs/ksmbd/vfs.c deleted file mode 100644 index 94b8ed4ef870..000000000000 --- a/fs/ksmbd/vfs.c +++ /dev/null @@ -1,1911 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/uaccess.h> -#include <linux/backing-dev.h> -#include <linux/writeback.h> -#include <linux/xattr.h> -#include <linux/falloc.h> -#include <linux/fsnotify.h> -#include <linux/dcache.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/sched/xacct.h> -#include <linux/crc32c.h> - -#include "../internal.h" /* for vfs_path_lookup */ - -#include "glob.h" -#include "oplock.h" -#include "connection.h" -#include "vfs.h" -#include "vfs_cache.h" -#include "smbacl.h" -#include "ndr.h" -#include "auth.h" -#include "misc.h" - -#include "smb_common.h" -#include "mgmt/share_config.h" -#include "mgmt/tree_connect.h" -#include "mgmt/user_session.h" -#include "mgmt/user_config.h" - -static char *extract_last_component(char *path) -{ - char *p = strrchr(path, '/'); - - if (p && p[1] != '\0') { - *p = '\0'; - p++; - } else { - p = NULL; - } - return p; -} - -static void ksmbd_vfs_inherit_owner(struct ksmbd_work *work, - struct inode *parent_inode, - struct inode *inode) -{ - if (!test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_INHERIT_OWNER)) - return; - - i_uid_write(inode, i_uid_read(parent_inode)); -} - -/** - * ksmbd_vfs_lock_parent() - lock parent dentry if it is stable - * - * the parent dentry got by dget_parent or @parent could be - * unstable, we try to lock a parent inode and lookup the - * child dentry again. - * - * the reference count of @parent isn't incremented. - */ -int ksmbd_vfs_lock_parent(struct user_namespace *user_ns, struct dentry *parent, - struct dentry *child) -{ - struct dentry *dentry; - int ret = 0; - - inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); - dentry = lookup_one(user_ns, child->d_name.name, parent, - child->d_name.len); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto out_err; - } - - if (dentry != child) { - ret = -ESTALE; - dput(dentry); - goto out_err; - } - - dput(dentry); - return 0; -out_err: - inode_unlock(d_inode(parent)); - return ret; -} - -int ksmbd_vfs_may_delete(struct user_namespace *user_ns, - struct dentry *dentry) -{ - struct dentry *parent; - int ret; - - parent = dget_parent(dentry); - ret = ksmbd_vfs_lock_parent(user_ns, parent, dentry); - if (ret) { - dput(parent); - return ret; - } - - ret = inode_permission(user_ns, d_inode(parent), - MAY_EXEC | MAY_WRITE); - - inode_unlock(d_inode(parent)); - dput(parent); - return ret; -} - -int ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns, - struct dentry *dentry, __le32 *daccess) -{ - struct dentry *parent; - int ret = 0; - - *daccess = cpu_to_le32(FILE_READ_ATTRIBUTES | READ_CONTROL); - - if (!inode_permission(user_ns, d_inode(dentry), MAY_OPEN | MAY_WRITE)) - *daccess |= cpu_to_le32(WRITE_DAC | WRITE_OWNER | SYNCHRONIZE | - FILE_WRITE_DATA | FILE_APPEND_DATA | - FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | - FILE_DELETE_CHILD); - - if (!inode_permission(user_ns, d_inode(dentry), MAY_OPEN | MAY_READ)) - *daccess |= FILE_READ_DATA_LE | FILE_READ_EA_LE; - - if (!inode_permission(user_ns, d_inode(dentry), MAY_OPEN | MAY_EXEC)) - *daccess |= FILE_EXECUTE_LE; - - parent = dget_parent(dentry); - ret = ksmbd_vfs_lock_parent(user_ns, parent, dentry); - if (ret) { - dput(parent); - return ret; - } - - if (!inode_permission(user_ns, d_inode(parent), MAY_EXEC | MAY_WRITE)) - *daccess |= FILE_DELETE_LE; - - inode_unlock(d_inode(parent)); - dput(parent); - return ret; -} - -/** - * ksmbd_vfs_create() - vfs helper for smb create file - * @work: work - * @name: file name that is relative to share - * @mode: file create mode - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode) -{ - struct path path; - struct dentry *dentry; - int err; - - dentry = ksmbd_vfs_kern_path_create(work, name, - LOOKUP_NO_SYMLINKS, &path); - if (IS_ERR(dentry)) { - err = PTR_ERR(dentry); - if (err != -ENOENT) - pr_err("path create failed for %s, err %d\n", - name, err); - return err; - } - - mode |= S_IFREG; - err = vfs_create(mnt_user_ns(path.mnt), d_inode(path.dentry), - dentry, mode, true); - if (!err) { - ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), - d_inode(dentry)); - } else { - pr_err("File(%s): creation failed (err:%d)\n", name, err); - } - done_path_create(&path, dentry); - return err; -} - -/** - * ksmbd_vfs_mkdir() - vfs helper for smb create directory - * @work: work - * @name: directory name that is relative to share - * @mode: directory create mode - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode) -{ - struct user_namespace *user_ns; - struct path path; - struct dentry *dentry; - int err; - - dentry = ksmbd_vfs_kern_path_create(work, name, - LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY, - &path); - if (IS_ERR(dentry)) { - err = PTR_ERR(dentry); - if (err != -EEXIST) - ksmbd_debug(VFS, "path create failed for %s, err %d\n", - name, err); - return err; - } - - user_ns = mnt_user_ns(path.mnt); - mode |= S_IFDIR; - err = vfs_mkdir(user_ns, d_inode(path.dentry), dentry, mode); - if (err) { - goto out; - } else if (d_unhashed(dentry)) { - struct dentry *d; - - d = lookup_one(user_ns, dentry->d_name.name, dentry->d_parent, - dentry->d_name.len); - if (IS_ERR(d)) { - err = PTR_ERR(d); - goto out; - } - if (unlikely(d_is_negative(d))) { - dput(d); - err = -ENOENT; - goto out; - } - - ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d)); - dput(d); - } -out: - done_path_create(&path, dentry); - if (err) - pr_err("mkdir(%s): creation failed (err:%d)\n", name, err); - return err; -} - -static ssize_t ksmbd_vfs_getcasexattr(struct user_namespace *user_ns, - struct dentry *dentry, char *attr_name, - int attr_name_len, char **attr_value) -{ - char *name, *xattr_list = NULL; - ssize_t value_len = -ENOENT, xattr_list_len; - - xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list); - if (xattr_list_len <= 0) - goto out; - - for (name = xattr_list; name - xattr_list < xattr_list_len; - name += strlen(name) + 1) { - ksmbd_debug(VFS, "%s, len %zd\n", name, strlen(name)); - if (strncasecmp(attr_name, name, attr_name_len)) - continue; - - value_len = ksmbd_vfs_getxattr(user_ns, - dentry, - name, - attr_value); - if (value_len < 0) - pr_err("failed to get xattr in file\n"); - break; - } - -out: - kvfree(xattr_list); - return value_len; -} - -static int ksmbd_vfs_stream_read(struct ksmbd_file *fp, char *buf, loff_t *pos, - size_t count) -{ - ssize_t v_len; - char *stream_buf = NULL; - - ksmbd_debug(VFS, "read stream data pos : %llu, count : %zd\n", - *pos, count); - - v_len = ksmbd_vfs_getcasexattr(file_mnt_user_ns(fp->filp), - fp->filp->f_path.dentry, - fp->stream.name, - fp->stream.size, - &stream_buf); - if ((int)v_len <= 0) - return (int)v_len; - - if (v_len <= *pos) { - count = -EINVAL; - goto free_buf; - } - - if (v_len - *pos < count) - count = v_len - *pos; - - memcpy(buf, &stream_buf[*pos], count); - -free_buf: - kvfree(stream_buf); - return count; -} - -/** - * check_lock_range() - vfs helper for smb byte range file locking - * @filp: the file to apply the lock to - * @start: lock start byte offset - * @end: lock end byte offset - * @type: byte range type read/write - * - * Return: 0 on success, otherwise error - */ -static int check_lock_range(struct file *filp, loff_t start, loff_t end, - unsigned char type) -{ - struct file_lock *flock; - struct file_lock_context *ctx = file_inode(filp)->i_flctx; - int error = 0; - - if (!ctx || list_empty_careful(&ctx->flc_posix)) - return 0; - - spin_lock(&ctx->flc_lock); - list_for_each_entry(flock, &ctx->flc_posix, fl_list) { - /* check conflict locks */ - if (flock->fl_end >= start && end >= flock->fl_start) { - if (flock->fl_type == F_RDLCK) { - if (type == WRITE) { - pr_err("not allow write by shared lock\n"); - error = 1; - goto out; - } - } else if (flock->fl_type == F_WRLCK) { - /* check owner in lock */ - if (flock->fl_file != filp) { - error = 1; - pr_err("not allow rw access by exclusive lock from other opens\n"); - goto out; - } - } - } - } -out: - spin_unlock(&ctx->flc_lock); - return error; -} - -/** - * ksmbd_vfs_read() - vfs helper for smb file read - * @work: smb work - * @fid: file id of open file - * @count: read byte count - * @pos: file pos - * - * Return: number of read bytes on success, otherwise error - */ -int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count, - loff_t *pos) -{ - struct file *filp = fp->filp; - ssize_t nbytes = 0; - char *rbuf = work->aux_payload_buf; - struct inode *inode = file_inode(filp); - - if (S_ISDIR(inode->i_mode)) - return -EISDIR; - - if (unlikely(count == 0)) - return 0; - - if (work->conn->connection_type) { - if (!(fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) { - pr_err("no right to read(%pD)\n", fp->filp); - return -EACCES; - } - } - - if (ksmbd_stream_fd(fp)) - return ksmbd_vfs_stream_read(fp, rbuf, pos, count); - - if (!work->tcon->posix_extensions) { - int ret; - - ret = check_lock_range(filp, *pos, *pos + count - 1, READ); - if (ret) { - pr_err("unable to read due to lock\n"); - return -EAGAIN; - } - } - - nbytes = kernel_read(filp, rbuf, count, pos); - if (nbytes < 0) { - pr_err("smb read failed, err = %zd\n", nbytes); - return nbytes; - } - - filp->f_pos = *pos; - return nbytes; -} - -static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, - size_t count) -{ - char *stream_buf = NULL, *wbuf; - struct user_namespace *user_ns = file_mnt_user_ns(fp->filp); - size_t size, v_len; - int err = 0; - - ksmbd_debug(VFS, "write stream data pos : %llu, count : %zd\n", - *pos, count); - - size = *pos + count; - if (size > XATTR_SIZE_MAX) { - size = XATTR_SIZE_MAX; - count = (*pos + count) - XATTR_SIZE_MAX; - } - - v_len = ksmbd_vfs_getcasexattr(user_ns, - fp->filp->f_path.dentry, - fp->stream.name, - fp->stream.size, - &stream_buf); - if ((int)v_len < 0) { - pr_err("not found stream in xattr : %zd\n", v_len); - err = (int)v_len; - goto out; - } - - if (v_len < size) { - wbuf = kvmalloc(size, GFP_KERNEL | __GFP_ZERO); - if (!wbuf) { - err = -ENOMEM; - goto out; - } - - if (v_len > 0) - memcpy(wbuf, stream_buf, v_len); - kvfree(stream_buf); - stream_buf = wbuf; - } - - memcpy(&stream_buf[*pos], buf, count); - - err = ksmbd_vfs_setxattr(user_ns, - fp->filp->f_path.dentry, - fp->stream.name, - (void *)stream_buf, - size, - 0); - if (err < 0) - goto out; - - fp->filp->f_pos = *pos; - err = 0; -out: - kvfree(stream_buf); - return err; -} - -/** - * ksmbd_vfs_write() - vfs helper for smb file write - * @work: work - * @fid: file id of open file - * @buf: buf containing data for writing - * @count: read byte count - * @pos: file pos - * @sync: fsync after write - * @written: number of bytes written - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp, - char *buf, size_t count, loff_t *pos, bool sync, - ssize_t *written) -{ - struct file *filp; - loff_t offset = *pos; - int err = 0; - - if (work->conn->connection_type) { - if (!(fp->daccess & FILE_WRITE_DATA_LE)) { - pr_err("no right to write(%pD)\n", fp->filp); - err = -EACCES; - goto out; - } - } - - filp = fp->filp; - - if (ksmbd_stream_fd(fp)) { - err = ksmbd_vfs_stream_write(fp, buf, pos, count); - if (!err) - *written = count; - goto out; - } - - if (!work->tcon->posix_extensions) { - err = check_lock_range(filp, *pos, *pos + count - 1, WRITE); - if (err) { - pr_err("unable to write due to lock\n"); - err = -EAGAIN; - goto out; - } - } - - /* Do we need to break any of a levelII oplock? */ - smb_break_all_levII_oplock(work, fp, 1); - - err = kernel_write(filp, buf, count, pos); - if (err < 0) { - ksmbd_debug(VFS, "smb write failed, err = %d\n", err); - goto out; - } - - filp->f_pos = *pos; - *written = err; - err = 0; - if (sync) { - err = vfs_fsync_range(filp, offset, offset + *written, 0); - if (err < 0) - pr_err("fsync failed for filename = %pD, err = %d\n", - fp->filp, err); - } - -out: - return err; -} - -/** - * ksmbd_vfs_getattr() - vfs helper for smb getattr - * @work: work - * @fid: file id of open file - * @attrs: inode attributes - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat) -{ - int err; - - err = vfs_getattr(path, stat, STATX_BTIME, AT_STATX_SYNC_AS_STAT); - if (err) - pr_err("getattr failed, err %d\n", err); - return err; -} - -/** - * ksmbd_vfs_fsync() - vfs helper for smb fsync - * @work: work - * @fid: file id of open file - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_fsync(struct ksmbd_work *work, u64 fid, u64 p_id) -{ - struct ksmbd_file *fp; - int err; - - fp = ksmbd_lookup_fd_slow(work, fid, p_id); - if (!fp) { - pr_err("failed to get filp for fid %llu\n", fid); - return -ENOENT; - } - err = vfs_fsync(fp->filp, 0); - if (err < 0) - pr_err("smb fsync failed, err = %d\n", err); - ksmbd_fd_put(work, fp); - return err; -} - -/** - * ksmbd_vfs_remove_file() - vfs helper for smb rmdir or unlink - * @name: directory or file name that is relative to share - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name) -{ - struct user_namespace *user_ns; - struct path path; - struct dentry *parent; - int err; - - if (ksmbd_override_fsids(work)) - return -ENOMEM; - - err = ksmbd_vfs_kern_path(work, name, LOOKUP_NO_SYMLINKS, &path, false); - if (err) { - ksmbd_debug(VFS, "can't get %s, err %d\n", name, err); - ksmbd_revert_fsids(work); - return err; - } - - user_ns = mnt_user_ns(path.mnt); - parent = dget_parent(path.dentry); - err = ksmbd_vfs_lock_parent(user_ns, parent, path.dentry); - if (err) { - dput(parent); - path_put(&path); - ksmbd_revert_fsids(work); - return err; - } - - if (!d_inode(path.dentry)->i_nlink) { - err = -ENOENT; - goto out_err; - } - - if (S_ISDIR(d_inode(path.dentry)->i_mode)) { - err = vfs_rmdir(user_ns, d_inode(parent), path.dentry); - if (err && err != -ENOTEMPTY) - ksmbd_debug(VFS, "%s: rmdir failed, err %d\n", name, - err); - } else { - err = vfs_unlink(user_ns, d_inode(parent), path.dentry, NULL); - if (err) - ksmbd_debug(VFS, "%s: unlink failed, err %d\n", name, - err); - } - -out_err: - inode_unlock(d_inode(parent)); - dput(parent); - path_put(&path); - ksmbd_revert_fsids(work); - return err; -} - -/** - * ksmbd_vfs_link() - vfs helper for creating smb hardlink - * @oldname: source file name - * @newname: hardlink name that is relative to share - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname, - const char *newname) -{ - struct path oldpath, newpath; - struct dentry *dentry; - int err; - - if (ksmbd_override_fsids(work)) - return -ENOMEM; - - err = kern_path(oldname, LOOKUP_NO_SYMLINKS, &oldpath); - if (err) { - pr_err("cannot get linux path for %s, err = %d\n", - oldname, err); - goto out1; - } - - dentry = ksmbd_vfs_kern_path_create(work, newname, - LOOKUP_NO_SYMLINKS | LOOKUP_REVAL, - &newpath); - if (IS_ERR(dentry)) { - err = PTR_ERR(dentry); - pr_err("path create err for %s, err %d\n", newname, err); - goto out2; - } - - err = -EXDEV; - if (oldpath.mnt != newpath.mnt) { - pr_err("vfs_link failed err %d\n", err); - goto out3; - } - - err = vfs_link(oldpath.dentry, mnt_user_ns(newpath.mnt), - d_inode(newpath.dentry), - dentry, NULL); - if (err) - ksmbd_debug(VFS, "vfs_link failed err %d\n", err); - -out3: - done_path_create(&newpath, dentry); -out2: - path_put(&oldpath); -out1: - ksmbd_revert_fsids(work); - return err; -} - -static int ksmbd_validate_entry_in_use(struct dentry *src_dent) -{ - struct dentry *dst_dent; - - spin_lock(&src_dent->d_lock); - list_for_each_entry(dst_dent, &src_dent->d_subdirs, d_child) { - struct ksmbd_file *child_fp; - - if (d_really_is_negative(dst_dent)) - continue; - - child_fp = ksmbd_lookup_fd_inode(d_inode(dst_dent)); - if (child_fp) { - spin_unlock(&src_dent->d_lock); - ksmbd_debug(VFS, "Forbid rename, sub file/dir is in use\n"); - return -EACCES; - } - } - spin_unlock(&src_dent->d_lock); - - return 0; -} - -static int __ksmbd_vfs_rename(struct ksmbd_work *work, - struct user_namespace *src_user_ns, - struct dentry *src_dent_parent, - struct dentry *src_dent, - struct user_namespace *dst_user_ns, - struct dentry *dst_dent_parent, - struct dentry *trap_dent, - char *dst_name) -{ - struct dentry *dst_dent; - int err; - - if (!work->tcon->posix_extensions) { - err = ksmbd_validate_entry_in_use(src_dent); - if (err) - return err; - } - - if (d_really_is_negative(src_dent_parent)) - return -ENOENT; - if (d_really_is_negative(dst_dent_parent)) - return -ENOENT; - if (d_really_is_negative(src_dent)) - return -ENOENT; - if (src_dent == trap_dent) - return -EINVAL; - - if (ksmbd_override_fsids(work)) - return -ENOMEM; - - dst_dent = lookup_one(dst_user_ns, dst_name, dst_dent_parent, - strlen(dst_name)); - err = PTR_ERR(dst_dent); - if (IS_ERR(dst_dent)) { - pr_err("lookup failed %s [%d]\n", dst_name, err); - goto out; - } - - err = -ENOTEMPTY; - if (dst_dent != trap_dent && !d_really_is_positive(dst_dent)) { - struct renamedata rd = { - .old_mnt_userns = src_user_ns, - .old_dir = d_inode(src_dent_parent), - .old_dentry = src_dent, - .new_mnt_userns = dst_user_ns, - .new_dir = d_inode(dst_dent_parent), - .new_dentry = dst_dent, - }; - err = vfs_rename(&rd); - } - if (err) - pr_err("vfs_rename failed err %d\n", err); - if (dst_dent) - dput(dst_dent); -out: - ksmbd_revert_fsids(work); - return err; -} - -int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp, - char *newname) -{ - struct user_namespace *user_ns; - struct path dst_path; - struct dentry *src_dent_parent, *dst_dent_parent; - struct dentry *src_dent, *trap_dent, *src_child; - char *dst_name; - int err; - - dst_name = extract_last_component(newname); - if (!dst_name) { - dst_name = newname; - newname = ""; - } - - src_dent_parent = dget_parent(fp->filp->f_path.dentry); - src_dent = fp->filp->f_path.dentry; - - err = ksmbd_vfs_kern_path(work, newname, - LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY, - &dst_path, false); - if (err) { - ksmbd_debug(VFS, "Cannot get path for %s [%d]\n", newname, err); - goto out; - } - dst_dent_parent = dst_path.dentry; - - trap_dent = lock_rename(src_dent_parent, dst_dent_parent); - dget(src_dent); - dget(dst_dent_parent); - user_ns = file_mnt_user_ns(fp->filp); - src_child = lookup_one(user_ns, src_dent->d_name.name, src_dent_parent, - src_dent->d_name.len); - if (IS_ERR(src_child)) { - err = PTR_ERR(src_child); - goto out_lock; - } - - if (src_child != src_dent) { - err = -ESTALE; - dput(src_child); - goto out_lock; - } - dput(src_child); - - err = __ksmbd_vfs_rename(work, - user_ns, - src_dent_parent, - src_dent, - mnt_user_ns(dst_path.mnt), - dst_dent_parent, - trap_dent, - dst_name); -out_lock: - dput(src_dent); - dput(dst_dent_parent); - unlock_rename(src_dent_parent, dst_dent_parent); - path_put(&dst_path); -out: - dput(src_dent_parent); - return err; -} - -/** - * ksmbd_vfs_truncate() - vfs helper for smb file truncate - * @work: work - * @fid: file id of old file - * @size: truncate to given size - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_truncate(struct ksmbd_work *work, - struct ksmbd_file *fp, loff_t size) -{ - int err = 0; - struct file *filp; - - filp = fp->filp; - - /* Do we need to break any of a levelII oplock? */ - smb_break_all_levII_oplock(work, fp, 1); - - if (!work->tcon->posix_extensions) { - struct inode *inode = file_inode(filp); - - if (size < inode->i_size) { - err = check_lock_range(filp, size, - inode->i_size - 1, WRITE); - } else { - err = check_lock_range(filp, inode->i_size, - size - 1, WRITE); - } - - if (err) { - pr_err("failed due to lock\n"); - return -EAGAIN; - } - } - - err = vfs_truncate(&filp->f_path, size); - if (err) - pr_err("truncate failed, err %d\n", err); - return err; -} - -/** - * ksmbd_vfs_listxattr() - vfs helper for smb list extended attributes - * @dentry: dentry of file for listing xattrs - * @list: destination buffer - * @size: destination buffer length - * - * Return: xattr list length on success, otherwise error - */ -ssize_t ksmbd_vfs_listxattr(struct dentry *dentry, char **list) -{ - ssize_t size; - char *vlist = NULL; - - size = vfs_listxattr(dentry, NULL, 0); - if (size <= 0) - return size; - - vlist = kvmalloc(size, GFP_KERNEL | __GFP_ZERO); - if (!vlist) - return -ENOMEM; - - *list = vlist; - size = vfs_listxattr(dentry, vlist, size); - if (size < 0) { - ksmbd_debug(VFS, "listxattr failed\n"); - kvfree(vlist); - *list = NULL; - } - - return size; -} - -static ssize_t ksmbd_vfs_xattr_len(struct user_namespace *user_ns, - struct dentry *dentry, char *xattr_name) -{ - return vfs_getxattr(user_ns, dentry, xattr_name, NULL, 0); -} - -/** - * ksmbd_vfs_getxattr() - vfs helper for smb get extended attributes value - * @user_ns: user namespace - * @dentry: dentry of file for getting xattrs - * @xattr_name: name of xattr name to query - * @xattr_buf: destination buffer xattr value - * - * Return: read xattr value length on success, otherwise error - */ -ssize_t ksmbd_vfs_getxattr(struct user_namespace *user_ns, - struct dentry *dentry, - char *xattr_name, char **xattr_buf) -{ - ssize_t xattr_len; - char *buf; - - *xattr_buf = NULL; - xattr_len = ksmbd_vfs_xattr_len(user_ns, dentry, xattr_name); - if (xattr_len < 0) - return xattr_len; - - buf = kmalloc(xattr_len + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - xattr_len = vfs_getxattr(user_ns, dentry, xattr_name, - (void *)buf, xattr_len); - if (xattr_len > 0) - *xattr_buf = buf; - else - kfree(buf); - return xattr_len; -} - -/** - * ksmbd_vfs_setxattr() - vfs helper for smb set extended attributes value - * @user_ns: user namespace - * @dentry: dentry to set XATTR at - * @name: xattr name for setxattr - * @value: xattr value to set - * @size: size of xattr value - * @flags: destination buffer length - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_setxattr(struct user_namespace *user_ns, - struct dentry *dentry, const char *attr_name, - void *attr_value, size_t attr_size, int flags) -{ - int err; - - err = vfs_setxattr(user_ns, - dentry, - attr_name, - attr_value, - attr_size, - flags); - if (err) - ksmbd_debug(VFS, "setxattr failed, err %d\n", err); - return err; -} - -/** - * ksmbd_vfs_set_fadvise() - convert smb IO caching options to linux options - * @filp: file pointer for IO - * @options: smb IO options - */ -void ksmbd_vfs_set_fadvise(struct file *filp, __le32 option) -{ - struct address_space *mapping; - - mapping = filp->f_mapping; - - if (!option || !mapping) - return; - - if (option & FILE_WRITE_THROUGH_LE) { - filp->f_flags |= O_SYNC; - } else if (option & FILE_SEQUENTIAL_ONLY_LE) { - filp->f_ra.ra_pages = inode_to_bdi(mapping->host)->ra_pages * 2; - spin_lock(&filp->f_lock); - filp->f_mode &= ~FMODE_RANDOM; - spin_unlock(&filp->f_lock); - } else if (option & FILE_RANDOM_ACCESS_LE) { - spin_lock(&filp->f_lock); - filp->f_mode |= FMODE_RANDOM; - spin_unlock(&filp->f_lock); - } -} - -int ksmbd_vfs_zero_data(struct ksmbd_work *work, struct ksmbd_file *fp, - loff_t off, loff_t len) -{ - smb_break_all_levII_oplock(work, fp, 1); - if (fp->f_ci->m_fattr & FILE_ATTRIBUTE_SPARSE_FILE_LE) - return vfs_fallocate(fp->filp, - FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, - off, len); - - return vfs_fallocate(fp->filp, - FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE, - off, len); -} - -int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length, - struct file_allocated_range_buffer *ranges, - unsigned int in_count, unsigned int *out_count) -{ - struct file *f = fp->filp; - struct inode *inode = file_inode(fp->filp); - loff_t maxbytes = (u64)inode->i_sb->s_maxbytes, end; - loff_t extent_start, extent_end; - int ret = 0; - - if (start > maxbytes) - return -EFBIG; - - if (!in_count) - return 0; - - /* - * Shrink request scope to what the fs can actually handle. - */ - if (length > maxbytes || (maxbytes - length) < start) - length = maxbytes - start; - - if (start + length > inode->i_size) - length = inode->i_size - start; - - *out_count = 0; - end = start + length; - while (start < end && *out_count < in_count) { - extent_start = vfs_llseek(f, start, SEEK_DATA); - if (extent_start < 0) { - if (extent_start != -ENXIO) - ret = (int)extent_start; - break; - } - - if (extent_start >= end) - break; - - extent_end = vfs_llseek(f, extent_start, SEEK_HOLE); - if (extent_end < 0) { - if (extent_end != -ENXIO) - ret = (int)extent_end; - break; - } else if (extent_start >= extent_end) { - break; - } - - ranges[*out_count].file_offset = cpu_to_le64(extent_start); - ranges[(*out_count)++].length = - cpu_to_le64(min(extent_end, end) - extent_start); - - start = extent_end; - } - - return ret; -} - -int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns, - struct dentry *dentry, char *attr_name) -{ - return vfs_removexattr(user_ns, dentry, attr_name); -} - -int ksmbd_vfs_unlink(struct user_namespace *user_ns, - struct dentry *dir, struct dentry *dentry) -{ - int err = 0; - - err = ksmbd_vfs_lock_parent(user_ns, dir, dentry); - if (err) - return err; - dget(dentry); - - if (S_ISDIR(d_inode(dentry)->i_mode)) - err = vfs_rmdir(user_ns, d_inode(dir), dentry); - else - err = vfs_unlink(user_ns, d_inode(dir), dentry, NULL); - - dput(dentry); - inode_unlock(d_inode(dir)); - if (err) - ksmbd_debug(VFS, "failed to delete, err %d\n", err); - - return err; -} - -static bool __dir_empty(struct dir_context *ctx, const char *name, int namlen, - loff_t offset, u64 ino, unsigned int d_type) -{ - struct ksmbd_readdir_data *buf; - - buf = container_of(ctx, struct ksmbd_readdir_data, ctx); - buf->dirent_count++; - - return buf->dirent_count <= 2; -} - -/** - * ksmbd_vfs_empty_dir() - check for empty directory - * @fp: ksmbd file pointer - * - * Return: true if directory empty, otherwise false - */ -int ksmbd_vfs_empty_dir(struct ksmbd_file *fp) -{ - int err; - struct ksmbd_readdir_data readdir_data; - - memset(&readdir_data, 0, sizeof(struct ksmbd_readdir_data)); - - set_ctx_actor(&readdir_data.ctx, __dir_empty); - readdir_data.dirent_count = 0; - - err = iterate_dir(fp->filp, &readdir_data.ctx); - if (readdir_data.dirent_count > 2) - err = -ENOTEMPTY; - else - err = 0; - return err; -} - -static bool __caseless_lookup(struct dir_context *ctx, const char *name, - int namlen, loff_t offset, u64 ino, - unsigned int d_type) -{ - struct ksmbd_readdir_data *buf; - int cmp = -EINVAL; - - buf = container_of(ctx, struct ksmbd_readdir_data, ctx); - - if (buf->used != namlen) - return true; - 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); - buf->dirent_count = 1; - return false; - } - return true; -} - -/** - * ksmbd_vfs_lookup_in_dir() - lookup a file in a directory - * @dir: path info - * @name: filename to lookup - * @namelen: filename length - * - * Return: 0 on success, otherwise error - */ -static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name, - size_t namelen, struct unicode_map *um) -{ - int ret; - struct file *dfilp; - int flags = O_RDONLY | O_LARGEFILE; - struct ksmbd_readdir_data readdir_data = { - .ctx.actor = __caseless_lookup, - .private = name, - .used = namelen, - .dirent_count = 0, - .um = um, - }; - - dfilp = dentry_open(dir, flags, current_cred()); - if (IS_ERR(dfilp)) - return PTR_ERR(dfilp); - - ret = iterate_dir(dfilp, &readdir_data.ctx); - if (readdir_data.dirent_count > 0) - ret = 0; - fput(dfilp); - return ret; -} - -/** - * ksmbd_vfs_kern_path() - lookup a file and get path info - * @name: file path that is relative to share - * @flags: lookup flags - * @path: if lookup succeed, return path info - * @caseless: caseless filename lookup - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *name, - unsigned int flags, struct path *path, bool caseless) -{ - struct ksmbd_share_config *share_conf = work->tcon->share_conf; - int err; - - flags |= LOOKUP_BENEATH; - err = vfs_path_lookup(share_conf->vfs_path.dentry, - share_conf->vfs_path.mnt, - name, - flags, - path); - if (!err) - return 0; - - if (caseless) { - char *filepath; - struct path parent; - size_t path_len, remain_len; - - filepath = kstrdup(name, GFP_KERNEL); - if (!filepath) - return -ENOMEM; - - path_len = strlen(filepath); - remain_len = path_len; - - parent = share_conf->vfs_path; - path_get(&parent); - - while (d_can_lookup(parent.dentry)) { - char *filename = filepath + path_len - remain_len; - char *next = strchrnul(filename, '/'); - size_t filename_len = next - filename; - bool is_last = !next[0]; - - if (filename_len == 0) - break; - - err = ksmbd_vfs_lookup_in_dir(&parent, filename, - filename_len, - work->conn->um); - path_put(&parent); - if (err) - goto out; - - next[0] = '\0'; - - err = vfs_path_lookup(share_conf->vfs_path.dentry, - share_conf->vfs_path.mnt, - filepath, - flags, - &parent); - if (err) - goto out; - else if (is_last) { - *path = parent; - goto out; - } - - next[0] = '/'; - remain_len -= filename_len + 1; - } - - path_put(&parent); - err = -EINVAL; -out: - kfree(filepath); - } - return err; -} - -struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, - const char *name, - unsigned int flags, - struct path *path) -{ - char *abs_name; - struct dentry *dent; - - abs_name = convert_to_unix_name(work->tcon->share_conf, name); - if (!abs_name) - return ERR_PTR(-ENOMEM); - - dent = kern_path_create(AT_FDCWD, abs_name, path, flags); - kfree(abs_name); - return dent; -} - -int ksmbd_vfs_remove_acl_xattrs(struct user_namespace *user_ns, - struct dentry *dentry) -{ - char *name, *xattr_list = NULL; - ssize_t xattr_list_len; - int err = 0; - - xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list); - if (xattr_list_len < 0) { - goto out; - } else if (!xattr_list_len) { - ksmbd_debug(SMB, "empty xattr in the file\n"); - goto out; - } - - for (name = xattr_list; name - xattr_list < xattr_list_len; - name += strlen(name) + 1) { - ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name)); - - if (!strncmp(name, XATTR_NAME_POSIX_ACL_ACCESS, - sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1) || - !strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT, - sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1)) { - err = ksmbd_vfs_remove_xattr(user_ns, dentry, name); - if (err) - ksmbd_debug(SMB, - "remove acl xattr failed : %s\n", name); - } - } -out: - kvfree(xattr_list); - return err; -} - -int ksmbd_vfs_remove_sd_xattrs(struct user_namespace *user_ns, - struct dentry *dentry) -{ - char *name, *xattr_list = NULL; - ssize_t xattr_list_len; - int err = 0; - - xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list); - if (xattr_list_len < 0) { - goto out; - } else if (!xattr_list_len) { - ksmbd_debug(SMB, "empty xattr in the file\n"); - goto out; - } - - for (name = xattr_list; name - xattr_list < xattr_list_len; - name += strlen(name) + 1) { - ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name)); - - if (!strncmp(name, XATTR_NAME_SD, XATTR_NAME_SD_LEN)) { - err = ksmbd_vfs_remove_xattr(user_ns, dentry, name); - if (err) - ksmbd_debug(SMB, "remove xattr failed : %s\n", name); - } - } -out: - kvfree(xattr_list); - return err; -} - -static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct user_namespace *user_ns, - struct inode *inode, - int acl_type) -{ - struct xattr_smb_acl *smb_acl = NULL; - struct posix_acl *posix_acls; - struct posix_acl_entry *pa_entry; - struct xattr_acl_entry *xa_entry; - int i; - - if (!IS_ENABLED(CONFIG_FS_POSIX_ACL)) - return NULL; - - posix_acls = get_acl(inode, acl_type); - if (!posix_acls) - return NULL; - - smb_acl = kzalloc(sizeof(struct xattr_smb_acl) + - sizeof(struct xattr_acl_entry) * posix_acls->a_count, - GFP_KERNEL); - if (!smb_acl) - goto out; - - smb_acl->count = posix_acls->a_count; - pa_entry = posix_acls->a_entries; - xa_entry = smb_acl->entries; - for (i = 0; i < posix_acls->a_count; i++, pa_entry++, xa_entry++) { - switch (pa_entry->e_tag) { - case ACL_USER: - xa_entry->type = SMB_ACL_USER; - xa_entry->uid = posix_acl_uid_translate(user_ns, pa_entry); - break; - case ACL_USER_OBJ: - xa_entry->type = SMB_ACL_USER_OBJ; - break; - case ACL_GROUP: - xa_entry->type = SMB_ACL_GROUP; - xa_entry->gid = posix_acl_gid_translate(user_ns, pa_entry); - break; - case ACL_GROUP_OBJ: - xa_entry->type = SMB_ACL_GROUP_OBJ; - break; - case ACL_OTHER: - xa_entry->type = SMB_ACL_OTHER; - break; - case ACL_MASK: - xa_entry->type = SMB_ACL_MASK; - break; - default: - pr_err("unknown type : 0x%x\n", pa_entry->e_tag); - goto out; - } - - if (pa_entry->e_perm & ACL_READ) - xa_entry->perm |= SMB_ACL_READ; - if (pa_entry->e_perm & ACL_WRITE) - xa_entry->perm |= SMB_ACL_WRITE; - if (pa_entry->e_perm & ACL_EXECUTE) - xa_entry->perm |= SMB_ACL_EXECUTE; - } -out: - posix_acl_release(posix_acls); - return smb_acl; -} - -int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, - struct user_namespace *user_ns, - struct dentry *dentry, - struct smb_ntsd *pntsd, int len) -{ - int rc; - struct ndr sd_ndr = {0}, acl_ndr = {0}; - struct xattr_ntacl acl = {0}; - struct xattr_smb_acl *smb_acl, *def_smb_acl = NULL; - struct inode *inode = d_inode(dentry); - - acl.version = 4; - acl.hash_type = XATTR_SD_HASH_TYPE_SHA256; - acl.current_time = ksmbd_UnixTimeToNT(current_time(inode)); - - memcpy(acl.desc, "posix_acl", 9); - acl.desc_len = 10; - - pntsd->osidoffset = - cpu_to_le32(le32_to_cpu(pntsd->osidoffset) + NDR_NTSD_OFFSETOF); - pntsd->gsidoffset = - cpu_to_le32(le32_to_cpu(pntsd->gsidoffset) + NDR_NTSD_OFFSETOF); - pntsd->dacloffset = - cpu_to_le32(le32_to_cpu(pntsd->dacloffset) + NDR_NTSD_OFFSETOF); - - acl.sd_buf = (char *)pntsd; - acl.sd_size = len; - - rc = ksmbd_gen_sd_hash(conn, acl.sd_buf, acl.sd_size, acl.hash); - if (rc) { - pr_err("failed to generate hash for ndr acl\n"); - return rc; - } - - smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns, inode, - ACL_TYPE_ACCESS); - if (S_ISDIR(inode->i_mode)) - def_smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns, inode, - ACL_TYPE_DEFAULT); - - rc = ndr_encode_posix_acl(&acl_ndr, user_ns, inode, - smb_acl, def_smb_acl); - if (rc) { - pr_err("failed to encode ndr to posix acl\n"); - goto out; - } - - rc = ksmbd_gen_sd_hash(conn, acl_ndr.data, acl_ndr.offset, - acl.posix_acl_hash); - if (rc) { - pr_err("failed to generate hash for ndr acl\n"); - goto out; - } - - rc = ndr_encode_v4_ntacl(&sd_ndr, &acl); - if (rc) { - pr_err("failed to encode ndr to posix acl\n"); - goto out; - } - - rc = ksmbd_vfs_setxattr(user_ns, dentry, - XATTR_NAME_SD, sd_ndr.data, - sd_ndr.offset, 0); - if (rc < 0) - pr_err("Failed to store XATTR ntacl :%d\n", rc); - - kfree(sd_ndr.data); -out: - kfree(acl_ndr.data); - kfree(smb_acl); - kfree(def_smb_acl); - return rc; -} - -int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, - struct user_namespace *user_ns, - struct dentry *dentry, - struct smb_ntsd **pntsd) -{ - int rc; - struct ndr n; - struct inode *inode = d_inode(dentry); - struct ndr acl_ndr = {0}; - struct xattr_ntacl acl; - struct xattr_smb_acl *smb_acl = NULL, *def_smb_acl = NULL; - __u8 cmp_hash[XATTR_SD_HASH_SIZE] = {0}; - - rc = ksmbd_vfs_getxattr(user_ns, dentry, XATTR_NAME_SD, &n.data); - if (rc <= 0) - return rc; - - n.length = rc; - rc = ndr_decode_v4_ntacl(&n, &acl); - if (rc) - goto free_n_data; - - smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns, inode, - ACL_TYPE_ACCESS); - if (S_ISDIR(inode->i_mode)) - def_smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns, inode, - ACL_TYPE_DEFAULT); - - rc = ndr_encode_posix_acl(&acl_ndr, user_ns, inode, smb_acl, - def_smb_acl); - if (rc) { - pr_err("failed to encode ndr to posix acl\n"); - goto out_free; - } - - rc = ksmbd_gen_sd_hash(conn, acl_ndr.data, acl_ndr.offset, cmp_hash); - if (rc) { - pr_err("failed to generate hash for ndr acl\n"); - goto out_free; - } - - if (memcmp(cmp_hash, acl.posix_acl_hash, XATTR_SD_HASH_SIZE)) { - pr_err("hash value diff\n"); - rc = -EINVAL; - goto out_free; - } - - *pntsd = acl.sd_buf; - if (acl.sd_size < sizeof(struct smb_ntsd)) { - pr_err("sd size is invalid\n"); - goto out_free; - } - - (*pntsd)->osidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->osidoffset) - - NDR_NTSD_OFFSETOF); - (*pntsd)->gsidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->gsidoffset) - - NDR_NTSD_OFFSETOF); - (*pntsd)->dacloffset = cpu_to_le32(le32_to_cpu((*pntsd)->dacloffset) - - NDR_NTSD_OFFSETOF); - - rc = acl.sd_size; -out_free: - kfree(acl_ndr.data); - kfree(smb_acl); - kfree(def_smb_acl); - if (rc < 0) { - kfree(acl.sd_buf); - *pntsd = NULL; - } - -free_n_data: - kfree(n.data); - return rc; -} - -int ksmbd_vfs_set_dos_attrib_xattr(struct user_namespace *user_ns, - struct dentry *dentry, - struct xattr_dos_attrib *da) -{ - struct ndr n; - int err; - - err = ndr_encode_dos_attr(&n, da); - if (err) - return err; - - err = ksmbd_vfs_setxattr(user_ns, dentry, XATTR_NAME_DOS_ATTRIBUTE, - (void *)n.data, n.offset, 0); - if (err) - ksmbd_debug(SMB, "failed to store dos attribute in xattr\n"); - kfree(n.data); - - return err; -} - -int ksmbd_vfs_get_dos_attrib_xattr(struct user_namespace *user_ns, - struct dentry *dentry, - struct xattr_dos_attrib *da) -{ - struct ndr n; - int err; - - err = ksmbd_vfs_getxattr(user_ns, dentry, XATTR_NAME_DOS_ATTRIBUTE, - (char **)&n.data); - if (err > 0) { - n.length = err; - if (ndr_decode_dos_attr(&n, da)) - err = -EINVAL; - kfree(n.data); - } else { - ksmbd_debug(SMB, "failed to load dos attribute in xattr\n"); - } - - return err; -} - -/** - * ksmbd_vfs_init_kstat() - convert unix stat information to smb stat format - * @p: destination buffer - * @ksmbd_kstat: ksmbd kstat wrapper - */ -void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat) -{ - struct file_directory_info *info = (struct file_directory_info *)(*p); - struct kstat *kstat = ksmbd_kstat->kstat; - u64 time; - - info->FileIndex = 0; - info->CreationTime = cpu_to_le64(ksmbd_kstat->create_time); - time = ksmbd_UnixTimeToNT(kstat->atime); - info->LastAccessTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(kstat->mtime); - info->LastWriteTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(kstat->ctime); - info->ChangeTime = cpu_to_le64(time); - - if (ksmbd_kstat->file_attributes & FILE_ATTRIBUTE_DIRECTORY_LE) { - info->EndOfFile = 0; - info->AllocationSize = 0; - } else { - info->EndOfFile = cpu_to_le64(kstat->size); - info->AllocationSize = cpu_to_le64(kstat->blocks << 9); - } - info->ExtFileAttributes = ksmbd_kstat->file_attributes; - - return info; -} - -int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work, - struct user_namespace *user_ns, - struct dentry *dentry, - struct ksmbd_kstat *ksmbd_kstat) -{ - u64 time; - int rc; - - generic_fillattr(user_ns, d_inode(dentry), ksmbd_kstat->kstat); - - time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime); - ksmbd_kstat->create_time = time; - - /* - * set default value for the case that store dos attributes is not yes - * or that acl is disable in server's filesystem and the config is yes. - */ - if (S_ISDIR(ksmbd_kstat->kstat->mode)) - ksmbd_kstat->file_attributes = FILE_ATTRIBUTE_DIRECTORY_LE; - else - ksmbd_kstat->file_attributes = FILE_ATTRIBUTE_ARCHIVE_LE; - - if (test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) { - struct xattr_dos_attrib da; - - rc = ksmbd_vfs_get_dos_attrib_xattr(user_ns, dentry, &da); - if (rc > 0) { - ksmbd_kstat->file_attributes = cpu_to_le32(da.attr); - ksmbd_kstat->create_time = da.create_time; - } else { - ksmbd_debug(VFS, "fail to load dos attribute.\n"); - } - } - - return 0; -} - -ssize_t ksmbd_vfs_casexattr_len(struct user_namespace *user_ns, - struct dentry *dentry, char *attr_name, - int attr_name_len) -{ - char *name, *xattr_list = NULL; - ssize_t value_len = -ENOENT, xattr_list_len; - - xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list); - if (xattr_list_len <= 0) - goto out; - - for (name = xattr_list; name - xattr_list < xattr_list_len; - name += strlen(name) + 1) { - ksmbd_debug(VFS, "%s, len %zd\n", name, strlen(name)); - if (strncasecmp(attr_name, name, attr_name_len)) - continue; - - value_len = ksmbd_vfs_xattr_len(user_ns, dentry, name); - break; - } - -out: - kvfree(xattr_list); - return value_len; -} - -int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name, - size_t *xattr_stream_name_size, int s_type) -{ - char *type, *buf; - - if (s_type == DIR_STREAM) - type = ":$INDEX_ALLOCATION"; - else - type = ":$DATA"; - - buf = kasprintf(GFP_KERNEL, "%s%s%s", - XATTR_NAME_STREAM, stream_name, type); - if (!buf) - return -ENOMEM; - - *xattr_stream_name = buf; - *xattr_stream_name_size = strlen(buf) + 1; - - return 0; -} - -int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work, - struct ksmbd_file *src_fp, - struct ksmbd_file *dst_fp, - struct srv_copychunk *chunks, - unsigned int chunk_count, - unsigned int *chunk_count_written, - unsigned int *chunk_size_written, - loff_t *total_size_written) -{ - unsigned int i; - loff_t src_off, dst_off, src_file_size; - size_t len; - int ret; - - *chunk_count_written = 0; - *chunk_size_written = 0; - *total_size_written = 0; - - if (!(src_fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) { - pr_err("no right to read(%pD)\n", src_fp->filp); - return -EACCES; - } - if (!(dst_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE))) { - pr_err("no right to write(%pD)\n", dst_fp->filp); - return -EACCES; - } - - if (ksmbd_stream_fd(src_fp) || ksmbd_stream_fd(dst_fp)) - return -EBADF; - - smb_break_all_levII_oplock(work, dst_fp, 1); - - if (!work->tcon->posix_extensions) { - for (i = 0; i < chunk_count; i++) { - src_off = le64_to_cpu(chunks[i].SourceOffset); - dst_off = le64_to_cpu(chunks[i].TargetOffset); - len = le32_to_cpu(chunks[i].Length); - - if (check_lock_range(src_fp->filp, src_off, - src_off + len - 1, READ)) - return -EAGAIN; - if (check_lock_range(dst_fp->filp, dst_off, - dst_off + len - 1, WRITE)) - return -EAGAIN; - } - } - - src_file_size = i_size_read(file_inode(src_fp->filp)); - - for (i = 0; i < chunk_count; i++) { - src_off = le64_to_cpu(chunks[i].SourceOffset); - dst_off = le64_to_cpu(chunks[i].TargetOffset); - len = le32_to_cpu(chunks[i].Length); - - if (src_off + len > src_file_size) - return -E2BIG; - - ret = vfs_copy_file_range(src_fp->filp, src_off, - dst_fp->filp, dst_off, len, 0); - if (ret == -EOPNOTSUPP || ret == -EXDEV) - ret = vfs_copy_file_range(src_fp->filp, src_off, - dst_fp->filp, dst_off, len, - COPY_FILE_SPLICE); - if (ret < 0) - return ret; - - *chunk_count_written += 1; - *total_size_written += ret; - } - return 0; -} - -void ksmbd_vfs_posix_lock_wait(struct file_lock *flock) -{ - wait_event(flock->fl_wait, !flock->fl_blocker); -} - -int ksmbd_vfs_posix_lock_wait_timeout(struct file_lock *flock, long timeout) -{ - return wait_event_interruptible_timeout(flock->fl_wait, - !flock->fl_blocker, - timeout); -} - -void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock) -{ - locks_delete_block(flock); -} - -int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns, - struct inode *inode) -{ - struct posix_acl_state acl_state; - struct posix_acl *acls; - int rc; - - if (!IS_ENABLED(CONFIG_FS_POSIX_ACL)) - return -EOPNOTSUPP; - - ksmbd_debug(SMB, "Set posix acls\n"); - rc = init_acl_state(&acl_state, 1); - if (rc) - return rc; - - /* Set default owner group */ - acl_state.owner.allow = (inode->i_mode & 0700) >> 6; - acl_state.group.allow = (inode->i_mode & 0070) >> 3; - acl_state.other.allow = inode->i_mode & 0007; - acl_state.users->aces[acl_state.users->n].uid = inode->i_uid; - acl_state.users->aces[acl_state.users->n++].perms.allow = - acl_state.owner.allow; - acl_state.groups->aces[acl_state.groups->n].gid = inode->i_gid; - acl_state.groups->aces[acl_state.groups->n++].perms.allow = - acl_state.group.allow; - acl_state.mask.allow = 0x07; - - acls = posix_acl_alloc(6, GFP_KERNEL); - if (!acls) { - free_acl_state(&acl_state); - return -ENOMEM; - } - posix_state_to_acl(&acl_state, acls->a_entries); - rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls); - if (rc < 0) - ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", - rc); - else if (S_ISDIR(inode->i_mode)) { - posix_state_to_acl(&acl_state, acls->a_entries); - rc = set_posix_acl(user_ns, inode, ACL_TYPE_DEFAULT, - acls); - if (rc < 0) - ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", - rc); - } - free_acl_state(&acl_state); - posix_acl_release(acls); - return rc; -} - -int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns, - struct inode *inode, struct inode *parent_inode) -{ - struct posix_acl *acls; - struct posix_acl_entry *pace; - int rc, i; - - if (!IS_ENABLED(CONFIG_FS_POSIX_ACL)) - return -EOPNOTSUPP; - - acls = get_acl(parent_inode, ACL_TYPE_DEFAULT); - if (!acls) - return -ENOENT; - pace = acls->a_entries; - - for (i = 0; i < acls->a_count; i++, pace++) { - if (pace->e_tag == ACL_MASK) { - pace->e_perm = 0x07; - break; - } - } - - rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls); - if (rc < 0) - ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", - rc); - if (S_ISDIR(inode->i_mode)) { - rc = set_posix_acl(user_ns, inode, ACL_TYPE_DEFAULT, - acls); - if (rc < 0) - ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", - rc); - } - posix_acl_release(acls); - return rc; -} diff --git a/fs/ksmbd/vfs.h b/fs/ksmbd/vfs.h deleted file mode 100644 index 593059ca8511..000000000000 --- a/fs/ksmbd/vfs.h +++ /dev/null @@ -1,167 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __KSMBD_VFS_H__ -#define __KSMBD_VFS_H__ - -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/namei.h> -#include <uapi/linux/xattr.h> -#include <linux/posix_acl.h> -#include <linux/unicode.h> - -#include "smbacl.h" -#include "xattr.h" - -/* - * Enumeration for stream type. - */ -enum { - DATA_STREAM = 1, /* type $DATA */ - DIR_STREAM /* type $INDEX_ALLOCATION */ -}; - -/* CreateOptions */ -#define CREATE_TREE_CONNECTION cpu_to_le32(0x00000080) -#define FILE_RESERVE_OPFILTER_LE cpu_to_le32(0x00100000) - -#define CREATE_OPTION_READONLY 0x10000000 -/* system. NB not sent over wire */ -#define CREATE_OPTION_SPECIAL 0x20000000 - -struct ksmbd_work; -struct ksmbd_file; -struct ksmbd_conn; - -struct ksmbd_dir_info { - const char *name; - char *wptr; - char *rptr; - int name_len; - int out_buf_len; - int num_entry; - int data_count; - int last_entry_offset; - bool hide_dot_file; - int flags; - int last_entry_off_align; -}; - -struct ksmbd_readdir_data { - struct dir_context ctx; - union { - void *private; - char *dirent; - }; - - unsigned int used; - unsigned int dirent_count; - unsigned int file_attr; - struct unicode_map *um; -}; - -/* ksmbd kstat wrapper to get valid create time when reading dir entry */ -struct ksmbd_kstat { - struct kstat *kstat; - unsigned long long create_time; - __le32 file_attributes; -}; - -int ksmbd_vfs_lock_parent(struct user_namespace *user_ns, struct dentry *parent, - struct dentry *child); -int ksmbd_vfs_may_delete(struct user_namespace *user_ns, struct dentry *dentry); -int ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns, - struct dentry *dentry, __le32 *daccess); -int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode); -int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode); -int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, - size_t count, loff_t *pos); -int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp, - char *buf, size_t count, loff_t *pos, bool sync, - ssize_t *written); -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_link(struct ksmbd_work *work, - const char *oldname, const char *newname); -int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat); -int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp, - char *newname); -int ksmbd_vfs_truncate(struct ksmbd_work *work, - struct ksmbd_file *fp, loff_t size); -struct srv_copychunk; -int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work, - struct ksmbd_file *src_fp, - struct ksmbd_file *dst_fp, - struct srv_copychunk *chunks, - unsigned int chunk_count, - unsigned int *chunk_count_written, - unsigned int *chunk_size_written, - loff_t *total_size_written); -ssize_t ksmbd_vfs_listxattr(struct dentry *dentry, char **list); -ssize_t ksmbd_vfs_getxattr(struct user_namespace *user_ns, - struct dentry *dentry, - char *xattr_name, - char **xattr_buf); -ssize_t ksmbd_vfs_casexattr_len(struct user_namespace *user_ns, - struct dentry *dentry, char *attr_name, - int attr_name_len); -int ksmbd_vfs_setxattr(struct user_namespace *user_ns, - struct dentry *dentry, const char *attr_name, - void *attr_value, size_t attr_size, int flags); -int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name, - size_t *xattr_stream_name_size, int s_type); -int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns, - struct dentry *dentry, char *attr_name); -int ksmbd_vfs_kern_path(struct ksmbd_work *work, - char *name, unsigned int flags, struct path *path, - bool caseless); -struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, - const char *name, - unsigned int flags, - struct path *path); -int ksmbd_vfs_empty_dir(struct ksmbd_file *fp); -void ksmbd_vfs_set_fadvise(struct file *filp, __le32 option); -int ksmbd_vfs_zero_data(struct ksmbd_work *work, struct ksmbd_file *fp, - loff_t off, loff_t len); -struct file_allocated_range_buffer; -int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length, - struct file_allocated_range_buffer *ranges, - unsigned int in_count, unsigned int *out_count); -int ksmbd_vfs_unlink(struct user_namespace *user_ns, - struct dentry *dir, struct dentry *dentry); -void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat); -int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work, - struct user_namespace *user_ns, - struct dentry *dentry, - struct ksmbd_kstat *ksmbd_kstat); -void ksmbd_vfs_posix_lock_wait(struct file_lock *flock); -int ksmbd_vfs_posix_lock_wait_timeout(struct file_lock *flock, long timeout); -void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock); -int ksmbd_vfs_remove_acl_xattrs(struct user_namespace *user_ns, - struct dentry *dentry); -int ksmbd_vfs_remove_sd_xattrs(struct user_namespace *user_ns, - struct dentry *dentry); -int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, - struct user_namespace *user_ns, - struct dentry *dentry, - struct smb_ntsd *pntsd, int len); -int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, - struct user_namespace *user_ns, - struct dentry *dentry, - struct smb_ntsd **pntsd); -int ksmbd_vfs_set_dos_attrib_xattr(struct user_namespace *user_ns, - struct dentry *dentry, - struct xattr_dos_attrib *da); -int ksmbd_vfs_get_dos_attrib_xattr(struct user_namespace *user_ns, - struct dentry *dentry, - struct xattr_dos_attrib *da); -int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns, - struct inode *inode); -int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns, - struct inode *inode, - struct inode *parent_inode); -#endif /* __KSMBD_VFS_H__ */ diff --git a/fs/ksmbd/vfs_cache.c b/fs/ksmbd/vfs_cache.c deleted file mode 100644 index 0ae5dd0829e9..000000000000 --- a/fs/ksmbd/vfs_cache.c +++ /dev/null @@ -1,708 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> - * Copyright (C) 2019 Samsung Electronics Co., Ltd. - */ - -#include <linux/fs.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> - -#include "glob.h" -#include "vfs_cache.h" -#include "oplock.h" -#include "vfs.h" -#include "connection.h" -#include "mgmt/tree_connect.h" -#include "mgmt/user_session.h" -#include "smb_common.h" - -#define S_DEL_PENDING 1 -#define S_DEL_ON_CLS 2 -#define S_DEL_ON_CLS_STREAM 8 - -static unsigned int inode_hash_mask __read_mostly; -static unsigned int inode_hash_shift __read_mostly; -static struct hlist_head *inode_hashtable __read_mostly; -static DEFINE_RWLOCK(inode_hash_lock); - -static struct ksmbd_file_table global_ft; -static atomic_long_t fd_limit; -static struct kmem_cache *filp_cache; - -void ksmbd_set_fd_limit(unsigned long limit) -{ - limit = min(limit, get_max_files()); - atomic_long_set(&fd_limit, limit); -} - -static bool fd_limit_depleted(void) -{ - long v = atomic_long_dec_return(&fd_limit); - - if (v >= 0) - return false; - atomic_long_inc(&fd_limit); - return true; -} - -static void fd_limit_close(void) -{ - atomic_long_inc(&fd_limit); -} - -/* - * INODE hash - */ - -static unsigned long inode_hash(struct super_block *sb, unsigned long hashval) -{ - unsigned long tmp; - - tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) / - L1_CACHE_BYTES; - tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> inode_hash_shift); - return tmp & inode_hash_mask; -} - -static struct ksmbd_inode *__ksmbd_inode_lookup(struct inode *inode) -{ - struct hlist_head *head = inode_hashtable + - inode_hash(inode->i_sb, inode->i_ino); - struct ksmbd_inode *ci = NULL, *ret_ci = NULL; - - hlist_for_each_entry(ci, head, m_hash) { - if (ci->m_inode == inode) { - if (atomic_inc_not_zero(&ci->m_count)) - ret_ci = ci; - break; - } - } - return ret_ci; -} - -static struct ksmbd_inode *ksmbd_inode_lookup(struct ksmbd_file *fp) -{ - return __ksmbd_inode_lookup(file_inode(fp->filp)); -} - -static struct ksmbd_inode *ksmbd_inode_lookup_by_vfsinode(struct inode *inode) -{ - struct ksmbd_inode *ci; - - read_lock(&inode_hash_lock); - ci = __ksmbd_inode_lookup(inode); - read_unlock(&inode_hash_lock); - return ci; -} - -int ksmbd_query_inode_status(struct inode *inode) -{ - struct ksmbd_inode *ci; - int ret = KSMBD_INODE_STATUS_UNKNOWN; - - read_lock(&inode_hash_lock); - ci = __ksmbd_inode_lookup(inode); - if (ci) { - ret = KSMBD_INODE_STATUS_OK; - if (ci->m_flags & S_DEL_PENDING) - ret = KSMBD_INODE_STATUS_PENDING_DELETE; - atomic_dec(&ci->m_count); - } - read_unlock(&inode_hash_lock); - return ret; -} - -bool ksmbd_inode_pending_delete(struct ksmbd_file *fp) -{ - return (fp->f_ci->m_flags & S_DEL_PENDING); -} - -void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp) -{ - fp->f_ci->m_flags |= S_DEL_PENDING; -} - -void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp) -{ - fp->f_ci->m_flags &= ~S_DEL_PENDING; -} - -void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp, - int file_info) -{ - if (ksmbd_stream_fd(fp)) { - fp->f_ci->m_flags |= S_DEL_ON_CLS_STREAM; - return; - } - - fp->f_ci->m_flags |= S_DEL_ON_CLS; -} - -static void ksmbd_inode_hash(struct ksmbd_inode *ci) -{ - struct hlist_head *b = inode_hashtable + - inode_hash(ci->m_inode->i_sb, ci->m_inode->i_ino); - - hlist_add_head(&ci->m_hash, b); -} - -static void ksmbd_inode_unhash(struct ksmbd_inode *ci) -{ - write_lock(&inode_hash_lock); - hlist_del_init(&ci->m_hash); - write_unlock(&inode_hash_lock); -} - -static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp) -{ - ci->m_inode = file_inode(fp->filp); - atomic_set(&ci->m_count, 1); - atomic_set(&ci->op_count, 0); - atomic_set(&ci->sop_count, 0); - ci->m_flags = 0; - ci->m_fattr = 0; - INIT_LIST_HEAD(&ci->m_fp_list); - INIT_LIST_HEAD(&ci->m_op_list); - rwlock_init(&ci->m_lock); - return 0; -} - -static struct ksmbd_inode *ksmbd_inode_get(struct ksmbd_file *fp) -{ - struct ksmbd_inode *ci, *tmpci; - int rc; - - read_lock(&inode_hash_lock); - ci = ksmbd_inode_lookup(fp); - read_unlock(&inode_hash_lock); - if (ci) - return ci; - - ci = kmalloc(sizeof(struct ksmbd_inode), GFP_KERNEL); - if (!ci) - return NULL; - - rc = ksmbd_inode_init(ci, fp); - if (rc) { - pr_err("inode initialized failed\n"); - kfree(ci); - return NULL; - } - - write_lock(&inode_hash_lock); - tmpci = ksmbd_inode_lookup(fp); - if (!tmpci) { - ksmbd_inode_hash(ci); - } else { - kfree(ci); - ci = tmpci; - } - write_unlock(&inode_hash_lock); - return ci; -} - -static void ksmbd_inode_free(struct ksmbd_inode *ci) -{ - ksmbd_inode_unhash(ci); - kfree(ci); -} - -static void ksmbd_inode_put(struct ksmbd_inode *ci) -{ - if (atomic_dec_and_test(&ci->m_count)) - ksmbd_inode_free(ci); -} - -int __init ksmbd_inode_hash_init(void) -{ - unsigned int loop; - unsigned long numentries = 16384; - unsigned long bucketsize = sizeof(struct hlist_head); - unsigned long size; - - inode_hash_shift = ilog2(numentries); - inode_hash_mask = (1 << inode_hash_shift) - 1; - - size = bucketsize << inode_hash_shift; - - /* init master fp hash table */ - inode_hashtable = vmalloc(size); - if (!inode_hashtable) - return -ENOMEM; - - for (loop = 0; loop < (1U << inode_hash_shift); loop++) - INIT_HLIST_HEAD(&inode_hashtable[loop]); - return 0; -} - -void ksmbd_release_inode_hash(void) -{ - vfree(inode_hashtable); -} - -static void __ksmbd_inode_close(struct ksmbd_file *fp) -{ - struct dentry *dir, *dentry; - struct ksmbd_inode *ci = fp->f_ci; - int err; - struct file *filp; - - filp = fp->filp; - if (ksmbd_stream_fd(fp) && (ci->m_flags & S_DEL_ON_CLS_STREAM)) { - ci->m_flags &= ~S_DEL_ON_CLS_STREAM; - err = ksmbd_vfs_remove_xattr(file_mnt_user_ns(filp), - filp->f_path.dentry, - fp->stream.name); - if (err) - pr_err("remove xattr failed : %s\n", - fp->stream.name); - } - - if (atomic_dec_and_test(&ci->m_count)) { - write_lock(&ci->m_lock); - if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) { - dentry = filp->f_path.dentry; - dir = dentry->d_parent; - ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING); - write_unlock(&ci->m_lock); - ksmbd_vfs_unlink(file_mnt_user_ns(filp), dir, dentry); - write_lock(&ci->m_lock); - } - write_unlock(&ci->m_lock); - - ksmbd_inode_free(ci); - } -} - -static void __ksmbd_remove_durable_fd(struct ksmbd_file *fp) -{ - if (!has_file_id(fp->persistent_id)) - return; - - write_lock(&global_ft.lock); - idr_remove(global_ft.idr, fp->persistent_id); - write_unlock(&global_ft.lock); -} - -static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp) -{ - if (!has_file_id(fp->volatile_id)) - return; - - write_lock(&fp->f_ci->m_lock); - list_del_init(&fp->node); - write_unlock(&fp->f_ci->m_lock); - - write_lock(&ft->lock); - idr_remove(ft->idr, fp->volatile_id); - write_unlock(&ft->lock); -} - -static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp) -{ - struct file *filp; - struct ksmbd_lock *smb_lock, *tmp_lock; - - fd_limit_close(); - __ksmbd_remove_durable_fd(fp); - __ksmbd_remove_fd(ft, fp); - - close_id_del_oplock(fp); - filp = fp->filp; - - __ksmbd_inode_close(fp); - if (!IS_ERR_OR_NULL(filp)) - fput(filp); - - /* because the reference count of fp is 0, it is guaranteed that - * there are not accesses to fp->lock_list. - */ - list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) { - spin_lock(&fp->conn->llist_lock); - list_del(&smb_lock->clist); - spin_unlock(&fp->conn->llist_lock); - - list_del(&smb_lock->flist); - locks_free_lock(smb_lock->fl); - kfree(smb_lock); - } - - if (ksmbd_stream_fd(fp)) - kfree(fp->stream.name); - kmem_cache_free(filp_cache, fp); -} - -static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp) -{ - if (!atomic_inc_not_zero(&fp->refcount)) - return NULL; - return fp; -} - -static struct ksmbd_file *__ksmbd_lookup_fd(struct ksmbd_file_table *ft, - u64 id) -{ - struct ksmbd_file *fp; - - if (!has_file_id(id)) - return NULL; - - read_lock(&ft->lock); - fp = idr_find(ft->idr, id); - if (fp) - fp = ksmbd_fp_get(fp); - read_unlock(&ft->lock); - return fp; -} - -static void __put_fd_final(struct ksmbd_work *work, struct ksmbd_file *fp) -{ - __ksmbd_close_fd(&work->sess->file_table, fp); - atomic_dec(&work->conn->stats.open_files_count); -} - -static void set_close_state_blocked_works(struct ksmbd_file *fp) -{ - struct ksmbd_work *cancel_work; - - spin_lock(&fp->f_lock); - list_for_each_entry(cancel_work, &fp->blocked_works, - fp_entry) { - cancel_work->state = KSMBD_WORK_CLOSED; - cancel_work->cancel_fn(cancel_work->cancel_argv); - } - spin_unlock(&fp->f_lock); -} - -int ksmbd_close_fd(struct ksmbd_work *work, u64 id) -{ - struct ksmbd_file *fp; - struct ksmbd_file_table *ft; - - if (!has_file_id(id)) - return 0; - - ft = &work->sess->file_table; - read_lock(&ft->lock); - fp = idr_find(ft->idr, id); - if (fp) { - set_close_state_blocked_works(fp); - - if (!atomic_dec_and_test(&fp->refcount)) - fp = NULL; - } - read_unlock(&ft->lock); - - if (!fp) - return -EINVAL; - - __put_fd_final(work, fp); - return 0; -} - -void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp) -{ - if (!fp) - return; - - if (!atomic_dec_and_test(&fp->refcount)) - return; - __put_fd_final(work, fp); -} - -static bool __sanity_check(struct ksmbd_tree_connect *tcon, struct ksmbd_file *fp) -{ - if (!fp) - return false; - if (fp->tcon != tcon) - return false; - return true; -} - -struct ksmbd_file *ksmbd_lookup_foreign_fd(struct ksmbd_work *work, u64 id) -{ - return __ksmbd_lookup_fd(&work->sess->file_table, id); -} - -struct ksmbd_file *ksmbd_lookup_fd_fast(struct ksmbd_work *work, u64 id) -{ - struct ksmbd_file *fp = __ksmbd_lookup_fd(&work->sess->file_table, id); - - if (__sanity_check(work->tcon, fp)) - return fp; - - ksmbd_fd_put(work, fp); - return NULL; -} - -struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id, - u64 pid) -{ - struct ksmbd_file *fp; - - if (!has_file_id(id)) { - id = work->compound_fid; - pid = work->compound_pfid; - } - - fp = __ksmbd_lookup_fd(&work->sess->file_table, id); - if (!__sanity_check(work->tcon, fp)) { - ksmbd_fd_put(work, fp); - return NULL; - } - if (fp->persistent_id != pid) { - ksmbd_fd_put(work, fp); - return NULL; - } - return fp; -} - -struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id) -{ - return __ksmbd_lookup_fd(&global_ft, id); -} - -struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid) -{ - struct ksmbd_file *fp = NULL; - unsigned int id; - - read_lock(&global_ft.lock); - idr_for_each_entry(global_ft.idr, fp, id) { - if (!memcmp(fp->create_guid, - cguid, - SMB2_CREATE_GUID_SIZE)) { - fp = ksmbd_fp_get(fp); - break; - } - } - read_unlock(&global_ft.lock); - - return fp; -} - -struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode) -{ - struct ksmbd_file *lfp; - struct ksmbd_inode *ci; - - ci = ksmbd_inode_lookup_by_vfsinode(inode); - if (!ci) - return NULL; - - read_lock(&ci->m_lock); - list_for_each_entry(lfp, &ci->m_fp_list, node) { - if (inode == file_inode(lfp->filp)) { - atomic_dec(&ci->m_count); - lfp = ksmbd_fp_get(lfp); - read_unlock(&ci->m_lock); - return lfp; - } - } - atomic_dec(&ci->m_count); - read_unlock(&ci->m_lock); - return NULL; -} - -#define OPEN_ID_TYPE_VOLATILE_ID (0) -#define OPEN_ID_TYPE_PERSISTENT_ID (1) - -static void __open_id_set(struct ksmbd_file *fp, u64 id, int type) -{ - if (type == OPEN_ID_TYPE_VOLATILE_ID) - fp->volatile_id = id; - if (type == OPEN_ID_TYPE_PERSISTENT_ID) - fp->persistent_id = id; -} - -static int __open_id(struct ksmbd_file_table *ft, struct ksmbd_file *fp, - int type) -{ - u64 id = 0; - int ret; - - if (type == OPEN_ID_TYPE_VOLATILE_ID && fd_limit_depleted()) { - __open_id_set(fp, KSMBD_NO_FID, type); - return -EMFILE; - } - - idr_preload(GFP_KERNEL); - write_lock(&ft->lock); - ret = idr_alloc_cyclic(ft->idr, fp, 0, INT_MAX - 1, GFP_NOWAIT); - if (ret >= 0) { - id = ret; - ret = 0; - } else { - id = KSMBD_NO_FID; - fd_limit_close(); - } - - __open_id_set(fp, id, type); - write_unlock(&ft->lock); - idr_preload_end(); - return ret; -} - -unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp) -{ - __open_id(&global_ft, fp, OPEN_ID_TYPE_PERSISTENT_ID); - return fp->persistent_id; -} - -struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp) -{ - struct ksmbd_file *fp; - int ret; - - fp = kmem_cache_zalloc(filp_cache, GFP_KERNEL); - if (!fp) { - pr_err("Failed to allocate memory\n"); - return ERR_PTR(-ENOMEM); - } - - INIT_LIST_HEAD(&fp->blocked_works); - INIT_LIST_HEAD(&fp->node); - INIT_LIST_HEAD(&fp->lock_list); - spin_lock_init(&fp->f_lock); - atomic_set(&fp->refcount, 1); - - fp->filp = filp; - fp->conn = work->conn; - fp->tcon = work->tcon; - fp->volatile_id = KSMBD_NO_FID; - fp->persistent_id = KSMBD_NO_FID; - fp->f_ci = ksmbd_inode_get(fp); - - if (!fp->f_ci) { - ret = -ENOMEM; - goto err_out; - } - - ret = __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID); - if (ret) { - ksmbd_inode_put(fp->f_ci); - goto err_out; - } - - atomic_inc(&work->conn->stats.open_files_count); - return fp; - -err_out: - kmem_cache_free(filp_cache, fp); - return ERR_PTR(ret); -} - -static int -__close_file_table_ids(struct ksmbd_file_table *ft, - struct ksmbd_tree_connect *tcon, - bool (*skip)(struct ksmbd_tree_connect *tcon, - struct ksmbd_file *fp)) -{ - unsigned int id; - struct ksmbd_file *fp; - int num = 0; - - idr_for_each_entry(ft->idr, fp, id) { - if (skip(tcon, fp)) - continue; - - set_close_state_blocked_works(fp); - - if (!atomic_dec_and_test(&fp->refcount)) - continue; - __ksmbd_close_fd(ft, fp); - num++; - } - return num; -} - -static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon, - struct ksmbd_file *fp) -{ - return fp->tcon != tcon; -} - -static bool session_fd_check(struct ksmbd_tree_connect *tcon, - struct ksmbd_file *fp) -{ - return false; -} - -void ksmbd_close_tree_conn_fds(struct ksmbd_work *work) -{ - int num = __close_file_table_ids(&work->sess->file_table, - work->tcon, - tree_conn_fd_check); - - atomic_sub(num, &work->conn->stats.open_files_count); -} - -void ksmbd_close_session_fds(struct ksmbd_work *work) -{ - int num = __close_file_table_ids(&work->sess->file_table, - work->tcon, - session_fd_check); - - atomic_sub(num, &work->conn->stats.open_files_count); -} - -int ksmbd_init_global_file_table(void) -{ - return ksmbd_init_file_table(&global_ft); -} - -void ksmbd_free_global_file_table(void) -{ - struct ksmbd_file *fp = NULL; - unsigned int id; - - idr_for_each_entry(global_ft.idr, fp, id) { - __ksmbd_remove_durable_fd(fp); - kmem_cache_free(filp_cache, fp); - } - - ksmbd_destroy_file_table(&global_ft); -} - -int ksmbd_init_file_table(struct ksmbd_file_table *ft) -{ - ft->idr = kzalloc(sizeof(struct idr), GFP_KERNEL); - if (!ft->idr) - return -ENOMEM; - - idr_init(ft->idr); - rwlock_init(&ft->lock); - return 0; -} - -void ksmbd_destroy_file_table(struct ksmbd_file_table *ft) -{ - if (!ft->idr) - return; - - __close_file_table_ids(ft, NULL, session_fd_check); - idr_destroy(ft->idr); - kfree(ft->idr); - ft->idr = NULL; -} - -int ksmbd_init_file_cache(void) -{ - filp_cache = kmem_cache_create("ksmbd_file_cache", - sizeof(struct ksmbd_file), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (!filp_cache) - goto out; - - return 0; - -out: - pr_err("failed to allocate file cache\n"); - return -ENOMEM; -} - -void ksmbd_exit_file_cache(void) -{ - kmem_cache_destroy(filp_cache); -} diff --git a/fs/ksmbd/vfs_cache.h b/fs/ksmbd/vfs_cache.h deleted file mode 100644 index fcb13413fa8d..000000000000 --- a/fs/ksmbd/vfs_cache.h +++ /dev/null @@ -1,166 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2019 Samsung Electronics Co., Ltd. - */ - -#ifndef __VFS_CACHE_H__ -#define __VFS_CACHE_H__ - -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/rwsem.h> -#include <linux/spinlock.h> -#include <linux/idr.h> -#include <linux/workqueue.h> - -#include "vfs.h" - -/* Windows style file permissions for extended response */ -#define FILE_GENERIC_ALL 0x1F01FF -#define FILE_GENERIC_READ 0x120089 -#define FILE_GENERIC_WRITE 0x120116 -#define FILE_GENERIC_EXECUTE 0X1200a0 - -#define KSMBD_START_FID 0 -#define KSMBD_NO_FID (INT_MAX) -#define SMB2_NO_FID (0xFFFFFFFFFFFFFFFFULL) - -struct ksmbd_conn; -struct ksmbd_session; - -struct ksmbd_lock { - struct file_lock *fl; - struct list_head clist; - struct list_head flist; - struct list_head llist; - unsigned int flags; - int cmd; - int zero_len; - unsigned long long start; - unsigned long long end; -}; - -struct stream { - char *name; - ssize_t size; -}; - -struct ksmbd_inode { - rwlock_t m_lock; - atomic_t m_count; - atomic_t op_count; - /* opinfo count for streams */ - atomic_t sop_count; - struct inode *m_inode; - unsigned int m_flags; - struct hlist_node m_hash; - struct list_head m_fp_list; - struct list_head m_op_list; - struct oplock_info *m_opinfo; - __le32 m_fattr; -}; - -struct ksmbd_file { - struct file *filp; - u64 persistent_id; - u64 volatile_id; - - spinlock_t f_lock; - - struct ksmbd_inode *f_ci; - struct ksmbd_inode *f_parent_ci; - struct oplock_info __rcu *f_opinfo; - struct ksmbd_conn *conn; - struct ksmbd_tree_connect *tcon; - - atomic_t refcount; - __le32 daccess; - __le32 saccess; - __le32 coption; - __le32 cdoption; - __u64 create_time; - __u64 itime; - - bool is_nt_open; - bool attrib_only; - - char client_guid[16]; - char create_guid[16]; - char app_instance_id[16]; - - struct stream stream; - struct list_head node; - struct list_head blocked_works; - struct list_head lock_list; - - int durable_timeout; - - /* if ls is happening on directory, below is valid*/ - struct ksmbd_readdir_data readdir_data; - int dot_dotdot[2]; -}; - -static inline void set_ctx_actor(struct dir_context *ctx, - filldir_t actor) -{ - ctx->actor = actor; -} - -#define KSMBD_NR_OPEN_DEFAULT BITS_PER_LONG - -struct ksmbd_file_table { - rwlock_t lock; - struct idr *idr; -}; - -static inline bool has_file_id(u64 id) -{ - return id < KSMBD_NO_FID; -} - -static inline bool ksmbd_stream_fd(struct ksmbd_file *fp) -{ - return fp->stream.name != NULL; -} - -int ksmbd_init_file_table(struct ksmbd_file_table *ft); -void ksmbd_destroy_file_table(struct ksmbd_file_table *ft); -int ksmbd_close_fd(struct ksmbd_work *work, u64 id); -struct ksmbd_file *ksmbd_lookup_fd_fast(struct ksmbd_work *work, u64 id); -struct ksmbd_file *ksmbd_lookup_foreign_fd(struct ksmbd_work *work, u64 id); -struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id, - u64 pid); -void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp); -struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id); -struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid); -struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode); -unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp); -struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp); -void ksmbd_close_tree_conn_fds(struct ksmbd_work *work); -void ksmbd_close_session_fds(struct ksmbd_work *work); -int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode); -int ksmbd_init_global_file_table(void); -void ksmbd_free_global_file_table(void); -void ksmbd_set_fd_limit(unsigned long limit); - -/* - * INODE hash - */ -int __init ksmbd_inode_hash_init(void); -void ksmbd_release_inode_hash(void); - -enum KSMBD_INODE_STATUS { - KSMBD_INODE_STATUS_OK, - KSMBD_INODE_STATUS_UNKNOWN, - KSMBD_INODE_STATUS_PENDING_DELETE, -}; - -int ksmbd_query_inode_status(struct inode *inode); -bool ksmbd_inode_pending_delete(struct ksmbd_file *fp); -void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp); -void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp); -void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp, - int file_info); -int ksmbd_init_file_cache(void); -void ksmbd_exit_file_cache(void); -#endif /* __VFS_CACHE_H__ */ diff --git a/fs/ksmbd/xattr.h b/fs/ksmbd/xattr.h deleted file mode 100644 index 16499ca5c82d..000000000000 --- a/fs/ksmbd/xattr.h +++ /dev/null @@ -1,122 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2021 Samsung Electronics Co., Ltd. - */ - -#ifndef __XATTR_H__ -#define __XATTR_H__ - -/* - * These are on-disk structures to store additional metadata into xattr to - * reproduce windows filesystem semantics. And they are encoded with NDR to - * compatible with samba's xattr meta format. The compatibility with samba - * is important because it can lose the information(file attribute, - * creation time, acls) about the existing files when switching between - * ksmbd and samba. - */ - -/* - * Dos attribute flags used for what variable is valid. - */ -enum { - XATTR_DOSINFO_ATTRIB = 0x00000001, - XATTR_DOSINFO_EA_SIZE = 0x00000002, - XATTR_DOSINFO_SIZE = 0x00000004, - XATTR_DOSINFO_ALLOC_SIZE = 0x00000008, - XATTR_DOSINFO_CREATE_TIME = 0x00000010, - XATTR_DOSINFO_CHANGE_TIME = 0x00000020, - XATTR_DOSINFO_ITIME = 0x00000040 -}; - -/* - * Dos attribute structure which is compatible with samba's one. - * Storing it into the xattr named "DOSATTRIB" separately from inode - * allows ksmbd to faithfully reproduce windows filesystem semantics - * on top of a POSIX filesystem. - */ -struct xattr_dos_attrib { - __u16 version; /* version 3 or version 4 */ - __u32 flags; /* valid flags */ - __u32 attr; /* Dos attribute */ - __u32 ea_size; /* EA size */ - __u64 size; - __u64 alloc_size; - __u64 create_time; /* File creation time */ - __u64 change_time; /* File change time */ - __u64 itime; /* Invented/Initial time */ -}; - -/* - * Enumeration is used for computing posix acl hash. - */ -enum { - SMB_ACL_TAG_INVALID = 0, - SMB_ACL_USER, - SMB_ACL_USER_OBJ, - SMB_ACL_GROUP, - SMB_ACL_GROUP_OBJ, - SMB_ACL_OTHER, - SMB_ACL_MASK -}; - -#define SMB_ACL_READ 4 -#define SMB_ACL_WRITE 2 -#define SMB_ACL_EXECUTE 1 - -struct xattr_acl_entry { - int type; - uid_t uid; - gid_t gid; - mode_t perm; -}; - -/* - * xattr_smb_acl structure is used for computing posix acl hash. - */ -struct xattr_smb_acl { - int count; - int next; - struct xattr_acl_entry entries[]; -}; - -/* 64bytes hash in xattr_ntacl is computed with sha256 */ -#define XATTR_SD_HASH_TYPE_SHA256 0x1 -#define XATTR_SD_HASH_SIZE 64 - -/* - * xattr_ntacl is used for storing ntacl and hashes. - * Hash is used for checking valid posix acl and ntacl in xattr. - */ -struct xattr_ntacl { - __u16 version; /* version 4*/ - void *sd_buf; - __u32 sd_size; - __u16 hash_type; /* hash type */ - __u8 desc[10]; /* posix_acl description */ - __u16 desc_len; - __u64 current_time; - __u8 hash[XATTR_SD_HASH_SIZE]; /* 64bytes hash for ntacl */ - __u8 posix_acl_hash[XATTR_SD_HASH_SIZE]; /* 64bytes hash for posix acl */ -}; - -/* DOS ATTRIBUITE XATTR PREFIX */ -#define DOS_ATTRIBUTE_PREFIX "DOSATTRIB" -#define DOS_ATTRIBUTE_PREFIX_LEN (sizeof(DOS_ATTRIBUTE_PREFIX) - 1) -#define XATTR_NAME_DOS_ATTRIBUTE (XATTR_USER_PREFIX DOS_ATTRIBUTE_PREFIX) -#define XATTR_NAME_DOS_ATTRIBUTE_LEN \ - (sizeof(XATTR_USER_PREFIX DOS_ATTRIBUTE_PREFIX) - 1) - -/* STREAM XATTR PREFIX */ -#define STREAM_PREFIX "DosStream." -#define STREAM_PREFIX_LEN (sizeof(STREAM_PREFIX) - 1) -#define XATTR_NAME_STREAM (XATTR_USER_PREFIX STREAM_PREFIX) -#define XATTR_NAME_STREAM_LEN (sizeof(XATTR_NAME_STREAM) - 1) - -/* SECURITY DESCRIPTOR(NTACL) XATTR PREFIX */ -#define SD_PREFIX "NTACL" -#define SD_PREFIX_LEN (sizeof(SD_PREFIX) - 1) -#define XATTR_NAME_SD (XATTR_SECURITY_PREFIX SD_PREFIX) -#define XATTR_NAME_SD_LEN \ - (sizeof(XATTR_SECURITY_PREFIX SD_PREFIX) - 1) - -#endif /* __XATTR_H__ */ |