root/fs/smb/client/fs_context.h
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 *   Copyright (C) 2020, Microsoft Corporation.
 *
 *   Author(s): Steve French <stfrench@microsoft.com>
 *              David Howells <dhowells@redhat.com>
 */

#ifndef _FS_CONTEXT_H
#define _FS_CONTEXT_H

#include "cifsglob.h"
#include <linux/parser.h>
#include <linux/fs_parser.h>

/* Log errors in fs_context (new mount api) but also in dmesg (old style) */
#define cifs_errorf(fc, fmt, ...)                       \
        do {                                            \
                errorf(fc, fmt, ## __VA_ARGS__);        \
                cifs_dbg(VFS, fmt, ## __VA_ARGS__);     \
        } while (0)

static inline size_t cifs_io_align(struct fs_context *fc,
                                   const char *name, size_t size)
{
        if (!size || !IS_ALIGNED(size, PAGE_SIZE)) {
                cifs_errorf(fc, "unaligned %s, making it a multiple of %lu bytes\n",
                            name, PAGE_SIZE);
                size = umax(round_down(size, PAGE_SIZE), PAGE_SIZE);
        }
        return size;
}

#define CIFS_ALIGN_WSIZE(_fc, _size) cifs_io_align(_fc, "wsize", _size)
#define CIFS_ALIGN_RSIZE(_fc, _size) cifs_io_align(_fc, "rsize", _size)
#define CIFS_ALIGN_BSIZE(_fc, _size) cifs_io_align(_fc, "bsize", _size)

enum smb_version {
        Smb_1 = 1,
        Smb_20,
        Smb_21,
        Smb_30,
        Smb_302,
        Smb_311,
        Smb_3any,
        Smb_default,
        Smb_version_err
};

enum {
        Opt_cache_loose,
        Opt_cache_strict,
        Opt_cache_none,
        Opt_cache_ro,
        Opt_cache_rw,
        Opt_cache_err
};

enum cifs_reparse_parm {
        Opt_reparse_default,
        Opt_reparse_none,
        Opt_reparse_nfs,
        Opt_reparse_wsl,
        Opt_reparse_err
};

enum cifs_symlink_parm {
        Opt_symlink_default,
        Opt_symlink_none,
        Opt_symlink_native,
        Opt_symlink_unix,
        Opt_symlink_mfsymlinks,
        Opt_symlink_sfu,
        Opt_symlink_nfs,
        Opt_symlink_wsl,
        Opt_symlink_err
};

enum cifs_sec_param {
        Opt_sec_krb5,
        Opt_sec_krb5i,
        Opt_sec_krb5p,
        Opt_sec_ntlmsspi,
        Opt_sec_ntlmssp,
        Opt_sec_ntlmv2,
        Opt_sec_ntlmv2i,
        Opt_sec_none,

        Opt_sec_err
};

enum cifs_upcall_target_param {
        Opt_upcall_target_mount,
        Opt_upcall_target_application,
        Opt_upcall_target_err
};

enum cifs_param {
        /* Mount options that take no arguments */
        Opt_user_xattr,
        Opt_forceuid,
        Opt_forcegid,
        Opt_noblocksend,
        Opt_noautotune,
        Opt_nolease,
        Opt_nosparse,
        Opt_hard,
        Opt_soft,
        Opt_perm,
        Opt_nodelete,
        Opt_mapposix,
        Opt_mapchars,
        Opt_nomapchars,
        Opt_sfu,
        Opt_nodfs,
        Opt_posixpaths,
        Opt_unix,
        Opt_nocase,
        Opt_brl,
        Opt_handlecache,
        Opt_forcemandatorylock,
        Opt_setuidfromacl,
        Opt_setuids,
        Opt_dynperm,
        Opt_intr,
        Opt_strictsync,
        Opt_serverino,
        Opt_rwpidforward,
        Opt_cifsacl,
        Opt_acl,
        Opt_locallease,
        Opt_sign,
        Opt_ignore_signature,
        Opt_seal,
        Opt_noac,
        Opt_fsc,
        Opt_mfsymlinks,
        Opt_multiuser,
        Opt_sloppy,
        Opt_nosharesock,
        Opt_persistent,
        Opt_resilient,
        Opt_tcp_nodelay,
        Opt_domainauto,
        Opt_rdma,
        Opt_modesid,
        Opt_rootfs,
        Opt_multichannel,
        Opt_compress,
        Opt_witness,
        Opt_is_upcall_target_mount,
        Opt_is_upcall_target_application,
        Opt_unicode,

        /* Mount options which take numeric value */
        Opt_backupuid,
        Opt_backupgid,
        Opt_uid,
        Opt_cruid,
        Opt_gid,
        Opt_port,
        Opt_file_mode,
        Opt_dirmode,
        Opt_min_enc_offload,
        Opt_retrans,
        Opt_blocksize,
        Opt_rasize,
        Opt_rsize,
        Opt_wsize,
        Opt_actimeo,
        Opt_acdirmax,
        Opt_acregmax,
        Opt_closetimeo,
        Opt_echo_interval,
        Opt_max_credits,
        Opt_max_cached_dirs,
        Opt_snapshot,
        Opt_max_channels,
        Opt_handletimeout,

        /* Mount options which take string value */
        Opt_source,
        Opt_user,
        Opt_pass,
        Opt_pass2,
        Opt_ip,
        Opt_domain,
        Opt_srcaddr,
        Opt_iocharset,
        Opt_netbiosname,
        Opt_servern,
        Opt_nbsessinit,
        Opt_ver,
        Opt_vers,
        Opt_sec,
        Opt_cache,
        Opt_reparse,
        Opt_upcalltarget,
        Opt_nativesocket,
        Opt_symlink,
        Opt_symlinkroot,

        /* Mount options to be ignored */
        Opt_ignore,

        Opt_err
};

struct smb3_fs_context {
        bool forceuid_specified;
        bool forcegid_specified;
        bool uid_specified;
        bool cruid_specified;
        bool gid_specified;
        bool sloppy;
        bool got_ip;
        bool got_version;
        bool got_rsize;
        bool got_wsize;
        bool got_bsize;
        unsigned short port;

        char *username;
        char *password;
        char *password2;
        char *domainname;
        char *source;
        char *server_hostname;
        char *UNC;
        char *nodename;
        char workstation_name[CIFS_MAX_WORKSTATION_LEN];
        char *iocharset;  /* local code page for mapping to and from Unicode */
        char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
        char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
        int rfc1001_sessinit;
        kuid_t cred_uid;
        kuid_t linux_uid;
        kgid_t linux_gid;
        kuid_t backupuid;
        kgid_t backupgid;
        umode_t file_mode;
        umode_t dir_mode;
        enum securityEnum sectype; /* sectype requested via mnt opts */
        enum upcall_target_enum upcall_target; /* where to upcall for mount */
        bool sign; /* was signing requested via mnt opts? */
        bool ignore_signature:1;
        bool retry:1;
        bool intr:1;
        bool setuids:1;
        bool setuidfromacl:1;
        bool override_uid:1;
        bool override_gid:1;
        bool dynperm:1;
        bool noperm:1;
        bool nodelete:1;
        bool mode_ace:1;
        bool no_psx_acl:1; /* set if posix acl support should be disabled */
        bool cifs_acl:1;
        bool backupuid_specified; /* mount option  backupuid  is specified */
        bool backupgid_specified; /* mount option  backupgid  is specified */
        bool no_xattr:1;   /* set if xattr (EA) support should be disabled*/
        bool server_ino:1; /* use inode numbers from server ie UniqueId */
        bool direct_io:1;
        bool strict_io:1; /* strict cache behavior */
        bool cache_ro:1;
        bool cache_rw:1;
        bool remap:1;      /* set to remap seven reserved chars in filenames */
        bool sfu_remap:1;  /* remap seven reserved chars ala SFU */
        bool posix_paths:1; /* unset to not ask for posix pathnames. */
        bool no_linux_ext:1;
        bool linux_ext:1;
        bool sfu_emul:1;
        bool nullauth:1;   /* attempt to authenticate with null user */
        bool nocase:1;     /* request case insensitive filenames */
        bool nobrl:1;      /* disable sending byte range locks to srv */
        bool nohandlecache:1; /* disable caching dir handles if srvr probs */
        bool mand_lock:1;  /* send mandatory not posix byte range lock reqs */
        bool seal:1;       /* request transport encryption on share */
        bool nodfs:1;      /* Do not request DFS, even if available */
        bool local_lease:1; /* check leases only on local system, not remote */
        bool noblocksnd:1;
        bool noautotune:1;
        bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
        bool no_lease:1;     /* disable requesting leases */
        bool no_sparse:1;    /* do not attempt to set files sparse */
        bool fsc:1;     /* enable fscache */
        bool mfsymlinks:1; /* use Minshall+French Symlinks */
        bool multiuser:1;
        bool rwpidforward:1; /* pid forward for read/write operations */
        bool nosharesock:1;
        bool persistent:1;
        bool nopersistent:1;
        bool resilient:1; /* noresilient not required since not fored for CA */
        bool domainauto:1;
        bool rdma:1;
        bool multichannel:1;
        bool multichannel_specified:1; /* true if user specified multichannel or nomultichannel */
        bool max_channels_specified:1; /* true if user specified max_channels */
        bool use_client_guid:1;
        /* reuse existing guid for multichannel */
        u8 client_guid[SMB2_CLIENT_GUID_SIZE];
        /* User-specified original r/wsize value */
        unsigned int vol_rsize;
        unsigned int vol_wsize;
        unsigned int bsize;
        unsigned int rasize;
        unsigned int rsize;
        unsigned int wsize;
        unsigned int min_offload;
        unsigned int retrans;
        bool sockopt_tcp_nodelay:1;
        /* attribute cache timeout for files and directories in jiffies */
        unsigned long acregmax;
        unsigned long acdirmax;
        /* timeout for deferred close of files in jiffies */
        unsigned long closetimeo;
        struct smb_version_operations *ops;
        struct smb_version_values *vals;
        char *prepath;
        struct sockaddr_storage dstaddr; /* destination address */
        struct sockaddr_storage srcaddr; /* allow binding to a local IP */
        struct nls_table *local_nls; /* This is a copy of the pointer in cifs_sb */
        unsigned int echo_interval; /* echo interval in secs */
        __u64 snapshot_time; /* needed for timewarp tokens */
        __u32 handle_timeout; /* persistent and durable handle timeout in ms */
        unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
        unsigned int max_channels;
        unsigned int max_cached_dirs;
        bool compress; /* enable SMB2 messages (READ/WRITE) de/compression */
        bool rootfs:1; /* if it's a SMB root file system */
        bool witness:1; /* use witness protocol */
        int unicode;
        char *leaf_fullpath;
        struct cifs_ses *dfs_root_ses;
        bool dfs_automount:1; /* set for dfs automount only */
        enum cifs_reparse_type reparse_type;
        enum cifs_symlink_type symlink_type;
        bool nonativesocket:1;
        bool dfs_conn:1; /* set for dfs mounts */
        char *dns_dom;
        char *symlinkroot; /* top level directory for native SMB symlinks in absolute format */
};

extern const struct fs_parameter_spec smb3_fs_parameters[];

static inline enum cifs_symlink_type cifs_symlink_type(struct cifs_sb_info *cifs_sb)
{
        bool posix = cifs_sb_master_tcon(cifs_sb)->posix_extensions;

        if (cifs_sb->ctx->symlink_type != CIFS_SYMLINK_TYPE_DEFAULT)
                return cifs_sb->ctx->symlink_type;

        if (cifs_sb->ctx->mfsymlinks)
                return CIFS_SYMLINK_TYPE_MFSYMLINKS;
        else if (cifs_sb->ctx->sfu_emul)
                return CIFS_SYMLINK_TYPE_SFU;
        else if (cifs_sb->ctx->linux_ext && !cifs_sb->ctx->no_linux_ext)
                return posix ? CIFS_SYMLINK_TYPE_NATIVE : CIFS_SYMLINK_TYPE_UNIX;
        else if (cifs_sb->ctx->reparse_type != CIFS_REPARSE_TYPE_NONE)
                return CIFS_SYMLINK_TYPE_NATIVE;
        return CIFS_SYMLINK_TYPE_NONE;
}

int smb3_init_fs_context(struct fs_context *fc);
void smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx);
void smb3_cleanup_fs_context(struct smb3_fs_context *ctx);

static inline struct smb3_fs_context *smb3_fc2context(const struct fs_context *fc)
{
        return fc->fs_private;
}

int smb3_fs_context_dup(struct smb3_fs_context *new_ctx,
                        struct smb3_fs_context *ctx);
int smb3_sync_session_ctx_passwords(struct cifs_sb_info *cifs_sb,
                                    struct cifs_ses *ses);
unsigned int smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);

/*
 * max deferred close timeout (jiffies) - 2^30
 */
#define SMB3_MAX_DCLOSETIMEO (1 << 30)
#define SMB3_DEF_DCLOSETIMEO (1 * HZ) /* even 1 sec enough to help eg open/write/close/open/read */
#define MAX_CACHED_FIDS 16
char *cifs_sanitize_prepath(char *prepath, gfp_t gfp);

extern struct mutex cifs_mount_mutex;

static inline void cifs_mount_lock(void)
{
        mutex_lock(&cifs_mount_mutex);
}

static inline void cifs_mount_unlock(void)
{
        mutex_unlock(&cifs_mount_mutex);
}

static inline void cifs_negotiate_rsize(struct TCP_Server_Info *server,
                                        struct smb3_fs_context *ctx,
                                        struct cifs_tcon *tcon)
{
        unsigned int size;

        size = umax(server->ops->negotiate_rsize(tcon, ctx), PAGE_SIZE);
        if (ctx->rsize)
                size = umax(umin(ctx->rsize, size), PAGE_SIZE);
        ctx->rsize = round_down(size, PAGE_SIZE);
}

static inline void cifs_negotiate_wsize(struct TCP_Server_Info *server,
                                        struct smb3_fs_context *ctx,
                                        struct cifs_tcon *tcon)
{
        unsigned int size;

        size = umax(server->ops->negotiate_wsize(tcon, ctx), PAGE_SIZE);
        if (ctx->wsize)
                size = umax(umin(ctx->wsize, size), PAGE_SIZE);
        ctx->wsize = round_down(size, PAGE_SIZE);
}

static inline void cifs_negotiate_iosize(struct TCP_Server_Info *server,
                                         struct smb3_fs_context *ctx,
                                         struct cifs_tcon *tcon)
{
        cifs_negotiate_rsize(server, ctx, tcon);
        cifs_negotiate_wsize(server, ctx, tcon);
}

#endif