2021-06-18 05:31:49 +00:00
|
|
|
// SPDX-License-Identifier: LGPL-2.1
|
2011-12-29 13:06:33 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Copyright (C) International Business Machines Corp., 2002, 2011
|
|
|
|
* Etersoft, 2012
|
|
|
|
* Author(s): Pavel Shilovsky (pshilovsky@samba.org),
|
|
|
|
* Steve French (sfrench@us.ibm.com)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/stat.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
#include <asm/div64.h>
|
|
|
|
#include "cifsfs.h"
|
|
|
|
#include "cifspdu.h"
|
|
|
|
#include "cifsglob.h"
|
|
|
|
#include "cifsproto.h"
|
|
|
|
#include "cifs_debug.h"
|
|
|
|
#include "cifs_fs_sb.h"
|
|
|
|
#include "cifs_unicode.h"
|
|
|
|
#include "fscache.h"
|
|
|
|
#include "smb2glob.h"
|
|
|
|
#include "smb2pdu.h"
|
|
|
|
#include "smb2proto.h"
|
2022-08-11 03:00:08 +00:00
|
|
|
#include "cached_dir.h"
|
2022-10-03 21:43:50 +00:00
|
|
|
#include "smb2status.h"
|
2011-12-29 13:06:33 +00:00
|
|
|
|
2019-03-13 05:02:47 +00:00
|
|
|
static void
|
|
|
|
free_set_inf_compound(struct smb_rqst *rqst)
|
|
|
|
{
|
|
|
|
if (rqst[1].rq_iov)
|
|
|
|
SMB2_set_info_free(&rqst[1]);
|
|
|
|
if (rqst[2].rq_iov)
|
|
|
|
SMB2_close_free(&rqst[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-05-20 02:19:59 +00:00
|
|
|
struct cop_vars {
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
struct kvec rsp_iov[3];
|
|
|
|
struct smb_rqst rqst[3];
|
|
|
|
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
|
|
|
struct kvec qi_iov[1];
|
|
|
|
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
|
|
|
|
struct kvec close_iov[1];
|
|
|
|
struct smb2_file_rename_info rename_info;
|
|
|
|
struct smb2_file_link_info link_info;
|
|
|
|
};
|
|
|
|
|
2021-07-30 06:43:09 +00:00
|
|
|
/*
|
|
|
|
* note: If cfile is passed, the reference to it is dropped here.
|
|
|
|
* So make sure that you do not reuse cfile after return from this func.
|
2022-10-03 21:43:50 +00:00
|
|
|
*
|
|
|
|
* If passing @err_iov and @err_buftype, ensure to make them both large enough (>= 3) to hold all
|
|
|
|
* error responses. Caller is also responsible for freeing them up.
|
2021-07-30 06:43:09 +00:00
|
|
|
*/
|
2022-10-03 21:43:50 +00:00
|
|
|
static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb, const char *full_path,
|
|
|
|
__u32 desired_access, __u32 create_disposition, __u32 create_options,
|
|
|
|
umode_t mode, void *ptr, int command, struct cifsFileInfo *cfile,
|
2022-11-25 11:26:00 +00:00
|
|
|
__u8 **extbuf, size_t *extbuflen,
|
2022-10-03 21:43:50 +00:00
|
|
|
struct kvec *err_iov, int *err_buftype)
|
2018-09-03 03:33:41 +00:00
|
|
|
{
|
2020-05-20 02:19:59 +00:00
|
|
|
struct cop_vars *vars = NULL;
|
|
|
|
struct kvec *rsp_iov;
|
|
|
|
struct smb_rqst *rqst;
|
2018-09-03 03:33:41 +00:00
|
|
|
int rc;
|
|
|
|
__le16 *utf16_path = NULL;
|
|
|
|
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
struct cifs_fid fid;
|
|
|
|
struct cifs_ses *ses = tcon->ses;
|
2020-05-31 17:38:22 +00:00
|
|
|
struct TCP_Server_Info *server;
|
2018-09-03 03:33:41 +00:00
|
|
|
int num_rqst = 0;
|
|
|
|
int resp_buftype[3];
|
2018-09-03 03:33:45 +00:00
|
|
|
struct smb2_query_info_rsp *qi_rsp = NULL;
|
2022-10-03 21:43:50 +00:00
|
|
|
struct cifs_open_info_data *idata;
|
2018-09-03 03:33:41 +00:00
|
|
|
int flags = 0;
|
2018-09-03 03:33:45 +00:00
|
|
|
__u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
|
2018-09-03 03:33:49 +00:00
|
|
|
unsigned int size[2];
|
|
|
|
void *data[2];
|
|
|
|
int len;
|
2018-09-03 03:33:41 +00:00
|
|
|
|
2020-05-20 02:19:59 +00:00
|
|
|
vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
|
|
|
|
if (vars == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
rqst = &vars->rqst[0];
|
|
|
|
rsp_iov = &vars->rsp_iov[0];
|
|
|
|
|
2020-05-31 17:38:22 +00:00
|
|
|
server = cifs_pick_channel(ses);
|
|
|
|
|
2018-09-03 03:33:41 +00:00
|
|
|
if (smb3_encryption_required(tcon))
|
|
|
|
flags |= CIFS_TRANSFORM_REQ;
|
|
|
|
|
|
|
|
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
|
|
|
|
2019-08-29 22:25:46 +00:00
|
|
|
/* We already have a handle so we can skip the open */
|
|
|
|
if (cfile)
|
|
|
|
goto after_open;
|
|
|
|
|
2018-09-03 03:33:41 +00:00
|
|
|
/* Open */
|
|
|
|
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
2019-08-29 22:25:46 +00:00
|
|
|
if (!utf16_path) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto finished;
|
|
|
|
}
|
2018-09-03 03:33:41 +00:00
|
|
|
|
2023-01-11 11:37:58 +00:00
|
|
|
vars->oparms = (struct cifs_open_parms) {
|
|
|
|
.tcon = tcon,
|
|
|
|
.desired_access = desired_access,
|
|
|
|
.disposition = create_disposition,
|
|
|
|
.create_options = cifs_create_options(cifs_sb, create_options),
|
|
|
|
.fid = &fid,
|
|
|
|
.mode = mode,
|
|
|
|
.cifs_sb = cifs_sb,
|
|
|
|
};
|
2020-05-20 02:19:59 +00:00
|
|
|
|
|
|
|
rqst[num_rqst].rq_iov = &vars->open_iov[0];
|
2018-09-03 03:33:41 +00:00
|
|
|
rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = SMB2_open_init(tcon, server,
|
|
|
|
&rqst[num_rqst], &oplock, &vars->oparms,
|
2018-09-03 03:33:41 +00:00
|
|
|
utf16_path);
|
|
|
|
kfree(utf16_path);
|
|
|
|
if (rc)
|
|
|
|
goto finished;
|
|
|
|
|
2019-08-29 22:25:46 +00:00
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
after_open:
|
|
|
|
num_rqst++;
|
|
|
|
rc = 0;
|
2018-09-03 03:33:41 +00:00
|
|
|
|
|
|
|
/* Operation */
|
|
|
|
switch (command) {
|
|
|
|
case SMB2_OP_QUERY_INFO:
|
2020-05-20 02:19:59 +00:00
|
|
|
rqst[num_rqst].rq_iov = &vars->qi_iov[0];
|
2018-09-03 03:33:41 +00:00
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
|
|
|
|
2019-09-09 05:30:00 +00:00
|
|
|
if (cfile)
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
2019-09-09 05:30:00 +00:00
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
FILE_ALL_INFORMATION,
|
2018-09-03 03:33:41 +00:00
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
sizeof(struct smb2_file_all_info) +
|
2018-10-08 00:19:58 +00:00
|
|
|
PATH_MAX * 2, 0, NULL);
|
2019-09-09 05:30:00 +00:00
|
|
|
else {
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
2019-09-09 05:30:00 +00:00
|
|
|
COMPOUND_FID,
|
|
|
|
COMPOUND_FID,
|
2020-05-31 17:38:22 +00:00
|
|
|
FILE_ALL_INFORMATION,
|
2019-09-09 05:30:00 +00:00
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
sizeof(struct smb2_file_all_info) +
|
|
|
|
PATH_MAX * 2, 0, NULL);
|
|
|
|
if (!rc) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-12 00:25:47 +00:00
|
|
|
if (rc)
|
|
|
|
goto finished;
|
|
|
|
num_rqst++;
|
|
|
|
trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid,
|
|
|
|
full_path);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_POSIX_QUERY_INFO:
|
|
|
|
rqst[num_rqst].rq_iov = &vars->qi_iov[0];
|
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
|
|
|
|
|
|
|
if (cfile)
|
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
SMB_FIND_FILE_POSIX_INFO,
|
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
/* TBD: fix following to allow for longer SIDs */
|
|
|
|
sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) +
|
|
|
|
(sizeof(struct cifs_sid) * 2), 0, NULL);
|
|
|
|
else {
|
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
COMPOUND_FID,
|
|
|
|
COMPOUND_FID,
|
|
|
|
SMB_FIND_FILE_POSIX_INFO,
|
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) +
|
|
|
|
(sizeof(struct cifs_sid) * 2), 0, NULL);
|
|
|
|
if (!rc) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-16 00:41:46 +00:00
|
|
|
if (rc)
|
|
|
|
goto finished;
|
2019-09-09 05:30:00 +00:00
|
|
|
num_rqst++;
|
2020-06-12 04:02:33 +00:00
|
|
|
trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, tcon->tid, full_path);
|
2018-09-03 03:33:41 +00:00
|
|
|
break;
|
2018-09-03 03:33:43 +00:00
|
|
|
case SMB2_OP_DELETE:
|
2019-03-13 05:02:47 +00:00
|
|
|
trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
|
2018-09-03 03:33:43 +00:00
|
|
|
break;
|
2018-09-03 03:33:42 +00:00
|
|
|
case SMB2_OP_MKDIR:
|
|
|
|
/*
|
|
|
|
* Directories are created through parameters in the
|
|
|
|
* SMB2_open() call.
|
|
|
|
*/
|
2019-03-13 05:02:47 +00:00
|
|
|
trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);
|
2018-09-03 03:33:42 +00:00
|
|
|
break;
|
2018-09-03 03:33:45 +00:00
|
|
|
case SMB2_OP_RMDIR:
|
2020-05-20 02:19:59 +00:00
|
|
|
rqst[num_rqst].rq_iov = &vars->si_iov[0];
|
2018-09-03 03:33:45 +00:00
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
|
|
|
|
2018-12-18 23:49:05 +00:00
|
|
|
size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
|
2018-09-03 03:33:45 +00:00
|
|
|
data[0] = &delete_pending[0];
|
|
|
|
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst], COMPOUND_FID,
|
2018-09-03 03:33:45 +00:00
|
|
|
COMPOUND_FID, current->tgid,
|
|
|
|
FILE_DISPOSITION_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
2019-07-16 00:41:46 +00:00
|
|
|
if (rc)
|
|
|
|
goto finished;
|
2018-12-31 03:43:40 +00:00
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
2018-09-03 03:33:45 +00:00
|
|
|
smb2_set_related(&rqst[num_rqst++]);
|
2019-03-13 05:02:47 +00:00
|
|
|
trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
|
2018-09-03 03:33:45 +00:00
|
|
|
break;
|
2018-09-03 03:33:46 +00:00
|
|
|
case SMB2_OP_SET_EOF:
|
2020-05-20 02:19:59 +00:00
|
|
|
rqst[num_rqst].rq_iov = &vars->si_iov[0];
|
2018-09-03 03:33:46 +00:00
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
|
|
|
|
|
|
|
size[0] = 8; /* sizeof __le64 */
|
|
|
|
data[0] = ptr;
|
|
|
|
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst], COMPOUND_FID,
|
2018-09-03 03:33:46 +00:00
|
|
|
COMPOUND_FID, current->tgid,
|
|
|
|
FILE_END_OF_FILE_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
2019-07-16 00:41:46 +00:00
|
|
|
if (rc)
|
|
|
|
goto finished;
|
2018-12-31 03:43:40 +00:00
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
2018-09-03 03:33:46 +00:00
|
|
|
smb2_set_related(&rqst[num_rqst++]);
|
2019-03-13 05:02:47 +00:00
|
|
|
trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
|
2018-09-03 03:33:46 +00:00
|
|
|
break;
|
2018-09-03 03:33:48 +00:00
|
|
|
case SMB2_OP_SET_INFO:
|
2020-05-20 02:19:59 +00:00
|
|
|
rqst[num_rqst].rq_iov = &vars->si_iov[0];
|
2018-09-03 03:33:48 +00:00
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
|
|
|
|
2018-09-03 03:33:49 +00:00
|
|
|
|
2018-09-03 03:33:48 +00:00
|
|
|
size[0] = sizeof(FILE_BASIC_INFO);
|
|
|
|
data[0] = ptr;
|
|
|
|
|
2019-08-29 23:53:56 +00:00
|
|
|
if (cfile)
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
2019-08-29 23:53:56 +00:00
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid, current->tgid,
|
|
|
|
FILE_BASIC_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
|
|
|
else {
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
2019-08-29 23:53:56 +00:00
|
|
|
COMPOUND_FID,
|
|
|
|
COMPOUND_FID, current->tgid,
|
|
|
|
FILE_BASIC_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
|
|
|
if (!rc) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-16 00:41:46 +00:00
|
|
|
if (rc)
|
|
|
|
goto finished;
|
2019-08-29 23:53:56 +00:00
|
|
|
num_rqst++;
|
2019-03-13 05:02:47 +00:00
|
|
|
trace_smb3_set_info_compound_enter(xid, ses->Suid, tcon->tid,
|
|
|
|
full_path);
|
2018-09-03 03:33:48 +00:00
|
|
|
break;
|
2018-09-03 03:33:49 +00:00
|
|
|
case SMB2_OP_RENAME:
|
2020-05-20 02:19:59 +00:00
|
|
|
rqst[num_rqst].rq_iov = &vars->si_iov[0];
|
2018-09-03 03:33:49 +00:00
|
|
|
rqst[num_rqst].rq_nvec = 2;
|
|
|
|
|
|
|
|
len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
|
|
|
|
|
2020-05-20 02:19:59 +00:00
|
|
|
vars->rename_info.ReplaceIfExists = 1;
|
|
|
|
vars->rename_info.RootDirectory = 0;
|
|
|
|
vars->rename_info.FileNameLength = cpu_to_le32(len);
|
2018-09-03 03:33:49 +00:00
|
|
|
|
|
|
|
size[0] = sizeof(struct smb2_file_rename_info);
|
2020-05-20 02:19:59 +00:00
|
|
|
data[0] = &vars->rename_info;
|
2018-09-03 03:33:49 +00:00
|
|
|
|
|
|
|
size[1] = len + 2 /* null */;
|
|
|
|
data[1] = (__le16 *)ptr;
|
|
|
|
|
2019-08-29 22:25:46 +00:00
|
|
|
if (cfile)
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
2019-08-29 22:25:46 +00:00
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
current->tgid, FILE_RENAME_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
|
|
|
else {
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
2019-08-29 22:25:46 +00:00
|
|
|
COMPOUND_FID, COMPOUND_FID,
|
|
|
|
current->tgid, FILE_RENAME_INFORMATION,
|
2018-09-03 03:33:49 +00:00
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
2019-08-29 23:53:56 +00:00
|
|
|
if (!rc) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
}
|
2019-08-29 22:25:46 +00:00
|
|
|
}
|
2019-07-16 00:41:46 +00:00
|
|
|
if (rc)
|
|
|
|
goto finished;
|
2019-08-29 22:25:46 +00:00
|
|
|
num_rqst++;
|
2019-03-13 05:02:47 +00:00
|
|
|
trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
|
2018-09-03 03:33:49 +00:00
|
|
|
break;
|
|
|
|
case SMB2_OP_HARDLINK:
|
2020-05-20 02:19:59 +00:00
|
|
|
rqst[num_rqst].rq_iov = &vars->si_iov[0];
|
2018-09-03 03:33:49 +00:00
|
|
|
rqst[num_rqst].rq_nvec = 2;
|
|
|
|
|
|
|
|
len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
|
|
|
|
|
2020-05-20 02:19:59 +00:00
|
|
|
vars->link_info.ReplaceIfExists = 0;
|
|
|
|
vars->link_info.RootDirectory = 0;
|
|
|
|
vars->link_info.FileNameLength = cpu_to_le32(len);
|
2018-09-03 03:33:49 +00:00
|
|
|
|
|
|
|
size[0] = sizeof(struct smb2_file_link_info);
|
2020-05-20 02:19:59 +00:00
|
|
|
data[0] = &vars->link_info;
|
2018-09-03 03:33:49 +00:00
|
|
|
|
|
|
|
size[1] = len + 2 /* null */;
|
|
|
|
data[1] = (__le16 *)ptr;
|
|
|
|
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst], COMPOUND_FID,
|
2018-09-03 03:33:49 +00:00
|
|
|
COMPOUND_FID, current->tgid,
|
|
|
|
FILE_LINK_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
2019-07-16 00:41:46 +00:00
|
|
|
if (rc)
|
|
|
|
goto finished;
|
2018-12-31 03:43:40 +00:00
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
2018-09-03 03:33:49 +00:00
|
|
|
smb2_set_related(&rqst[num_rqst++]);
|
2019-03-13 05:02:47 +00:00
|
|
|
trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
|
2018-09-03 03:33:49 +00:00
|
|
|
break;
|
2018-09-03 03:33:41 +00:00
|
|
|
default:
|
|
|
|
cifs_dbg(VFS, "Invalid command\n");
|
|
|
|
rc = -EINVAL;
|
|
|
|
}
|
|
|
|
if (rc)
|
|
|
|
goto finished;
|
|
|
|
|
2019-08-29 22:25:46 +00:00
|
|
|
/* We already have a handle so we can skip the close */
|
|
|
|
if (cfile)
|
|
|
|
goto after_close;
|
2018-09-03 03:33:41 +00:00
|
|
|
/* Close */
|
2021-03-08 15:00:50 +00:00
|
|
|
flags |= CIFS_CP_CREATE_CLOSE_OP;
|
2020-05-20 02:19:59 +00:00
|
|
|
rqst[num_rqst].rq_iov = &vars->close_iov[0];
|
2018-09-03 03:33:41 +00:00
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = SMB2_close_init(tcon, server,
|
|
|
|
&rqst[num_rqst], COMPOUND_FID,
|
2019-12-03 03:46:54 +00:00
|
|
|
COMPOUND_FID, false);
|
2019-08-29 22:25:46 +00:00
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
2018-09-03 03:33:41 +00:00
|
|
|
if (rc)
|
|
|
|
goto finished;
|
2019-08-29 22:25:46 +00:00
|
|
|
after_close:
|
|
|
|
num_rqst++;
|
|
|
|
|
|
|
|
if (cfile) {
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = compound_send_recv(xid, ses, server,
|
|
|
|
flags, num_rqst - 2,
|
2019-08-29 22:25:46 +00:00
|
|
|
&rqst[1], &resp_buftype[1],
|
|
|
|
&rsp_iov[1]);
|
|
|
|
} else
|
2020-05-31 17:38:22 +00:00
|
|
|
rc = compound_send_recv(xid, ses, server,
|
|
|
|
flags, num_rqst,
|
2019-08-29 22:25:46 +00:00
|
|
|
rqst, resp_buftype,
|
|
|
|
rsp_iov);
|
2018-09-03 03:33:41 +00:00
|
|
|
|
|
|
|
finished:
|
2019-08-29 22:25:46 +00:00
|
|
|
if (cfile)
|
|
|
|
cifsFileInfo_put(cfile);
|
|
|
|
|
2018-09-03 03:33:41 +00:00
|
|
|
SMB2_open_free(&rqst[0]);
|
2019-09-11 05:07:36 +00:00
|
|
|
if (rc == -EREMCHG) {
|
2022-09-21 19:05:53 +00:00
|
|
|
pr_warn_once("server share %s deleted\n", tcon->tree_name);
|
2019-09-11 05:07:36 +00:00
|
|
|
tcon->need_reconnect = true;
|
|
|
|
}
|
|
|
|
|
2018-09-03 03:33:41 +00:00
|
|
|
switch (command) {
|
|
|
|
case SMB2_OP_QUERY_INFO:
|
2022-10-03 21:43:50 +00:00
|
|
|
idata = ptr;
|
|
|
|
if (rc == 0 && cfile && cfile->symlink_target) {
|
|
|
|
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
|
|
|
|
if (!idata->symlink_target)
|
|
|
|
rc = -ENOMEM;
|
|
|
|
}
|
2018-09-03 03:33:41 +00:00
|
|
|
if (rc == 0) {
|
2018-09-03 03:33:45 +00:00
|
|
|
qi_rsp = (struct smb2_query_info_rsp *)
|
|
|
|
rsp_iov[1].iov_base;
|
2018-09-03 03:33:41 +00:00
|
|
|
rc = smb2_validate_and_copy_iov(
|
2018-09-03 03:33:45 +00:00
|
|
|
le16_to_cpu(qi_rsp->OutputBufferOffset),
|
|
|
|
le32_to_cpu(qi_rsp->OutputBufferLength),
|
2022-10-03 21:43:50 +00:00
|
|
|
&rsp_iov[1], sizeof(idata->fi), (char *)&idata->fi);
|
2018-09-03 03:33:41 +00:00
|
|
|
}
|
|
|
|
if (rqst[1].rq_iov)
|
|
|
|
SMB2_query_info_free(&rqst[1]);
|
|
|
|
if (rqst[2].rq_iov)
|
|
|
|
SMB2_close_free(&rqst[2]);
|
2019-03-13 05:02:47 +00:00
|
|
|
if (rc)
|
|
|
|
trace_smb3_query_info_compound_err(xid, ses->Suid,
|
|
|
|
tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_query_info_compound_done(xid, ses->Suid,
|
|
|
|
tcon->tid);
|
2018-09-03 03:33:41 +00:00
|
|
|
break;
|
2020-06-12 00:25:47 +00:00
|
|
|
case SMB2_OP_POSIX_QUERY_INFO:
|
2022-10-04 18:10:09 +00:00
|
|
|
idata = ptr;
|
2022-10-03 21:43:50 +00:00
|
|
|
if (rc == 0 && cfile && cfile->symlink_target) {
|
|
|
|
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
|
|
|
|
if (!idata->symlink_target)
|
|
|
|
rc = -ENOMEM;
|
|
|
|
}
|
2020-06-12 00:25:47 +00:00
|
|
|
if (rc == 0) {
|
|
|
|
qi_rsp = (struct smb2_query_info_rsp *)
|
|
|
|
rsp_iov[1].iov_base;
|
|
|
|
rc = smb2_validate_and_copy_iov(
|
|
|
|
le16_to_cpu(qi_rsp->OutputBufferOffset),
|
|
|
|
le32_to_cpu(qi_rsp->OutputBufferLength),
|
2022-10-03 21:43:50 +00:00
|
|
|
&rsp_iov[1], sizeof(idata->posix_fi) /* add SIDs */,
|
|
|
|
(char *)&idata->posix_fi);
|
2020-06-12 00:25:47 +00:00
|
|
|
}
|
2022-11-25 11:37:44 +00:00
|
|
|
if (rc == 0) {
|
|
|
|
unsigned int length = le32_to_cpu(qi_rsp->OutputBufferLength);
|
|
|
|
|
|
|
|
if (length > sizeof(idata->posix_fi)) {
|
|
|
|
char *base = (char *)rsp_iov[1].iov_base +
|
|
|
|
le16_to_cpu(qi_rsp->OutputBufferOffset) +
|
|
|
|
sizeof(idata->posix_fi);
|
|
|
|
*extbuflen = length - sizeof(idata->posix_fi);
|
|
|
|
*extbuf = kmemdup(base, *extbuflen, GFP_KERNEL);
|
|
|
|
if (!*extbuf)
|
|
|
|
rc = -ENOMEM;
|
|
|
|
} else {
|
|
|
|
rc = -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
2020-06-12 00:25:47 +00:00
|
|
|
if (rqst[1].rq_iov)
|
|
|
|
SMB2_query_info_free(&rqst[1]);
|
|
|
|
if (rqst[2].rq_iov)
|
|
|
|
SMB2_close_free(&rqst[2]);
|
|
|
|
if (rc)
|
2020-06-12 04:02:33 +00:00
|
|
|
trace_smb3_posix_query_info_compound_err(xid, ses->Suid, tcon->tid, rc);
|
2020-06-12 00:25:47 +00:00
|
|
|
else
|
2020-06-12 04:02:33 +00:00
|
|
|
trace_smb3_posix_query_info_compound_done(xid, ses->Suid, tcon->tid);
|
2020-06-12 00:25:47 +00:00
|
|
|
break;
|
2018-09-03 03:33:43 +00:00
|
|
|
case SMB2_OP_DELETE:
|
2019-03-13 05:02:47 +00:00
|
|
|
if (rc)
|
|
|
|
trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
|
|
|
|
if (rqst[1].rq_iov)
|
|
|
|
SMB2_close_free(&rqst[1]);
|
|
|
|
break;
|
2018-09-03 03:33:42 +00:00
|
|
|
case SMB2_OP_MKDIR:
|
2019-03-13 05:02:47 +00:00
|
|
|
if (rc)
|
|
|
|
trace_smb3_mkdir_err(xid, ses->Suid, tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
|
2018-09-03 03:33:42 +00:00
|
|
|
if (rqst[1].rq_iov)
|
|
|
|
SMB2_close_free(&rqst[1]);
|
|
|
|
break;
|
2018-09-03 03:33:49 +00:00
|
|
|
case SMB2_OP_HARDLINK:
|
2019-03-13 05:02:47 +00:00
|
|
|
if (rc)
|
|
|
|
trace_smb3_hardlink_err(xid, ses->Suid, tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
|
|
|
|
free_set_inf_compound(rqst);
|
|
|
|
break;
|
2018-09-03 03:33:49 +00:00
|
|
|
case SMB2_OP_RENAME:
|
2019-03-13 05:02:47 +00:00
|
|
|
if (rc)
|
|
|
|
trace_smb3_rename_err(xid, ses->Suid, tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
|
|
|
|
free_set_inf_compound(rqst);
|
|
|
|
break;
|
2018-09-03 03:33:45 +00:00
|
|
|
case SMB2_OP_RMDIR:
|
2019-03-13 05:02:47 +00:00
|
|
|
if (rc)
|
|
|
|
trace_smb3_rmdir_err(xid, ses->Suid, tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
|
|
|
|
free_set_inf_compound(rqst);
|
|
|
|
break;
|
2018-09-03 03:33:48 +00:00
|
|
|
case SMB2_OP_SET_EOF:
|
2019-03-13 05:02:47 +00:00
|
|
|
if (rc)
|
|
|
|
trace_smb3_set_eof_err(xid, ses->Suid, tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
|
|
|
|
free_set_inf_compound(rqst);
|
|
|
|
break;
|
2018-09-03 03:33:48 +00:00
|
|
|
case SMB2_OP_SET_INFO:
|
2019-03-13 05:02:47 +00:00
|
|
|
if (rc)
|
|
|
|
trace_smb3_set_info_compound_err(xid, ses->Suid,
|
|
|
|
tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_set_info_compound_done(xid, ses->Suid,
|
|
|
|
tcon->tid);
|
|
|
|
free_set_inf_compound(rqst);
|
2018-09-03 03:33:45 +00:00
|
|
|
break;
|
2018-09-03 03:33:41 +00:00
|
|
|
}
|
2022-10-03 21:43:50 +00:00
|
|
|
|
|
|
|
if (rc && err_iov && err_buftype) {
|
|
|
|
memcpy(err_iov, rsp_iov, 3 * sizeof(*err_iov));
|
|
|
|
memcpy(err_buftype, resp_buftype, 3 * sizeof(*err_buftype));
|
|
|
|
} else {
|
|
|
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
|
|
|
}
|
2020-05-20 02:19:59 +00:00
|
|
|
kfree(vars);
|
2018-09-03 03:33:41 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2022-10-03 21:43:50 +00:00
|
|
|
int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb, const char *full_path,
|
|
|
|
struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse)
|
2011-12-29 13:06:33 +00:00
|
|
|
{
|
2018-10-19 05:32:41 +00:00
|
|
|
__u32 create_options = 0;
|
2019-09-09 05:30:00 +00:00
|
|
|
struct cifsFileInfo *cfile;
|
2020-10-05 02:37:52 +00:00
|
|
|
struct cached_fid *cfid = NULL;
|
2022-10-03 21:43:50 +00:00
|
|
|
struct kvec err_iov[3] = {};
|
|
|
|
int err_buftype[3] = {};
|
2023-02-28 22:01:54 +00:00
|
|
|
bool islink;
|
|
|
|
int rc, rc2;
|
2011-12-29 13:06:33 +00:00
|
|
|
|
|
|
|
*adjust_tz = false;
|
2020-10-23 03:03:14 +00:00
|
|
|
*reparse = false;
|
2011-12-29 13:06:33 +00:00
|
|
|
|
2022-05-09 23:42:06 +00:00
|
|
|
if (strcmp(full_path, ""))
|
|
|
|
rc = -ENOENT;
|
|
|
|
else
|
2022-08-12 00:51:18 +00:00
|
|
|
rc = open_cached_dir(xid, tcon, full_path, cifs_sb, false, &cfid);
|
2019-01-16 19:48:42 +00:00
|
|
|
/* If it is a root and its handle is cached then use it */
|
2021-03-08 23:07:28 +00:00
|
|
|
if (!rc) {
|
2022-08-09 02:11:49 +00:00
|
|
|
if (cfid->file_all_info_is_valid) {
|
2022-10-03 21:43:50 +00:00
|
|
|
memcpy(&data->fi, &cfid->file_all_info, sizeof(data->fi));
|
2021-03-08 23:07:28 +00:00
|
|
|
} else {
|
2022-10-03 21:43:50 +00:00
|
|
|
rc = SMB2_query_info(xid, tcon, cfid->fid.persistent_fid,
|
|
|
|
cfid->fid.volatile_fid, &data->fi);
|
2019-03-12 03:58:31 +00:00
|
|
|
}
|
2021-03-08 23:07:29 +00:00
|
|
|
close_cached_dir(cfid);
|
2022-10-03 21:43:50 +00:00
|
|
|
return rc;
|
2019-01-16 19:48:42 +00:00
|
|
|
}
|
|
|
|
|
2019-09-09 05:30:00 +00:00
|
|
|
cifs_get_readable_path(tcon, full_path, &cfile);
|
2022-10-03 21:43:50 +00:00
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
|
|
|
|
create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile,
|
2022-11-25 11:26:00 +00:00
|
|
|
NULL, NULL, err_iov, err_buftype);
|
cifs: reduce roundtrips on create/qinfo requests
To work around some Window servers that return
STATUS_OBJECT_NAME_INVALID on query infos under DFS namespaces that
contain non-ASCII characters, we started checking for -ENOENT on every
file open, and if so, then send additional requests to figure out
whether it is a DFS link or not. It means that all those requests
will be sent to every non-existing file.
So, in order to reduce the number of roundtrips, check earlier whether
status code is STATUS_OBJECT_NAME_INVALID and tcon supports dfs, and
if so, then map -ENOENT to -EREMOTE so mount or automount will take
care of chasing the DFS link -- if it isn't an DFS link, then -ENOENT
will be returned appropriately.
Before patch
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 228 Ioctl Request FSCTL_DFS_GET_REFERRALS, File: \ada.test\dfs\foo
SMB2 143 Ioctl Response, Error: STATUS_OBJECT_PATH_NOT_FOUND
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 228 Ioctl Request FSCTL_DFS_GET_REFERRALS, File: \ada.test\dfs\foo
SMB2 143 Ioctl Response, Error: STATUS_OBJECT_PATH_NOT_FOUND
After patch
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-12-13 02:39:37 +00:00
|
|
|
if (rc) {
|
|
|
|
struct smb2_hdr *hdr = err_iov[0].iov_base;
|
|
|
|
|
|
|
|
if (unlikely(!hdr || err_buftype[0] == CIFS_NO_BUFFER))
|
|
|
|
goto out;
|
|
|
|
if (rc == -EOPNOTSUPP && hdr->Command == SMB2_CREATE &&
|
|
|
|
hdr->Status == STATUS_STOPPED_ON_SYMLINK) {
|
|
|
|
rc = smb2_parse_symlink_response(cifs_sb, err_iov,
|
|
|
|
&data->symlink_target);
|
2022-10-03 21:43:50 +00:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
cifs: reduce roundtrips on create/qinfo requests
To work around some Window servers that return
STATUS_OBJECT_NAME_INVALID on query infos under DFS namespaces that
contain non-ASCII characters, we started checking for -ENOENT on every
file open, and if so, then send additional requests to figure out
whether it is a DFS link or not. It means that all those requests
will be sent to every non-existing file.
So, in order to reduce the number of roundtrips, check earlier whether
status code is STATUS_OBJECT_NAME_INVALID and tcon supports dfs, and
if so, then map -ENOENT to -EREMOTE so mount or automount will take
care of chasing the DFS link -- if it isn't an DFS link, then -ENOENT
will be returned appropriately.
Before patch
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 228 Ioctl Request FSCTL_DFS_GET_REFERRALS, File: \ada.test\dfs\foo
SMB2 143 Ioctl Response, Error: STATUS_OBJECT_PATH_NOT_FOUND
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 228 Ioctl Request FSCTL_DFS_GET_REFERRALS, File: \ada.test\dfs\foo
SMB2 143 Ioctl Response, Error: STATUS_OBJECT_PATH_NOT_FOUND
After patch
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-12-13 02:39:37 +00:00
|
|
|
|
|
|
|
*reparse = true;
|
|
|
|
create_options |= OPEN_REPARSE_POINT;
|
|
|
|
|
|
|
|
/* Failed on a symbolic link - query a reparse point info */
|
|
|
|
cifs_get_readable_path(tcon, full_path, &cfile);
|
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
|
|
|
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
|
|
|
create_options, ACL_NO_MODE, data,
|
|
|
|
SMB2_OP_QUERY_INFO, cfile, NULL, NULL,
|
|
|
|
NULL, NULL);
|
|
|
|
goto out;
|
2023-02-28 22:01:54 +00:00
|
|
|
} else if (rc != -EREMOTE && hdr->Status == STATUS_OBJECT_NAME_INVALID) {
|
|
|
|
rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
|
|
|
|
full_path, &islink);
|
|
|
|
if (rc2) {
|
|
|
|
rc = rc2;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (islink)
|
|
|
|
rc = -EREMOTE;
|
2022-10-03 21:43:50 +00:00
|
|
|
}
|
cifs: reduce roundtrips on create/qinfo requests
To work around some Window servers that return
STATUS_OBJECT_NAME_INVALID on query infos under DFS namespaces that
contain non-ASCII characters, we started checking for -ENOENT on every
file open, and if so, then send additional requests to figure out
whether it is a DFS link or not. It means that all those requests
will be sent to every non-existing file.
So, in order to reduce the number of roundtrips, check earlier whether
status code is STATUS_OBJECT_NAME_INVALID and tcon supports dfs, and
if so, then map -ENOENT to -EREMOTE so mount or automount will take
care of chasing the DFS link -- if it isn't an DFS link, then -ENOENT
will be returned appropriately.
Before patch
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 228 Ioctl Request FSCTL_DFS_GET_REFERRALS, File: \ada.test\dfs\foo
SMB2 143 Ioctl Response, Error: STATUS_OBJECT_PATH_NOT_FOUND
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 228 Ioctl Request FSCTL_DFS_GET_REFERRALS, File: \ada.test\dfs\foo
SMB2 143 Ioctl Response, Error: STATUS_OBJECT_PATH_NOT_FOUND
After patch
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-12-13 02:39:37 +00:00
|
|
|
if (rc == -EREMOTE && IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) && cifs_sb &&
|
|
|
|
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS))
|
|
|
|
rc = -EOPNOTSUPP;
|
2013-10-23 13:49:47 +00:00
|
|
|
}
|
2011-12-29 13:06:33 +00:00
|
|
|
|
|
|
|
out:
|
2022-10-03 21:43:50 +00:00
|
|
|
free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
|
|
|
|
free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
|
|
|
|
free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
|
2011-12-29 13:06:33 +00:00
|
|
|
return rc;
|
|
|
|
}
|
2011-07-19 08:56:37 +00:00
|
|
|
|
2020-06-12 00:25:47 +00:00
|
|
|
|
2022-10-03 21:43:50 +00:00
|
|
|
int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb, const char *full_path,
|
2022-11-25 11:37:44 +00:00
|
|
|
struct cifs_open_info_data *data,
|
|
|
|
struct cifs_sid *owner,
|
|
|
|
struct cifs_sid *group,
|
|
|
|
bool *adjust_tz, bool *reparse)
|
2020-06-12 00:25:47 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
__u32 create_options = 0;
|
|
|
|
struct cifsFileInfo *cfile;
|
2022-10-03 21:43:50 +00:00
|
|
|
struct kvec err_iov[3] = {};
|
|
|
|
int err_buftype[3] = {};
|
2022-11-25 11:37:44 +00:00
|
|
|
__u8 *sidsbuf = NULL;
|
|
|
|
__u8 *sidsbuf_end = NULL;
|
|
|
|
size_t sidsbuflen = 0;
|
|
|
|
size_t owner_len, group_len;
|
2020-06-12 00:25:47 +00:00
|
|
|
|
|
|
|
*adjust_tz = false;
|
2020-10-23 03:03:14 +00:00
|
|
|
*reparse = false;
|
2020-06-12 00:25:47 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* BB TODO: Add support for using the cached root handle.
|
|
|
|
* Create SMB2_query_posix_info worker function to do non-compounded query
|
|
|
|
* when we already have an open file handle for this. For now this is fast enough
|
|
|
|
* (always using the compounded version).
|
|
|
|
*/
|
|
|
|
|
|
|
|
cifs_get_readable_path(tcon, full_path, &cfile);
|
2022-10-03 21:43:50 +00:00
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
|
|
|
|
create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile,
|
2022-11-25 11:37:44 +00:00
|
|
|
&sidsbuf, &sidsbuflen, err_iov, err_buftype);
|
2020-06-12 00:25:47 +00:00
|
|
|
if (rc == -EOPNOTSUPP) {
|
|
|
|
/* BB TODO: When support for special files added to Samba re-verify this path */
|
2022-10-03 21:43:50 +00:00
|
|
|
if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER &&
|
|
|
|
((struct smb2_hdr *)err_iov[0].iov_base)->Command == SMB2_CREATE &&
|
|
|
|
((struct smb2_hdr *)err_iov[0].iov_base)->Status == STATUS_STOPPED_ON_SYMLINK) {
|
|
|
|
rc = smb2_parse_symlink_response(cifs_sb, err_iov, &data->symlink_target);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
}
|
2020-10-23 03:03:14 +00:00
|
|
|
*reparse = true;
|
2020-06-12 00:25:47 +00:00
|
|
|
create_options |= OPEN_REPARSE_POINT;
|
|
|
|
|
|
|
|
/* Failed on a symbolic link - query a reparse point info */
|
2021-07-30 06:43:09 +00:00
|
|
|
cifs_get_readable_path(tcon, full_path, &cfile);
|
2022-10-03 21:43:50 +00:00
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES,
|
|
|
|
FILE_OPEN, create_options, ACL_NO_MODE, data,
|
2022-11-25 11:37:44 +00:00
|
|
|
SMB2_OP_POSIX_QUERY_INFO, cfile,
|
|
|
|
&sidsbuf, &sidsbuflen, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc == 0) {
|
|
|
|
sidsbuf_end = sidsbuf + sidsbuflen;
|
|
|
|
|
|
|
|
owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
|
|
|
|
if (owner_len == -1) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
memcpy(owner, sidsbuf, owner_len);
|
|
|
|
|
|
|
|
group_len = posix_info_sid_size(
|
|
|
|
sidsbuf + owner_len, sidsbuf_end);
|
|
|
|
if (group_len == -1) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
memcpy(group, sidsbuf + owner_len, group_len);
|
2020-06-12 00:25:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2022-11-25 11:37:44 +00:00
|
|
|
kfree(sidsbuf);
|
2022-10-03 21:43:50 +00:00
|
|
|
free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
|
|
|
|
free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
|
|
|
|
free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
|
2020-06-12 00:25:47 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-07-19 08:56:37 +00:00
|
|
|
int
|
2019-09-25 05:32:13 +00:00
|
|
|
smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
|
|
|
|
struct cifs_tcon *tcon, const char *name,
|
2011-07-19 08:56:37 +00:00
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
2018-09-03 03:33:42 +00:00
|
|
|
return smb2_compound_op(xid, tcon, cifs_sb, name,
|
|
|
|
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
2019-09-25 05:32:13 +00:00
|
|
|
CREATE_NOT_FILE, mode, NULL, SMB2_OP_MKDIR,
|
2022-11-25 11:26:00 +00:00
|
|
|
NULL, NULL, NULL, NULL, NULL);
|
2011-07-19 08:56:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
smb2_mkdir_setinfo(struct inode *inode, const char *name,
|
|
|
|
struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
|
|
|
|
const unsigned int xid)
|
|
|
|
{
|
|
|
|
FILE_BASIC_INFO data;
|
|
|
|
struct cifsInodeInfo *cifs_i;
|
2019-08-29 23:53:56 +00:00
|
|
|
struct cifsFileInfo *cfile;
|
2011-07-19 08:56:37 +00:00
|
|
|
u32 dosattrs;
|
|
|
|
int tmprc;
|
|
|
|
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
cifs_i = CIFS_I(inode);
|
|
|
|
dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
|
|
|
|
data.Attributes = cpu_to_le32(dosattrs);
|
cifs: fix rename() by ensuring source handle opened with DELETE bit
To rename a file in SMB2 we open it with the DELETE access and do a
special SetInfo on it. If the handle is missing the DELETE bit the
server will fail the SetInfo with STATUS_ACCESS_DENIED.
We currently try to reuse any existing opened handle we have with
cifs_get_writable_path(). That function looks for handles with WRITE
access but doesn't check for DELETE, making rename() fail if it finds
a handle to reuse. Simple reproducer below.
To select handles with the DELETE bit, this patch adds a flag argument
to cifs_get_writable_path() and find_writable_file() and the existing
'bool fsuid_only' argument is converted to a flag.
The cifsFileInfo struct only stores the UNIX open mode but not the
original SMB access flags. Since the DELETE bit is not mapped in that
mode, this patch stores the access mask in cifs_fid on file open,
which is accessible from cifsFileInfo.
Simple reproducer:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define E(s) perror(s), exit(1)
int main(int argc, char *argv[])
{
int fd, ret;
if (argc != 3) {
fprintf(stderr, "Usage: %s A B\n"
"create&open A in write mode, "
"rename A to B, close A\n", argv[0]);
return 0;
}
fd = openat(AT_FDCWD, argv[1], O_WRONLY|O_CREAT|O_SYNC, 0666);
if (fd == -1) E("openat()");
ret = rename(argv[1], argv[2]);
if (ret) E("rename()");
ret = close(fd);
if (ret) E("close()");
return ret;
}
$ gcc -o bugrename bugrename.c
$ ./bugrename /mnt/a /mnt/b
rename(): Permission denied
Fixes: 8de9e86c67ba ("cifs: create a helper to find a writeable handle by path name")
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
2020-02-21 10:19:06 +00:00
|
|
|
cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
|
2018-09-03 03:33:48 +00:00
|
|
|
tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
|
|
|
|
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
2019-09-25 05:32:13 +00:00
|
|
|
CREATE_NOT_FILE, ACL_NO_MODE,
|
2022-11-25 11:26:00 +00:00
|
|
|
&data, SMB2_OP_SET_INFO, cfile, NULL, NULL, NULL, NULL);
|
2011-07-19 08:56:37 +00:00
|
|
|
if (tmprc == 0)
|
|
|
|
cifs_i->cifsAttrs = dosattrs;
|
|
|
|
}
|
2012-07-10 12:14:38 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
2022-10-18 07:39:10 +00:00
|
|
|
drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
|
2018-09-03 03:33:45 +00:00
|
|
|
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
|
2019-09-25 05:32:13 +00:00
|
|
|
CREATE_NOT_FILE, ACL_NO_MODE,
|
2022-11-25 11:26:00 +00:00
|
|
|
NULL, SMB2_OP_RMDIR, NULL, NULL, NULL, NULL, NULL);
|
2012-07-10 12:14:38 +00:00
|
|
|
}
|
2012-09-18 23:20:25 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
2018-09-03 03:33:43 +00:00
|
|
|
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
|
|
|
|
CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
|
2022-11-25 11:26:00 +00:00
|
|
|
ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL, NULL, NULL, NULL, NULL);
|
2012-09-18 23:20:25 +00:00
|
|
|
}
|
2012-09-18 23:20:31 +00:00
|
|
|
|
2012-09-18 23:20:31 +00:00
|
|
|
static int
|
|
|
|
smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const char *from_name, const char *to_name,
|
2019-08-29 22:25:46 +00:00
|
|
|
struct cifs_sb_info *cifs_sb, __u32 access, int command,
|
|
|
|
struct cifsFileInfo *cfile)
|
2012-09-18 23:20:31 +00:00
|
|
|
{
|
|
|
|
__le16 *smb2_to_name = NULL;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
|
|
|
|
if (smb2_to_name == NULL) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto smb2_rename_path;
|
|
|
|
}
|
2018-09-03 03:33:49 +00:00
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
|
2019-09-25 05:32:13 +00:00
|
|
|
FILE_OPEN, 0, ACL_NO_MODE, smb2_to_name,
|
2022-11-25 11:26:00 +00:00
|
|
|
command, cfile, NULL, NULL, NULL, NULL);
|
2012-09-18 23:20:31 +00:00
|
|
|
smb2_rename_path:
|
|
|
|
kfree(smb2_to_name);
|
|
|
|
return rc;
|
|
|
|
}
|
2012-09-18 23:20:31 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const char *from_name, const char *to_name,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
2019-08-29 22:25:46 +00:00
|
|
|
struct cifsFileInfo *cfile;
|
|
|
|
|
2022-10-18 07:39:10 +00:00
|
|
|
drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
|
cifs: fix rename() by ensuring source handle opened with DELETE bit
To rename a file in SMB2 we open it with the DELETE access and do a
special SetInfo on it. If the handle is missing the DELETE bit the
server will fail the SetInfo with STATUS_ACCESS_DENIED.
We currently try to reuse any existing opened handle we have with
cifs_get_writable_path(). That function looks for handles with WRITE
access but doesn't check for DELETE, making rename() fail if it finds
a handle to reuse. Simple reproducer below.
To select handles with the DELETE bit, this patch adds a flag argument
to cifs_get_writable_path() and find_writable_file() and the existing
'bool fsuid_only' argument is converted to a flag.
The cifsFileInfo struct only stores the UNIX open mode but not the
original SMB access flags. Since the DELETE bit is not mapped in that
mode, this patch stores the access mask in cifs_fid on file open,
which is accessible from cifsFileInfo.
Simple reproducer:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define E(s) perror(s), exit(1)
int main(int argc, char *argv[])
{
int fd, ret;
if (argc != 3) {
fprintf(stderr, "Usage: %s A B\n"
"create&open A in write mode, "
"rename A to B, close A\n", argv[0]);
return 0;
}
fd = openat(AT_FDCWD, argv[1], O_WRONLY|O_CREAT|O_SYNC, 0666);
if (fd == -1) E("openat()");
ret = rename(argv[1], argv[2]);
if (ret) E("rename()");
ret = close(fd);
if (ret) E("close()");
return ret;
}
$ gcc -o bugrename bugrename.c
$ ./bugrename /mnt/a /mnt/b
rename(): Permission denied
Fixes: 8de9e86c67ba ("cifs: create a helper to find a writeable handle by path name")
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
2020-02-21 10:19:06 +00:00
|
|
|
cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
|
2019-08-29 22:25:46 +00:00
|
|
|
|
|
|
|
return smb2_set_path_attr(xid, tcon, from_name, to_name,
|
|
|
|
cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
|
2012-09-18 23:20:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const char *from_name, const char *to_name,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
|
|
|
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
|
2019-08-29 22:25:46 +00:00
|
|
|
FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK,
|
|
|
|
NULL);
|
2012-09-18 23:20:31 +00:00
|
|
|
}
|
2012-09-18 23:20:32 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const char *full_path, __u64 size,
|
|
|
|
struct cifs_sb_info *cifs_sb, bool set_alloc)
|
|
|
|
{
|
|
|
|
__le64 eof = cpu_to_le64(size);
|
2021-07-30 06:43:09 +00:00
|
|
|
struct cifsFileInfo *cfile;
|
2018-09-03 03:33:46 +00:00
|
|
|
|
2021-07-30 06:43:09 +00:00
|
|
|
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
2018-09-03 03:33:46 +00:00
|
|
|
return smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
2019-09-25 05:32:13 +00:00
|
|
|
FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE,
|
2022-11-25 11:26:00 +00:00
|
|
|
&eof, SMB2_OP_SET_EOF, cfile, NULL, NULL, NULL, NULL);
|
2012-09-18 23:20:32 +00:00
|
|
|
}
|
2012-09-18 23:20:32 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
smb2_set_file_info(struct inode *inode, const char *full_path,
|
|
|
|
FILE_BASIC_INFO *buf, const unsigned int xid)
|
|
|
|
{
|
|
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
|
|
struct tcon_link *tlink;
|
2021-07-30 06:43:09 +00:00
|
|
|
struct cifs_tcon *tcon;
|
|
|
|
struct cifsFileInfo *cfile;
|
2012-09-18 23:20:32 +00:00
|
|
|
int rc;
|
|
|
|
|
2016-09-26 19:23:08 +00:00
|
|
|
if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
|
2018-08-03 01:28:18 +00:00
|
|
|
(buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
|
2016-09-26 19:23:08 +00:00
|
|
|
(buf->Attributes == 0))
|
|
|
|
return 0; /* would be a no op, no sense sending this */
|
|
|
|
|
2012-09-18 23:20:32 +00:00
|
|
|
tlink = cifs_sb_tlink(cifs_sb);
|
|
|
|
if (IS_ERR(tlink))
|
|
|
|
return PTR_ERR(tlink);
|
2021-07-30 06:43:09 +00:00
|
|
|
tcon = tlink_tcon(tlink);
|
2016-09-26 19:23:08 +00:00
|
|
|
|
2021-07-30 06:43:09 +00:00
|
|
|
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
2019-09-25 05:32:13 +00:00
|
|
|
FILE_WRITE_ATTRIBUTES, FILE_OPEN,
|
2022-10-03 21:43:50 +00:00
|
|
|
0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, cfile,
|
2022-11-25 11:26:00 +00:00
|
|
|
NULL, NULL, NULL, NULL);
|
2012-09-18 23:20:32 +00:00
|
|
|
cifs_put_tlink(tlink);
|
|
|
|
return rc;
|
|
|
|
}
|