Commit fb157ed2 authored by Steve French's avatar Steve French
Browse files

cifs: when insecure legacy is disabled shrink amount of SMB1 code



Currently much of the smb1 code is built even when
CONFIG_CIFS_ALLOW_INSECURE_LEGACY is disabled.

Move cifssmb.c to only be compiled when insecure legacy is disabled,
and move various SMB1/CIFS helper functions to that ifdef.  Some
functions that were not SMB1/CIFS specific needed to be moved out of
cifssmb.c

This shrinks cifs.ko by more than 10% which is good - but also will
help with the eventual movement of the legacy code to a distinct
module.  Follow on patches can shrink the number of ifdefs by
code restructuring where smb1 code is wedged in functions that
should be calling dialect specific helper functions instead,
and also by moving some functions from file.c/dir.c/inode.c into
smb1 specific c files.

Reviewed-by: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Reviewed-by: default avatarPaulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 97b82c07
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
ccflags-y += -I$(src)		# needed for trace events
obj-$(CONFIG_CIFS) += cifs.o

cifs-y := trace.o cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o \
cifs-y := trace.o cifsfs.o cifs_debug.o connect.o dir.o file.o \
	  inode.o link.o misc.o netmisc.o smbencrypt.o transport.o \
	  cifs_unicode.o nterr.o cifsencrypt.o \
	  readdir.o ioctl.o sess.o export.o unc.o winucase.o \
@@ -31,4 +31,4 @@ cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o

cifs-$(CONFIG_CIFS_ROOT) += cifsroot.o

cifs-$(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) += smb1ops.o
cifs-$(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) += smb1ops.o cifssmb.o
+2 −0
Original line number Diff line number Diff line
@@ -1379,6 +1379,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
	return rc;
}

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
				      const struct cifs_fid *cifsfid, u32 *pacllen,
				      u32 __maybe_unused unused)
@@ -1512,6 +1513,7 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
	cifs_put_tlink(tlink);
	return rc;
}
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */

/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
int
+2 −0
Original line number Diff line number Diff line
@@ -521,6 +521,7 @@ extern int generate_smb30signingkey(struct cifs_ses *ses,
extern int generate_smb311signingkey(struct cifs_ses *ses,
				     struct TCP_Server_Info *server);

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
extern int CIFSSMBCopy(unsigned int xid,
			struct cifs_tcon *source_tcon,
			const char *fromName,
@@ -551,6 +552,7 @@ extern int CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
		const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
			const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
#endif /* CIFS_ALLOW_INSECURE_LEGACY */
extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
extern bool couldbe_mf_symlink(const struct cifs_fattr *fattr);
extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+2 −451
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@
#include "cifsproto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "smb2proto.h"
#include "fscache.h"
#include "smbdirect.h"
#ifdef CONFIG_CIFS_DFS_UPCALL
@@ -62,52 +61,6 @@ static struct {
#define CIFS_NUM_PROT 1
#endif /* CIFS_POSIX */

/*
 * Mark as invalid, all open files on tree connections since they
 * were closed when session to server was lost.
 */
void
cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
{
	struct cifsFileInfo *open_file = NULL;
	struct list_head *tmp;
	struct list_head *tmp1;

	/* only send once per connect */
	spin_lock(&tcon->ses->ses_lock);
	if ((tcon->ses->ses_status != SES_GOOD) || (tcon->status != TID_NEED_RECON)) {
		spin_unlock(&tcon->ses->ses_lock);
		return;
	}
	tcon->status = TID_IN_FILES_INVALIDATE;
	spin_unlock(&tcon->ses->ses_lock);

	/* list all files open on tree connection and mark them invalid */
	spin_lock(&tcon->open_file_lock);
	list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
		open_file = list_entry(tmp, struct cifsFileInfo, tlist);
		open_file->invalidHandle = true;
		open_file->oplock_break_cancelled = true;
	}
	spin_unlock(&tcon->open_file_lock);

	mutex_lock(&tcon->crfid.fid_mutex);
	tcon->crfid.is_valid = false;
	/* cached handle is not valid, so SMB2_CLOSE won't be sent below */
	close_cached_dir_lease_locked(&tcon->crfid);
	memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
	mutex_unlock(&tcon->crfid.fid_mutex);

	spin_lock(&tcon->tc_lock);
	if (tcon->status == TID_IN_FILES_INVALIDATE)
		tcon->status = TID_NEED_TCON;
	spin_unlock(&tcon->tc_lock);

	/*
	 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
	 * to this tcon.
	 */
}

/* reconnect the socket, tcon, and smb session if needed */
static int
@@ -457,52 +410,6 @@ decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
	return 0;
}

int
cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
{
	bool srv_sign_required = server->sec_mode & server->vals->signing_required;
	bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
	bool mnt_sign_enabled;

	/*
	 * Is signing required by mnt options? If not then check
	 * global_secflags to see if it is there.
	 */
	if (!mnt_sign_required)
		mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
						CIFSSEC_MUST_SIGN);

	/*
	 * If signing is required then it's automatically enabled too,
	 * otherwise, check to see if the secflags allow it.
	 */
	mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
				(global_secflags & CIFSSEC_MAY_SIGN);

	/* If server requires signing, does client allow it? */
	if (srv_sign_required) {
		if (!mnt_sign_enabled) {
			cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!\n");
			return -ENOTSUPP;
		}
		server->sign = true;
	}

	/* If client requires signing, does server allow it? */
	if (mnt_sign_required) {
		if (!srv_sign_enabled) {
			cifs_dbg(VFS, "Server does not support signing!\n");
			return -ENOTSUPP;
		}
		server->sign = true;
	}

	if (cifs_rdma_enabled(server) && server->sign)
		cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled\n");

	return 0;
}

static bool
should_set_ext_sec_flag(enum securityEnum sectype)
{
@@ -1379,184 +1286,6 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
	return rc;
}

/*
 * Discard any remaining data in the current SMB. To do this, we borrow the
 * current bigbuf.
 */
int
cifs_discard_remaining_data(struct TCP_Server_Info *server)
{
	unsigned int rfclen = server->pdu_size;
	int remaining = rfclen + server->vals->header_preamble_size -
		server->total_read;

	while (remaining > 0) {
		int length;

		length = cifs_discard_from_socket(server,
				min_t(size_t, remaining,
				      CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
		if (length < 0)
			return length;
		server->total_read += length;
		remaining -= length;
	}

	return 0;
}

static int
__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
		     bool malformed)
{
	int length;

	length = cifs_discard_remaining_data(server);
	dequeue_mid(mid, malformed);
	mid->resp_buf = server->smallbuf;
	server->smallbuf = NULL;
	return length;
}

static int
cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
	struct cifs_readdata *rdata = mid->callback_data;

	return  __cifs_readv_discard(server, mid, rdata->result);
}

int
cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
	int length, len;
	unsigned int data_offset, data_len;
	struct cifs_readdata *rdata = mid->callback_data;
	char *buf = server->smallbuf;
	unsigned int buflen = server->pdu_size +
		server->vals->header_preamble_size;
	bool use_rdma_mr = false;

	cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
		 __func__, mid->mid, rdata->offset, rdata->bytes);

	/*
	 * read the rest of READ_RSP header (sans Data array), or whatever we
	 * can if there's not enough data. At this point, we've read down to
	 * the Mid.
	 */
	len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
							HEADER_SIZE(server) + 1;

	length = cifs_read_from_socket(server,
				       buf + HEADER_SIZE(server) - 1, len);
	if (length < 0)
		return length;
	server->total_read += length;

	if (server->ops->is_session_expired &&
	    server->ops->is_session_expired(buf)) {
		cifs_reconnect(server, true);
		return -1;
	}

	if (server->ops->is_status_pending &&
	    server->ops->is_status_pending(buf, server)) {
		cifs_discard_remaining_data(server);
		return -1;
	}

	/* set up first two iov for signature check and to get credits */
	rdata->iov[0].iov_base = buf;
	rdata->iov[0].iov_len = server->vals->header_preamble_size;
	rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
	rdata->iov[1].iov_len =
		server->total_read - server->vals->header_preamble_size;
	cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
		 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
	cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
		 rdata->iov[1].iov_base, rdata->iov[1].iov_len);

	/* Was the SMB read successful? */
	rdata->result = server->ops->map_error(buf, false);
	if (rdata->result != 0) {
		cifs_dbg(FYI, "%s: server returned error %d\n",
			 __func__, rdata->result);
		/* normal error on read response */
		return __cifs_readv_discard(server, mid, false);
	}

	/* Is there enough to get to the rest of the READ_RSP header? */
	if (server->total_read < server->vals->read_rsp_size) {
		cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
			 __func__, server->total_read,
			 server->vals->read_rsp_size);
		rdata->result = -EIO;
		return cifs_readv_discard(server, mid);
	}

	data_offset = server->ops->read_data_offset(buf) +
		server->vals->header_preamble_size;
	if (data_offset < server->total_read) {
		/*
		 * win2k8 sometimes sends an offset of 0 when the read
		 * is beyond the EOF. Treat it as if the data starts just after
		 * the header.
		 */
		cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
			 __func__, data_offset);
		data_offset = server->total_read;
	} else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
		/* data_offset is beyond the end of smallbuf */
		cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
			 __func__, data_offset);
		rdata->result = -EIO;
		return cifs_readv_discard(server, mid);
	}

	cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
		 __func__, server->total_read, data_offset);

	len = data_offset - server->total_read;
	if (len > 0) {
		/* read any junk before data into the rest of smallbuf */
		length = cifs_read_from_socket(server,
					       buf + server->total_read, len);
		if (length < 0)
			return length;
		server->total_read += length;
	}

	/* how much data is in the response? */
#ifdef CONFIG_CIFS_SMB_DIRECT
	use_rdma_mr = rdata->mr;
#endif
	data_len = server->ops->read_data_length(buf, use_rdma_mr);
	if (!use_rdma_mr && (data_offset + data_len > buflen)) {
		/* data_len is corrupt -- discard frame */
		rdata->result = -EIO;
		return cifs_readv_discard(server, mid);
	}

	length = rdata->read_into_pages(server, rdata, data_len);
	if (length < 0)
		return length;

	server->total_read += length;

	cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
		 server->total_read, buflen, data_len);

	/* discard anything left over */
	if (server->total_read < buflen)
		return cifs_readv_discard(server, mid);

	dequeue_mid(mid, false);
	mid->resp_buf = server->smallbuf;
	server->smallbuf = NULL;
	return length;
}

static void
cifs_readv_callback(struct mid_q_entry *mid)
{
@@ -1909,183 +1638,6 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
	return rc;
}

void
cifs_writedata_release(struct kref *refcount)
{
	struct cifs_writedata *wdata = container_of(refcount,
					struct cifs_writedata, refcount);
#ifdef CONFIG_CIFS_SMB_DIRECT
	if (wdata->mr) {
		smbd_deregister_mr(wdata->mr);
		wdata->mr = NULL;
	}
#endif

	if (wdata->cfile)
		cifsFileInfo_put(wdata->cfile);

	kvfree(wdata->pages);
	kfree(wdata);
}

/*
 * Write failed with a retryable error. Resend the write request. It's also
 * possible that the page was redirtied so re-clean the page.
 */
static void
cifs_writev_requeue(struct cifs_writedata *wdata)
{
	int i, rc = 0;
	struct inode *inode = d_inode(wdata->cfile->dentry);
	struct TCP_Server_Info *server;
	unsigned int rest_len;

	server = tlink_tcon(wdata->cfile->tlink)->ses->server;
	i = 0;
	rest_len = wdata->bytes;
	do {
		struct cifs_writedata *wdata2;
		unsigned int j, nr_pages, wsize, tailsz, cur_len;

		wsize = server->ops->wp_retry_size(inode);
		if (wsize < rest_len) {
			nr_pages = wsize / PAGE_SIZE;
			if (!nr_pages) {
				rc = -ENOTSUPP;
				break;
			}
			cur_len = nr_pages * PAGE_SIZE;
			tailsz = PAGE_SIZE;
		} else {
			nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
			cur_len = rest_len;
			tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
		}

		wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
		if (!wdata2) {
			rc = -ENOMEM;
			break;
		}

		for (j = 0; j < nr_pages; j++) {
			wdata2->pages[j] = wdata->pages[i + j];
			lock_page(wdata2->pages[j]);
			clear_page_dirty_for_io(wdata2->pages[j]);
		}

		wdata2->sync_mode = wdata->sync_mode;
		wdata2->nr_pages = nr_pages;
		wdata2->offset = page_offset(wdata2->pages[0]);
		wdata2->pagesz = PAGE_SIZE;
		wdata2->tailsz = tailsz;
		wdata2->bytes = cur_len;

		rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY,
					    &wdata2->cfile);
		if (!wdata2->cfile) {
			cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
				 rc);
			if (!is_retryable_error(rc))
				rc = -EBADF;
		} else {
			wdata2->pid = wdata2->cfile->pid;
			rc = server->ops->async_writev(wdata2,
						       cifs_writedata_release);
		}

		for (j = 0; j < nr_pages; j++) {
			unlock_page(wdata2->pages[j]);
			if (rc != 0 && !is_retryable_error(rc)) {
				SetPageError(wdata2->pages[j]);
				end_page_writeback(wdata2->pages[j]);
				put_page(wdata2->pages[j]);
			}
		}

		kref_put(&wdata2->refcount, cifs_writedata_release);
		if (rc) {
			if (is_retryable_error(rc))
				continue;
			i += nr_pages;
			break;
		}

		rest_len -= cur_len;
		i += nr_pages;
	} while (i < wdata->nr_pages);

	/* cleanup remaining pages from the original wdata */
	for (; i < wdata->nr_pages; i++) {
		SetPageError(wdata->pages[i]);
		end_page_writeback(wdata->pages[i]);
		put_page(wdata->pages[i]);
	}

	if (rc != 0 && !is_retryable_error(rc))
		mapping_set_error(inode->i_mapping, rc);
	kref_put(&wdata->refcount, cifs_writedata_release);
}

void
cifs_writev_complete(struct work_struct *work)
{
	struct cifs_writedata *wdata = container_of(work,
						struct cifs_writedata, work);
	struct inode *inode = d_inode(wdata->cfile->dentry);
	int i = 0;

	if (wdata->result == 0) {
		spin_lock(&inode->i_lock);
		cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
		spin_unlock(&inode->i_lock);
		cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
					 wdata->bytes);
	} else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
		return cifs_writev_requeue(wdata);

	for (i = 0; i < wdata->nr_pages; i++) {
		struct page *page = wdata->pages[i];
		if (wdata->result == -EAGAIN)
			__set_page_dirty_nobuffers(page);
		else if (wdata->result < 0)
			SetPageError(page);
		end_page_writeback(page);
		cifs_readpage_to_fscache(inode, page);
		put_page(page);
	}
	if (wdata->result != -EAGAIN)
		mapping_set_error(inode->i_mapping, wdata->result);
	kref_put(&wdata->refcount, cifs_writedata_release);
}

struct cifs_writedata *
cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
{
	struct page **pages =
		kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
	if (pages)
		return cifs_writedata_direct_alloc(pages, complete);

	return NULL;
}

struct cifs_writedata *
cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
{
	struct cifs_writedata *wdata;

	wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
	if (wdata != NULL) {
		wdata->pages = pages;
		kref_init(&wdata->refcount);
		INIT_LIST_HEAD(&wdata->list);
		init_completion(&wdata->done);
		INIT_WORK(&wdata->work, complete);
	}
	return wdata;
}

/*
 * Check the mid_state and signature on received buffer (if any), and queue the
 * workqueue completion task.
@@ -3660,7 +3212,6 @@ CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
	return rc;
}

/* BB fix tabs in this function FIXME BB */
int
CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
	       const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
@@ -3723,7 +3274,7 @@ CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
			struct file_chattr_info *pfinfo;
			/* BB Do we need a cast or hash here ? */

			if (count != 16) {
				cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
				rc = -EIO;
+53 −0
Original line number Diff line number Diff line
@@ -898,6 +898,53 @@ handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
	dequeue_mid(mid, malformed);
}

int
cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
{
	bool srv_sign_required = server->sec_mode & server->vals->signing_required;
	bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
	bool mnt_sign_enabled;

	/*
	 * Is signing required by mnt options? If not then check
	 * global_secflags to see if it is there.
	 */
	if (!mnt_sign_required)
		mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
						CIFSSEC_MUST_SIGN);

	/*
	 * If signing is required then it's automatically enabled too,
	 * otherwise, check to see if the secflags allow it.
	 */
	mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
				(global_secflags & CIFSSEC_MAY_SIGN);

	/* If server requires signing, does client allow it? */
	if (srv_sign_required) {
		if (!mnt_sign_enabled) {
			cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!\n");
			return -EOPNOTSUPP;
		}
		server->sign = true;
	}

	/* If client requires signing, does server allow it? */
	if (mnt_sign_required) {
		if (!srv_sign_enabled) {
			cifs_dbg(VFS, "Server does not support signing!\n");
			return -EOPNOTSUPP;
		}
		server->sign = true;
	}

	if (cifs_rdma_enabled(server) && server->sign)
		cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled\n");

	return 0;
}


static void clean_demultiplex_info(struct TCP_Server_Info *server)
{
	int length;
@@ -2976,6 +3023,7 @@ ip_connect(struct TCP_Server_Info *server)
	return generic_ip_connect(server);
}

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
			  struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
{
@@ -3081,6 +3129,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
		}
	}
}
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */

int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb)
{
@@ -3197,6 +3246,7 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx)
	if (tcon->posix_extensions)
		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
	/* tell server which Unix caps we support */
	if (cap_unix(tcon->ses)) {
		/*
@@ -3214,6 +3264,7 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx)
		}
		spin_unlock(&tcon->ses->server->srv_lock);
	} else
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
		tcon->unix_ext = 0; /* server does not support them */

	/* do not care if a following call succeed - informational */
@@ -4189,8 +4240,10 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
		goto out;
	}

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
	if (cap_unix(ses))
		reset_cifs_unix_caps(0, tcon, NULL, ctx);
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */

out:
	kfree(ctx->username);
Loading