Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0f44bc36 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
 "A set of cifs fixes (mostly for symlinks, and SMB2 xattrs) and
  cleanups"

* 'for-linus' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: Fix check for regular file in couldbe_mf_symlink()
  [CIFS] Fix SMB2 mounts so they don't try to set or get xattrs via cifs
  CIFS: Cleanup cifs open codepath
  CIFS: Remove extra indentation in cifs_sfu_type
  CIFS: Cleanup cifs_mknod
  CIFS: Cleanup CIFSSMBOpen
  cifs: Add support for follow_link on dfs shares under posix extensions
  cifs: move unix extension call to cifs_query_symlink()
  cifs: Re-order M-F Symlink code
  cifs: Add create MFSymlinks to protocol ops struct
  cifs: use protocol specific call for query_mf_symlink()
  cifs: Rename MF symlink function names
  cifs: Rename and cleanup open_query_close_cifs_symlink()
  cifs: Fix memory leak in cifs_hardlink()
parents efc518eb a9a315d4
Loading
Loading
Loading
Loading
+28 −12
Original line number Diff line number Diff line
@@ -895,9 +895,10 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
	int oplock = 0;
	unsigned int xid;
	int rc, create_options = 0;
	__u16 fid;
	struct cifs_tcon *tcon;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
	struct cifs_fid fid;
	struct cifs_open_parms oparms;

	if (IS_ERR(tlink))
		return ERR_CAST(tlink);
@@ -908,12 +909,19 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
	if (backup_cred(cifs_sb))
		create_options |= CREATE_OPEN_BACKUP_INTENT;

	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
			create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
	oparms.tcon = tcon;
	oparms.cifs_sb = cifs_sb;
	oparms.desired_access = READ_CONTROL;
	oparms.create_options = create_options;
	oparms.disposition = FILE_OPEN;
	oparms.path = path;
	oparms.fid = &fid;
	oparms.reconnect = false;

	rc = CIFS_open(xid, &oparms, &oplock, NULL);
	if (!rc) {
		rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
		CIFSSMBClose(xid, tcon, fid);
		rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
		CIFSSMBClose(xid, tcon, fid.netfid);
	}

	cifs_put_tlink(tlink);
@@ -950,10 +958,11 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
	int oplock = 0;
	unsigned int xid;
	int rc, access_flags, create_options = 0;
	__u16 fid;
	struct cifs_tcon *tcon;
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
	struct cifs_fid fid;
	struct cifs_open_parms oparms;

	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
@@ -969,18 +978,25 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
	else
		access_flags = WRITE_DAC;

	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
			create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
	oparms.tcon = tcon;
	oparms.cifs_sb = cifs_sb;
	oparms.desired_access = access_flags;
	oparms.create_options = create_options;
	oparms.disposition = FILE_OPEN;
	oparms.path = path;
	oparms.fid = &fid;
	oparms.reconnect = false;

	rc = CIFS_open(xid, &oparms, &oplock, NULL);
	if (rc) {
		cifs_dbg(VFS, "Unable to open file to set ACL\n");
		goto out;
	}

	rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
	rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
	cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);

	CIFSSMBClose(xid, tcon, fid);
	CIFSSMBClose(xid, tcon, fid.netfid);
out:
	free_xid(xid);
	cifs_put_tlink(tlink);
+12 −2
Original line number Diff line number Diff line
@@ -370,8 +370,12 @@ struct smb_version_operations {
	void (*new_lease_key)(struct cifs_fid *);
	int (*generate_signingkey)(struct cifs_ses *);
	int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *);
	int (*query_mf_symlink)(const unsigned char *, char *, unsigned int *,
				struct cifs_sb_info *, unsigned int);
	int (*query_mf_symlink)(unsigned int, struct cifs_tcon *,
				struct cifs_sb_info *, const unsigned char *,
				char *, unsigned int *);
	int (*create_mf_symlink)(unsigned int, struct cifs_tcon *,
				 struct cifs_sb_info *, const unsigned char *,
				 char *, unsigned int *);
	/* if we can do cache read operations */
	bool (*is_read_op)(__u32);
	/* set oplock level for the inode */
@@ -385,6 +389,12 @@ struct smb_version_operations {
			struct cifsFileInfo *target_file, u64 src_off, u64 len,
			u64 dest_off);
	int (*validate_negotiate)(const unsigned int, struct cifs_tcon *);
	ssize_t (*query_all_EAs)(const unsigned int, struct cifs_tcon *,
			const unsigned char *, const unsigned char *, char *,
			size_t, const struct nls_table *, int);
	int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
			const char *, const void *, const __u16,
			const struct nls_table *, int);
};

struct smb_version_values {
+12 −10
Original line number Diff line number Diff line
@@ -362,11 +362,8 @@ extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
			       const struct nls_table *nls_codepage);
extern int CIFSSMB_set_compression(const unsigned int xid,
				   struct cifs_tcon *tcon, __u16 fid);
extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
			const char *fileName, const int disposition,
			const int access_flags, const int omode,
			__u16 *netfid, int *pOplock, FILE_ALL_INFO *,
			const struct nls_table *nls_codepage, int remap);
extern int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms,
		     int *oplock, FILE_ALL_INFO *buf);
extern int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
			const char *fileName, const int disposition,
			const int access_flags, const int omode,
@@ -476,8 +473,8 @@ extern int CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
			const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr);
extern int CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon,
extern bool couldbe_mf_symlink(const struct cifs_fattr *fattr);
extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
			      struct cifs_sb_info *cifs_sb,
			      struct cifs_fattr *fattr,
			      const unsigned char *path);
@@ -496,7 +493,12 @@ void cifs_writev_complete(struct work_struct *work);
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
						work_func_t complete);
void cifs_writedata_release(struct kref *refcount);
int open_query_close_cifs_symlink(const unsigned char *path, char *pbuf,
			unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
			unsigned int xid);
int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
			  struct cifs_sb_info *cifs_sb,
			  const unsigned char *path, char *pbuf,
			  unsigned int *pbytes_read);
int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
			   struct cifs_sb_info *cifs_sb,
			   const unsigned char *path, char *pbuf,
			   unsigned int *pbytes_written);
#endif			/* _CIFSPROTO_H */
+89 −69
Original line number Diff line number Diff line
@@ -1273,104 +1273,124 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
}

int
CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
	    const char *fileName, const int openDisposition,
	    const int access_flags, const int create_options, __u16 *netfid,
	    int *pOplock, FILE_ALL_INFO *pfile_info,
	    const struct nls_table *nls_codepage, int remap)
CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
	  FILE_ALL_INFO *buf)
{
	int rc = -EACCES;
	OPEN_REQ *pSMB = NULL;
	OPEN_RSP *pSMBr = NULL;
	OPEN_REQ *req = NULL;
	OPEN_RSP *rsp = NULL;
	int bytes_returned;
	int name_len;
	__u16 count;
	struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
	struct cifs_tcon *tcon = oparms->tcon;
	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
	const struct nls_table *nls = cifs_sb->local_nls;
	int create_options = oparms->create_options;
	int desired_access = oparms->desired_access;
	int disposition = oparms->disposition;
	const char *path = oparms->path;

openRetry:
	rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
		      (void **)&rsp);
	if (rc)
		return rc;

	pSMB->AndXCommand = 0xFF;	/* none */
	/* no commands go after this */
	req->AndXCommand = 0xFF;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		count = 1;	/* account for one byte pad to word boundary */
		name_len =
		    cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
				       fileName, PATH_MAX, nls_codepage, remap);
		name_len++;	/* trailing null */
	if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
		/* account for one byte pad to word boundary */
		count = 1;
		name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
					      path, PATH_MAX, nls, remap);
		/* trailing null */
		name_len++;
		name_len *= 2;
		pSMB->NameLength = cpu_to_le16(name_len);
	} else {		/* BB improve check for buffer overruns BB */
		count = 0;	/* no pad */
		name_len = strnlen(fileName, PATH_MAX);
		name_len++;	/* trailing null */
		pSMB->NameLength = cpu_to_le16(name_len);
		strncpy(pSMB->fileName, fileName, name_len);
		req->NameLength = cpu_to_le16(name_len);
	} else {
		/* BB improve check for buffer overruns BB */
		/* no pad */
		count = 0;
		name_len = strnlen(path, PATH_MAX);
		/* trailing null */
		name_len++;
		req->NameLength = cpu_to_le16(name_len);
		strncpy(req->fileName, path, name_len);
	}
	if (*pOplock & REQ_OPLOCK)
		pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
	else if (*pOplock & REQ_BATCHOPLOCK)
		pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
	pSMB->DesiredAccess = cpu_to_le32(access_flags);
	pSMB->AllocationSize = 0;
	/* set file as system file if special file such
	   as fifo and server expecting SFU style and
	   no Unix extensions */

	if (*oplock & REQ_OPLOCK)
		req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
	else if (*oplock & REQ_BATCHOPLOCK)
		req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);

	req->DesiredAccess = cpu_to_le32(desired_access);
	req->AllocationSize = 0;

	/*
	 * Set file as system file if special file such as fifo and server
	 * expecting SFU style and no Unix extensions.
	 */
	if (create_options & CREATE_OPTION_SPECIAL)
		pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
		req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
	else
		pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
		req->FileAttributes = cpu_to_le32(ATTR_NORMAL);

	/* XP does not handle ATTR_POSIX_SEMANTICS */
	/* but it helps speed up case sensitive checks for other
	servers such as Samba */
	/*
	 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
	 * sensitive checks for other servers such as Samba.
	 */
	if (tcon->ses->capabilities & CAP_UNIX)
		pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
		req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);

	if (create_options & CREATE_OPTION_READONLY)
		pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
		req->FileAttributes |= cpu_to_le32(ATTR_READONLY);

	req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
	req->CreateDisposition = cpu_to_le32(disposition);
	req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);

	pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
	pSMB->CreateDisposition = cpu_to_le32(openDisposition);
	pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
	/* BB Expirement with various impersonation levels and verify */
	pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
	pSMB->SecurityFlags =
	    SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
	req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
	req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;

	count += name_len;
	inc_rfc1001_len(pSMB, count);
	inc_rfc1001_len(req, count);

	pSMB->ByteCount = cpu_to_le16(count);
	/* long_op set to 1 to allow for oplock break timeouts */
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			(struct smb_hdr *)pSMBr, &bytes_returned, 0);
	req->ByteCount = cpu_to_le16(count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
			 (struct smb_hdr *)rsp, &bytes_returned, 0);
	cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
	if (rc) {
		cifs_dbg(FYI, "Error in Open = %d\n", rc);
	} else {
		*pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
		*netfid = pSMBr->Fid;	/* cifs fid stays in le */
		cifs_buf_release(req);
		if (rc == -EAGAIN)
			goto openRetry;
		return rc;
	}

	/* 1 byte no need to le_to_cpu */
	*oplock = rsp->OplockLevel;
	/* cifs fid stays in le */
	oparms->fid->netfid = rsp->Fid;

	/* Let caller know file was created so we can set the mode. */
	/* Do we care about the CreateAction in any other cases? */
		if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
			*pOplock |= CIFS_CREATE_ACTION;
		if (pfile_info) {
			memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
				36 /* CreationTime to Attributes */);
	if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
		*oplock |= CIFS_CREATE_ACTION;

	if (buf) {
		/* copy from CreationTime to Attributes */
		memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
		/* the file_info buf is endian converted by caller */
			pfile_info->AllocationSize = pSMBr->AllocationSize;
			pfile_info->EndOfFile = pSMBr->EndOfFile;
			pfile_info->NumberOfLinks = cpu_to_le32(1);
			pfile_info->DeletePending = 0;
		}
		buf->AllocationSize = rsp->AllocationSize;
		buf->EndOfFile = rsp->EndOfFile;
		buf->NumberOfLinks = cpu_to_le32(1);
		buf->DeletePending = 0;
	}

	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto openRetry;
	cifs_buf_release(req);
	return rc;
}

+31 −28
Original line number Diff line number Diff line
@@ -565,12 +565,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
	int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL;
	struct cifs_sb_info *cifs_sb;
	struct tcon_link *tlink;
	struct cifs_tcon *pTcon;
	struct cifs_tcon *tcon;
	struct cifs_io_parms io_parms;
	char *full_path = NULL;
	struct inode *newinode = NULL;
	int oplock = 0;
	u16 fileHandle;
	struct cifs_fid fid;
	struct cifs_open_parms oparms;
	FILE_ALL_INFO *buf = NULL;
	unsigned int bytes_written;
	struct win_dev *pdev;
@@ -583,7 +584,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);

	pTcon = tlink_tcon(tlink);
	tcon = tlink_tcon(tlink);

	xid = get_xid();

@@ -593,7 +594,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
		goto mknod_out;
	}

	if (pTcon->unix_ext) {
	if (tcon->unix_ext) {
		struct cifs_unix_set_info_args args = {
			.mode	= mode & ~current_umask(),
			.ctime	= NO_CHANGE_64,
@@ -608,7 +609,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
			args.uid = INVALID_UID; /* no change */
			args.gid = INVALID_GID; /* no change */
		}
		rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
		rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
					    cifs_sb->local_nls,
					    cifs_sb->mnt_cifs_flags &
						CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -640,42 +641,44 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
	if (backup_cred(cifs_sb))
		create_options |= CREATE_OPEN_BACKUP_INTENT;

	rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
			 GENERIC_WRITE, create_options,
			 &fileHandle, &oplock, buf, cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
	oparms.tcon = tcon;
	oparms.cifs_sb = cifs_sb;
	oparms.desired_access = GENERIC_WRITE;
	oparms.create_options = create_options;
	oparms.disposition = FILE_CREATE;
	oparms.path = full_path;
	oparms.fid = &fid;
	oparms.reconnect = false;

	rc = CIFS_open(xid, &oparms, &oplock, buf);
	if (rc)
		goto mknod_out;

	/* BB Do not bother to decode buf since no local inode yet to put
	 * timestamps in, but we can reuse it safely */
	/*
	 * BB Do not bother to decode buf since no local inode yet to put
	 * timestamps in, but we can reuse it safely.
	 */

	pdev = (struct win_dev *)buf;
	io_parms.netfid = fileHandle;
	io_parms.netfid = fid.netfid;
	io_parms.pid = current->tgid;
	io_parms.tcon = pTcon;
	io_parms.tcon = tcon;
	io_parms.offset = 0;
	io_parms.length = sizeof(struct win_dev);
	if (S_ISCHR(mode)) {
		memcpy(pdev->type, "IntxCHR", 8);
		pdev->major =
		      cpu_to_le64(MAJOR(device_number));
		pdev->minor =
		      cpu_to_le64(MINOR(device_number));
		rc = CIFSSMBWrite(xid, &io_parms,
			&bytes_written, (char *)pdev,
		pdev->major = cpu_to_le64(MAJOR(device_number));
		pdev->minor = cpu_to_le64(MINOR(device_number));
		rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev,
				  NULL, 0);
	} else if (S_ISBLK(mode)) {
		memcpy(pdev->type, "IntxBLK", 8);
		pdev->major =
		      cpu_to_le64(MAJOR(device_number));
		pdev->minor =
		      cpu_to_le64(MINOR(device_number));
		rc = CIFSSMBWrite(xid, &io_parms,
			&bytes_written, (char *)pdev,
		pdev->major = cpu_to_le64(MAJOR(device_number));
		pdev->minor = cpu_to_le64(MINOR(device_number));
		rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev,
				  NULL, 0);
	} /* else if (S_ISFIFO) */
	CIFSSMBClose(xid, pTcon, fileHandle);
	CIFSSMBClose(xid, tcon, fid.netfid);
	d_drop(direntry);

	/* FIXME: add code here to set EAs */
Loading