1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3 *
4 * Copyright (C) International Business Machines Corp., 2002, 2011
5 * Etersoft, 2012
6 * Author(s): Pavel Shilovsky (pshilovsky@samba.org),
7 * Steve French (sfrench@us.ibm.com)
8 *
9 */
10 #include <linux/fs.h>
11 #include <linux/stat.h>
12 #include <linux/slab.h>
13 #include <linux/pagemap.h>
14 #include <asm/div64.h>
15 #include "cifsfs.h"
16 #include "cifspdu.h"
17 #include "cifsglob.h"
18 #include "cifsproto.h"
19 #include "cifs_debug.h"
20 #include "cifs_fs_sb.h"
21 #include "cifs_unicode.h"
22 #include "fscache.h"
23 #include "smb2glob.h"
24 #include "smb2pdu.h"
25 #include "smb2proto.h"
26 #include "cached_dir.h"
27 #include "../common/smb2status.h"
28
reparse_buf_ptr(struct kvec * iov)29 static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
30 {
31 struct reparse_data_buffer *buf;
32 struct smb2_ioctl_rsp *io = iov->iov_base;
33 u32 off, count, len;
34
35 count = le32_to_cpu(io->OutputCount);
36 off = le32_to_cpu(io->OutputOffset);
37 if (check_add_overflow(off, count, &len) || len > iov->iov_len)
38 return ERR_PTR(-EIO);
39
40 buf = (struct reparse_data_buffer *)((u8 *)io + off);
41 len = sizeof(*buf);
42 if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
43 return ERR_PTR(-EIO);
44 return buf;
45 }
46
file_create_options(struct dentry * dentry)47 static inline __u32 file_create_options(struct dentry *dentry)
48 {
49 struct cifsInodeInfo *ci;
50
51 if (dentry) {
52 ci = CIFS_I(d_inode(dentry));
53 if (ci->cifsAttrs & ATTR_REPARSE)
54 return OPEN_REPARSE_POINT;
55 }
56 return 0;
57 }
58
59 /* Parse owner and group from SMB3.1.1 POSIX query info */
parse_posix_sids(struct cifs_open_info_data * data,struct kvec * rsp_iov)60 static int parse_posix_sids(struct cifs_open_info_data *data,
61 struct kvec *rsp_iov)
62 {
63 struct smb2_query_info_rsp *qi = rsp_iov->iov_base;
64 unsigned int out_len = le32_to_cpu(qi->OutputBufferLength);
65 unsigned int qi_len = sizeof(data->posix_fi);
66 int owner_len, group_len;
67 u8 *sidsbuf, *sidsbuf_end;
68
69 if (out_len <= qi_len)
70 return -EINVAL;
71
72 sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
73 sidsbuf_end = sidsbuf + out_len - qi_len;
74
75 owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
76 if (owner_len == -1)
77 return -EINVAL;
78
79 memcpy(&data->posix_owner, sidsbuf, owner_len);
80 group_len = posix_info_sid_size(sidsbuf + owner_len, sidsbuf_end);
81 if (group_len == -1)
82 return -EINVAL;
83
84 memcpy(&data->posix_group, sidsbuf + owner_len, group_len);
85 return 0;
86 }
87
88 struct wsl_query_ea {
89 __le32 next;
90 __u8 name_len;
91 __u8 name[SMB2_WSL_XATTR_NAME_LEN + 1];
92 } __packed;
93
94 #define NEXT_OFF cpu_to_le32(sizeof(struct wsl_query_ea))
95
96 static const struct wsl_query_ea wsl_query_eas[] = {
97 { .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_UID, },
98 { .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_GID, },
99 { .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_MODE, },
100 { .next = 0, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_DEV, },
101 };
102
check_wsl_eas(struct kvec * rsp_iov)103 static int check_wsl_eas(struct kvec *rsp_iov)
104 {
105 struct smb2_file_full_ea_info *ea;
106 struct smb2_query_info_rsp *rsp = rsp_iov->iov_base;
107 unsigned long addr;
108 u32 outlen, next;
109 u16 vlen;
110 u8 nlen;
111 u8 *end;
112
113 outlen = le32_to_cpu(rsp->OutputBufferLength);
114 if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
115 outlen > SMB2_WSL_MAX_QUERY_EA_RESP_SIZE)
116 return -EINVAL;
117
118 ea = (void *)((u8 *)rsp_iov->iov_base +
119 le16_to_cpu(rsp->OutputBufferOffset));
120 end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
121 for (;;) {
122 if ((u8 *)ea > end - sizeof(*ea))
123 return -EINVAL;
124
125 nlen = ea->ea_name_length;
126 vlen = le16_to_cpu(ea->ea_value_length);
127 if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
128 (u8 *)ea + nlen + 1 + vlen > end)
129 return -EINVAL;
130
131 switch (vlen) {
132 case 4:
133 if (strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) &&
134 strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) &&
135 strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen))
136 return -EINVAL;
137 break;
138 case 8:
139 if (strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
140 return -EINVAL;
141 break;
142 case 0:
143 if (!strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) ||
144 !strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) ||
145 !strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen) ||
146 !strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
147 break;
148 fallthrough;
149 default:
150 return -EINVAL;
151 }
152
153 next = le32_to_cpu(ea->next_entry_offset);
154 if (!next)
155 break;
156 if (!IS_ALIGNED(next, 4) ||
157 check_add_overflow((unsigned long)ea, next, &addr))
158 return -EINVAL;
159 ea = (void *)addr;
160 }
161 return 0;
162 }
163
164 /*
165 * note: If cfile is passed, the reference to it is dropped here.
166 * So make sure that you do not reuse cfile after return from this func.
167 *
168 * If passing @out_iov and @out_buftype, ensure to make them both large enough
169 * (>= 3) to hold all compounded responses. Caller is also responsible for
170 * freeing them up with free_rsp_buf().
171 */
smb2_compound_op(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,struct cifs_open_parms * oparms,struct kvec * in_iov,int * cmds,int num_cmds,struct cifsFileInfo * cfile,struct kvec * out_iov,int * out_buftype,struct dentry * dentry)172 static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
173 struct cifs_sb_info *cifs_sb, const char *full_path,
174 struct cifs_open_parms *oparms, struct kvec *in_iov,
175 int *cmds, int num_cmds, struct cifsFileInfo *cfile,
176 struct kvec *out_iov, int *out_buftype, struct dentry *dentry)
177 {
178
179 struct smb2_query_info_rsp *qi_rsp = NULL;
180 struct smb2_compound_vars *vars = NULL;
181 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
182 struct cifs_open_info_data *idata;
183 struct cifs_ses *ses = tcon->ses;
184 struct reparse_data_buffer *rbuf;
185 struct TCP_Server_Info *server;
186 int resp_buftype[MAX_COMPOUND];
187 int retries = 0, cur_sleep = 1;
188 __u8 delete_pending[8] = {1,};
189 struct kvec *rsp_iov, *iov;
190 struct inode *inode = NULL;
191 __le16 *utf16_path = NULL;
192 struct smb_rqst *rqst;
193 unsigned int size[2];
194 struct cifs_fid fid;
195 int num_rqst = 0, i;
196 unsigned int len;
197 int tmp_rc, rc;
198 int flags = 0;
199 void *data[2];
200
201 replay_again:
202 /* reinitialize for possible replay */
203 flags = 0;
204 oplock = SMB2_OPLOCK_LEVEL_NONE;
205 num_rqst = 0;
206 server = cifs_pick_channel(ses);
207
208 vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
209 if (vars == NULL) {
210 rc = -ENOMEM;
211 goto out;
212 }
213 rqst = &vars->rqst[0];
214 rsp_iov = &vars->rsp_iov[0];
215
216 if (smb3_encryption_required(tcon))
217 flags |= CIFS_TRANSFORM_REQ;
218
219 for (i = 0; i < ARRAY_SIZE(resp_buftype); i++)
220 resp_buftype[i] = CIFS_NO_BUFFER;
221
222 /* We already have a handle so we can skip the open */
223 if (cfile)
224 goto after_open;
225
226 /* Open */
227 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
228 if (!utf16_path) {
229 rc = -ENOMEM;
230 goto finished;
231 }
232
233 /* if there is an existing lease, reuse it */
234
235 /*
236 * note: files with hardlinks cause unexpected behaviour. As per MS-SMB2,
237 * lease keys are associated with the filepath. We are maintaining lease keys
238 * with the inode on the client. If the file has hardlinks, it is possible
239 * that the lease for a file be reused for an operation on its hardlink or
240 * vice versa.
241 * As a workaround, send request using an existing lease key and if the server
242 * returns STATUS_INVALID_PARAMETER, which maps to EINVAL, send the request
243 * again without the lease.
244 */
245 if (dentry) {
246 inode = d_inode(dentry);
247 if (CIFS_I(inode)->lease_granted && server->ops->get_lease_key) {
248 oplock = SMB2_OPLOCK_LEVEL_LEASE;
249 server->ops->get_lease_key(inode, &fid);
250 }
251 }
252
253 vars->oparms = *oparms;
254 vars->oparms.fid = &fid;
255
256 rqst[num_rqst].rq_iov = &vars->open_iov[0];
257 rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
258 rc = SMB2_open_init(tcon, server,
259 &rqst[num_rqst], &oplock, &vars->oparms,
260 utf16_path);
261 kfree(utf16_path);
262 if (rc)
263 goto finished;
264
265 smb2_set_next_command(tcon, &rqst[num_rqst]);
266 after_open:
267 num_rqst++;
268 rc = 0;
269
270 for (i = 0; i < num_cmds; i++) {
271 /* Operation */
272 switch (cmds[i]) {
273 case SMB2_OP_QUERY_INFO:
274 rqst[num_rqst].rq_iov = &vars->qi_iov;
275 rqst[num_rqst].rq_nvec = 1;
276
277 if (cfile) {
278 rc = SMB2_query_info_init(tcon, server,
279 &rqst[num_rqst],
280 cfile->fid.persistent_fid,
281 cfile->fid.volatile_fid,
282 FILE_ALL_INFORMATION,
283 SMB2_O_INFO_FILE, 0,
284 sizeof(struct smb2_file_all_info) +
285 PATH_MAX * 2, 0, NULL);
286 } else {
287 rc = SMB2_query_info_init(tcon, server,
288 &rqst[num_rqst],
289 COMPOUND_FID,
290 COMPOUND_FID,
291 FILE_ALL_INFORMATION,
292 SMB2_O_INFO_FILE, 0,
293 sizeof(struct smb2_file_all_info) +
294 PATH_MAX * 2, 0, NULL);
295 }
296 if (!rc && (!cfile || num_rqst > 1)) {
297 smb2_set_next_command(tcon, &rqst[num_rqst]);
298 smb2_set_related(&rqst[num_rqst]);
299 } else if (rc) {
300 goto finished;
301 }
302 num_rqst++;
303 trace_smb3_query_info_compound_enter(xid, tcon->tid,
304 ses->Suid, full_path);
305 break;
306 case SMB2_OP_POSIX_QUERY_INFO:
307 rqst[num_rqst].rq_iov = &vars->qi_iov;
308 rqst[num_rqst].rq_nvec = 1;
309
310 if (cfile) {
311 /* TBD: fix following to allow for longer SIDs */
312 rc = SMB2_query_info_init(tcon, server,
313 &rqst[num_rqst],
314 cfile->fid.persistent_fid,
315 cfile->fid.volatile_fid,
316 SMB_FIND_FILE_POSIX_INFO,
317 SMB2_O_INFO_FILE, 0,
318 sizeof(struct smb311_posix_qinfo *) +
319 (PATH_MAX * 2) +
320 (sizeof(struct smb_sid) * 2), 0, NULL);
321 } else {
322 rc = SMB2_query_info_init(tcon, server,
323 &rqst[num_rqst],
324 COMPOUND_FID,
325 COMPOUND_FID,
326 SMB_FIND_FILE_POSIX_INFO,
327 SMB2_O_INFO_FILE, 0,
328 sizeof(struct smb311_posix_qinfo *) +
329 (PATH_MAX * 2) +
330 (sizeof(struct smb_sid) * 2), 0, NULL);
331 }
332 if (!rc && (!cfile || num_rqst > 1)) {
333 smb2_set_next_command(tcon, &rqst[num_rqst]);
334 smb2_set_related(&rqst[num_rqst]);
335 } else if (rc) {
336 goto finished;
337 }
338 num_rqst++;
339 trace_smb3_posix_query_info_compound_enter(xid, tcon->tid,
340 ses->Suid, full_path);
341 break;
342 case SMB2_OP_DELETE:
343 trace_smb3_delete_enter(xid, tcon->tid, ses->Suid, full_path);
344 break;
345 case SMB2_OP_MKDIR:
346 /*
347 * Directories are created through parameters in the
348 * SMB2_open() call.
349 */
350 trace_smb3_mkdir_enter(xid, tcon->tid, ses->Suid, full_path);
351 break;
352 case SMB2_OP_RMDIR:
353 rqst[num_rqst].rq_iov = &vars->si_iov[0];
354 rqst[num_rqst].rq_nvec = 1;
355
356 size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
357 data[0] = &delete_pending[0];
358
359 rc = SMB2_set_info_init(tcon, server,
360 &rqst[num_rqst], COMPOUND_FID,
361 COMPOUND_FID, current->tgid,
362 FILE_DISPOSITION_INFORMATION,
363 SMB2_O_INFO_FILE, 0, data, size);
364 if (rc)
365 goto finished;
366 smb2_set_next_command(tcon, &rqst[num_rqst]);
367 smb2_set_related(&rqst[num_rqst++]);
368 trace_smb3_rmdir_enter(xid, tcon->tid, ses->Suid, full_path);
369 break;
370 case SMB2_OP_SET_EOF:
371 rqst[num_rqst].rq_iov = &vars->si_iov[0];
372 rqst[num_rqst].rq_nvec = 1;
373
374 size[0] = in_iov[i].iov_len;
375 data[0] = in_iov[i].iov_base;
376
377 if (cfile) {
378 rc = SMB2_set_info_init(tcon, server,
379 &rqst[num_rqst],
380 cfile->fid.persistent_fid,
381 cfile->fid.volatile_fid,
382 current->tgid,
383 FILE_END_OF_FILE_INFORMATION,
384 SMB2_O_INFO_FILE, 0,
385 data, size);
386 } else {
387 rc = SMB2_set_info_init(tcon, server,
388 &rqst[num_rqst],
389 COMPOUND_FID,
390 COMPOUND_FID,
391 current->tgid,
392 FILE_END_OF_FILE_INFORMATION,
393 SMB2_O_INFO_FILE, 0,
394 data, size);
395 }
396 if (!rc && (!cfile || num_rqst > 1)) {
397 smb2_set_next_command(tcon, &rqst[num_rqst]);
398 smb2_set_related(&rqst[num_rqst]);
399 } else if (rc) {
400 goto finished;
401 }
402 num_rqst++;
403 trace_smb3_set_eof_enter(xid, tcon->tid, ses->Suid, full_path);
404 break;
405 case SMB2_OP_SET_INFO:
406 rqst[num_rqst].rq_iov = &vars->si_iov[0];
407 rqst[num_rqst].rq_nvec = 1;
408
409 size[0] = in_iov[i].iov_len;
410 data[0] = in_iov[i].iov_base;
411
412 if (cfile) {
413 rc = SMB2_set_info_init(tcon, server,
414 &rqst[num_rqst],
415 cfile->fid.persistent_fid,
416 cfile->fid.volatile_fid, current->tgid,
417 FILE_BASIC_INFORMATION,
418 SMB2_O_INFO_FILE, 0, data, size);
419 } else {
420 rc = SMB2_set_info_init(tcon, server,
421 &rqst[num_rqst],
422 COMPOUND_FID,
423 COMPOUND_FID, current->tgid,
424 FILE_BASIC_INFORMATION,
425 SMB2_O_INFO_FILE, 0, data, size);
426 }
427 if (!rc && (!cfile || num_rqst > 1)) {
428 smb2_set_next_command(tcon, &rqst[num_rqst]);
429 smb2_set_related(&rqst[num_rqst]);
430 } else if (rc) {
431 goto finished;
432 }
433 num_rqst++;
434 trace_smb3_set_info_compound_enter(xid, tcon->tid,
435 ses->Suid, full_path);
436 break;
437 case SMB2_OP_RENAME:
438 rqst[num_rqst].rq_iov = &vars->si_iov[0];
439 rqst[num_rqst].rq_nvec = 2;
440
441 len = in_iov[i].iov_len;
442
443 vars->rename_info.ReplaceIfExists = 1;
444 vars->rename_info.RootDirectory = 0;
445 vars->rename_info.FileNameLength = cpu_to_le32(len);
446
447 size[0] = sizeof(struct smb2_file_rename_info);
448 data[0] = &vars->rename_info;
449
450 size[1] = len + 2 /* null */;
451 data[1] = in_iov[i].iov_base;
452
453 if (cfile) {
454 rc = SMB2_set_info_init(tcon, server,
455 &rqst[num_rqst],
456 cfile->fid.persistent_fid,
457 cfile->fid.volatile_fid,
458 current->tgid, FILE_RENAME_INFORMATION,
459 SMB2_O_INFO_FILE, 0, data, size);
460 } else {
461 rc = SMB2_set_info_init(tcon, server,
462 &rqst[num_rqst],
463 COMPOUND_FID, COMPOUND_FID,
464 current->tgid, FILE_RENAME_INFORMATION,
465 SMB2_O_INFO_FILE, 0, data, size);
466 }
467 if (!rc && (!cfile || num_rqst > 1)) {
468 smb2_set_next_command(tcon, &rqst[num_rqst]);
469 smb2_set_related(&rqst[num_rqst]);
470 } else if (rc) {
471 goto finished;
472 }
473 num_rqst++;
474 trace_smb3_rename_enter(xid, tcon->tid, ses->Suid, full_path);
475 break;
476 case SMB2_OP_HARDLINK:
477 rqst[num_rqst].rq_iov = &vars->si_iov[0];
478 rqst[num_rqst].rq_nvec = 2;
479
480 len = in_iov[i].iov_len;
481
482 vars->link_info.ReplaceIfExists = 0;
483 vars->link_info.RootDirectory = 0;
484 vars->link_info.FileNameLength = cpu_to_le32(len);
485
486 size[0] = sizeof(struct smb2_file_link_info);
487 data[0] = &vars->link_info;
488
489 size[1] = len + 2 /* null */;
490 data[1] = in_iov[i].iov_base;
491
492 rc = SMB2_set_info_init(tcon, server,
493 &rqst[num_rqst], COMPOUND_FID,
494 COMPOUND_FID, current->tgid,
495 FILE_LINK_INFORMATION,
496 SMB2_O_INFO_FILE, 0, data, size);
497 if (rc)
498 goto finished;
499 smb2_set_next_command(tcon, &rqst[num_rqst]);
500 smb2_set_related(&rqst[num_rqst++]);
501 trace_smb3_hardlink_enter(xid, tcon->tid, ses->Suid, full_path);
502 break;
503 case SMB2_OP_SET_REPARSE:
504 rqst[num_rqst].rq_iov = vars->io_iov;
505 rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
506
507 if (cfile) {
508 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
509 cfile->fid.persistent_fid,
510 cfile->fid.volatile_fid,
511 FSCTL_SET_REPARSE_POINT,
512 in_iov[i].iov_base,
513 in_iov[i].iov_len, 0);
514 } else {
515 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
516 COMPOUND_FID, COMPOUND_FID,
517 FSCTL_SET_REPARSE_POINT,
518 in_iov[i].iov_base,
519 in_iov[i].iov_len, 0);
520 }
521 if (!rc && (!cfile || num_rqst > 1)) {
522 smb2_set_next_command(tcon, &rqst[num_rqst]);
523 smb2_set_related(&rqst[num_rqst]);
524 } else if (rc) {
525 goto finished;
526 }
527 num_rqst++;
528 trace_smb3_set_reparse_compound_enter(xid, tcon->tid,
529 ses->Suid, full_path);
530 break;
531 case SMB2_OP_GET_REPARSE:
532 rqst[num_rqst].rq_iov = vars->io_iov;
533 rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
534
535 if (cfile) {
536 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
537 cfile->fid.persistent_fid,
538 cfile->fid.volatile_fid,
539 FSCTL_GET_REPARSE_POINT,
540 NULL, 0, CIFSMaxBufSize);
541 } else {
542 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
543 COMPOUND_FID, COMPOUND_FID,
544 FSCTL_GET_REPARSE_POINT,
545 NULL, 0, CIFSMaxBufSize);
546 }
547 if (!rc && (!cfile || num_rqst > 1)) {
548 smb2_set_next_command(tcon, &rqst[num_rqst]);
549 smb2_set_related(&rqst[num_rqst]);
550 } else if (rc) {
551 goto finished;
552 }
553 num_rqst++;
554 trace_smb3_get_reparse_compound_enter(xid, tcon->tid,
555 ses->Suid, full_path);
556 break;
557 case SMB2_OP_QUERY_WSL_EA:
558 rqst[num_rqst].rq_iov = &vars->ea_iov;
559 rqst[num_rqst].rq_nvec = 1;
560
561 if (cfile) {
562 rc = SMB2_query_info_init(tcon, server,
563 &rqst[num_rqst],
564 cfile->fid.persistent_fid,
565 cfile->fid.volatile_fid,
566 FILE_FULL_EA_INFORMATION,
567 SMB2_O_INFO_FILE, 0,
568 SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
569 sizeof(wsl_query_eas),
570 (void *)wsl_query_eas);
571 } else {
572 rc = SMB2_query_info_init(tcon, server,
573 &rqst[num_rqst],
574 COMPOUND_FID,
575 COMPOUND_FID,
576 FILE_FULL_EA_INFORMATION,
577 SMB2_O_INFO_FILE, 0,
578 SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
579 sizeof(wsl_query_eas),
580 (void *)wsl_query_eas);
581 }
582 if (!rc && (!cfile || num_rqst > 1)) {
583 smb2_set_next_command(tcon, &rqst[num_rqst]);
584 smb2_set_related(&rqst[num_rqst]);
585 } else if (rc) {
586 goto finished;
587 }
588 num_rqst++;
589 break;
590 default:
591 cifs_dbg(VFS, "Invalid command\n");
592 rc = -EINVAL;
593 }
594 }
595 if (rc)
596 goto finished;
597
598 /* We already have a handle so we can skip the close */
599 if (cfile)
600 goto after_close;
601 /* Close */
602 flags |= CIFS_CP_CREATE_CLOSE_OP;
603 rqst[num_rqst].rq_iov = &vars->close_iov;
604 rqst[num_rqst].rq_nvec = 1;
605 rc = SMB2_close_init(tcon, server,
606 &rqst[num_rqst], COMPOUND_FID,
607 COMPOUND_FID, false);
608 smb2_set_related(&rqst[num_rqst]);
609 if (rc)
610 goto finished;
611 after_close:
612 num_rqst++;
613
614 if (cfile) {
615 if (retries)
616 for (i = 1; i < num_rqst - 2; i++)
617 smb2_set_replay(server, &rqst[i]);
618
619 rc = compound_send_recv(xid, ses, server,
620 flags, num_rqst - 2,
621 &rqst[1], &resp_buftype[1],
622 &rsp_iov[1]);
623 } else {
624 if (retries)
625 for (i = 0; i < num_rqst; i++)
626 smb2_set_replay(server, &rqst[i]);
627
628 rc = compound_send_recv(xid, ses, server,
629 flags, num_rqst,
630 rqst, resp_buftype,
631 rsp_iov);
632 }
633
634 finished:
635 num_rqst = 0;
636 SMB2_open_free(&rqst[num_rqst++]);
637 if (rc == -EREMCHG) {
638 pr_warn_once("server share %s deleted\n", tcon->tree_name);
639 tcon->need_reconnect = true;
640 }
641
642 tmp_rc = rc;
643 for (i = 0; i < num_cmds; i++) {
644 char *buf = rsp_iov[i + 1].iov_base;
645
646 if (buf && resp_buftype[i + 1] != CIFS_NO_BUFFER)
647 rc = server->ops->map_error(buf, false);
648 else
649 rc = tmp_rc;
650 switch (cmds[i]) {
651 case SMB2_OP_QUERY_INFO:
652 idata = in_iov[i].iov_base;
653 idata->contains_posix_file_info = false;
654 if (rc == 0 && cfile && cfile->symlink_target) {
655 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
656 if (!idata->symlink_target)
657 rc = -ENOMEM;
658 }
659 if (rc == 0) {
660 qi_rsp = (struct smb2_query_info_rsp *)
661 rsp_iov[i + 1].iov_base;
662 rc = smb2_validate_and_copy_iov(
663 le16_to_cpu(qi_rsp->OutputBufferOffset),
664 le32_to_cpu(qi_rsp->OutputBufferLength),
665 &rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi);
666 }
667 SMB2_query_info_free(&rqst[num_rqst++]);
668 if (rc)
669 trace_smb3_query_info_compound_err(xid, tcon->tid,
670 ses->Suid, rc);
671 else
672 trace_smb3_query_info_compound_done(xid, tcon->tid,
673 ses->Suid);
674 break;
675 case SMB2_OP_POSIX_QUERY_INFO:
676 idata = in_iov[i].iov_base;
677 idata->contains_posix_file_info = true;
678 if (rc == 0 && cfile && cfile->symlink_target) {
679 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
680 if (!idata->symlink_target)
681 rc = -ENOMEM;
682 }
683 if (rc == 0) {
684 qi_rsp = (struct smb2_query_info_rsp *)
685 rsp_iov[i + 1].iov_base;
686 rc = smb2_validate_and_copy_iov(
687 le16_to_cpu(qi_rsp->OutputBufferOffset),
688 le32_to_cpu(qi_rsp->OutputBufferLength),
689 &rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,
690 (char *)&idata->posix_fi);
691 }
692 if (rc == 0)
693 rc = parse_posix_sids(idata, &rsp_iov[i + 1]);
694
695 SMB2_query_info_free(&rqst[num_rqst++]);
696 if (rc)
697 trace_smb3_posix_query_info_compound_err(xid, tcon->tid,
698 ses->Suid, rc);
699 else
700 trace_smb3_posix_query_info_compound_done(xid, tcon->tid,
701 ses->Suid);
702 break;
703 case SMB2_OP_DELETE:
704 if (rc)
705 trace_smb3_delete_err(xid, tcon->tid, ses->Suid, rc);
706 else {
707 /*
708 * If dentry (hence, inode) is NULL, lease break is going to
709 * take care of degrading leases on handles for deleted files.
710 */
711 if (inode)
712 cifs_mark_open_handles_for_deleted_file(inode, full_path);
713 trace_smb3_delete_done(xid, tcon->tid, ses->Suid);
714 }
715 break;
716 case SMB2_OP_MKDIR:
717 if (rc)
718 trace_smb3_mkdir_err(xid, tcon->tid, ses->Suid, rc);
719 else
720 trace_smb3_mkdir_done(xid, tcon->tid, ses->Suid);
721 break;
722 case SMB2_OP_HARDLINK:
723 if (rc)
724 trace_smb3_hardlink_err(xid, tcon->tid, ses->Suid, rc);
725 else
726 trace_smb3_hardlink_done(xid, tcon->tid, ses->Suid);
727 SMB2_set_info_free(&rqst[num_rqst++]);
728 break;
729 case SMB2_OP_RENAME:
730 if (rc)
731 trace_smb3_rename_err(xid, tcon->tid, ses->Suid, rc);
732 else
733 trace_smb3_rename_done(xid, tcon->tid, ses->Suid);
734 SMB2_set_info_free(&rqst[num_rqst++]);
735 break;
736 case SMB2_OP_RMDIR:
737 if (rc)
738 trace_smb3_rmdir_err(xid, tcon->tid, ses->Suid, rc);
739 else
740 trace_smb3_rmdir_done(xid, tcon->tid, ses->Suid);
741 SMB2_set_info_free(&rqst[num_rqst++]);
742 break;
743 case SMB2_OP_SET_EOF:
744 if (rc)
745 trace_smb3_set_eof_err(xid, tcon->tid, ses->Suid, rc);
746 else
747 trace_smb3_set_eof_done(xid, tcon->tid, ses->Suid);
748 SMB2_set_info_free(&rqst[num_rqst++]);
749 break;
750 case SMB2_OP_SET_INFO:
751 if (rc)
752 trace_smb3_set_info_compound_err(xid, tcon->tid,
753 ses->Suid, rc);
754 else
755 trace_smb3_set_info_compound_done(xid, tcon->tid,
756 ses->Suid);
757 SMB2_set_info_free(&rqst[num_rqst++]);
758 break;
759 case SMB2_OP_SET_REPARSE:
760 if (rc) {
761 trace_smb3_set_reparse_compound_err(xid, tcon->tid,
762 ses->Suid, rc);
763 } else {
764 trace_smb3_set_reparse_compound_done(xid, tcon->tid,
765 ses->Suid);
766 }
767 SMB2_ioctl_free(&rqst[num_rqst++]);
768 break;
769 case SMB2_OP_GET_REPARSE:
770 if (!rc) {
771 iov = &rsp_iov[i + 1];
772 idata = in_iov[i].iov_base;
773 idata->reparse.io.iov = *iov;
774 idata->reparse.io.buftype = resp_buftype[i + 1];
775 idata->contains_posix_file_info = false; /* BB VERIFY */
776 rbuf = reparse_buf_ptr(iov);
777 if (IS_ERR(rbuf)) {
778 rc = PTR_ERR(rbuf);
779 trace_smb3_get_reparse_compound_err(xid, tcon->tid,
780 ses->Suid, rc);
781 } else {
782 idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
783 trace_smb3_get_reparse_compound_done(xid, tcon->tid,
784 ses->Suid);
785 }
786 memset(iov, 0, sizeof(*iov));
787 resp_buftype[i + 1] = CIFS_NO_BUFFER;
788 } else {
789 trace_smb3_get_reparse_compound_err(xid, tcon->tid,
790 ses->Suid, rc);
791 }
792 SMB2_ioctl_free(&rqst[num_rqst++]);
793 break;
794 case SMB2_OP_QUERY_WSL_EA:
795 if (!rc) {
796 idata = in_iov[i].iov_base;
797 idata->contains_posix_file_info = false;
798 qi_rsp = rsp_iov[i + 1].iov_base;
799 data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
800 size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);
801 rc = check_wsl_eas(&rsp_iov[i + 1]);
802 if (!rc) {
803 memcpy(idata->wsl.eas, data[0], size[0]);
804 idata->wsl.eas_len = size[0];
805 }
806 }
807 if (!rc) {
808 trace_smb3_query_wsl_ea_compound_done(xid, tcon->tid,
809 ses->Suid);
810 } else {
811 trace_smb3_query_wsl_ea_compound_err(xid, tcon->tid,
812 ses->Suid, rc);
813 }
814 SMB2_query_info_free(&rqst[num_rqst++]);
815 break;
816 }
817 }
818 SMB2_close_free(&rqst[num_rqst]);
819 rc = tmp_rc;
820
821 num_cmds += 2;
822 if (out_iov && out_buftype) {
823 memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
824 memcpy(out_buftype, resp_buftype,
825 num_cmds * sizeof(*out_buftype));
826 } else {
827 for (i = 0; i < num_cmds; i++)
828 free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
829 }
830 num_cmds -= 2; /* correct num_cmds as there could be a retry */
831 kfree(vars);
832
833 if (is_replayable_error(rc) &&
834 smb2_should_replay(tcon, &retries, &cur_sleep))
835 goto replay_again;
836
837 out:
838 if (cfile)
839 cifsFileInfo_put(cfile);
840
841 return rc;
842 }
843
parse_create_response(struct cifs_open_info_data * data,struct cifs_sb_info * cifs_sb,const char * full_path,const struct kvec * iov)844 static int parse_create_response(struct cifs_open_info_data *data,
845 struct cifs_sb_info *cifs_sb,
846 const char *full_path,
847 const struct kvec *iov)
848 {
849 struct smb2_create_rsp *rsp = iov->iov_base;
850 bool reparse_point = false;
851 u32 tag = 0;
852 int rc = 0;
853
854 switch (rsp->hdr.Status) {
855 case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
856 reparse_point = true;
857 break;
858 case STATUS_STOPPED_ON_SYMLINK:
859 rc = smb2_parse_symlink_response(cifs_sb, iov,
860 full_path,
861 &data->symlink_target);
862 if (rc)
863 return rc;
864 tag = IO_REPARSE_TAG_SYMLINK;
865 reparse_point = true;
866 break;
867 case STATUS_SUCCESS:
868 reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
869 break;
870 }
871 data->reparse_point = reparse_point;
872 data->reparse.tag = tag;
873 return rc;
874 }
875
876 /* Check only if SMB2_OP_QUERY_WSL_EA command failed in the compound chain */
ea_unsupported(int * cmds,int num_cmds,struct kvec * out_iov,int * out_buftype)877 static bool ea_unsupported(int *cmds, int num_cmds,
878 struct kvec *out_iov, int *out_buftype)
879 {
880 int i;
881
882 if (cmds[num_cmds - 1] != SMB2_OP_QUERY_WSL_EA)
883 return false;
884
885 for (i = 1; i < num_cmds - 1; i++) {
886 struct smb2_hdr *hdr = out_iov[i].iov_base;
887
888 if (out_buftype[i] == CIFS_NO_BUFFER || !hdr ||
889 hdr->Status != STATUS_SUCCESS)
890 return false;
891 }
892 return true;
893 }
894
free_rsp_iov(struct kvec * iovs,int * buftype,int count)895 static inline void free_rsp_iov(struct kvec *iovs, int *buftype, int count)
896 {
897 int i;
898
899 for (i = 0; i < count; i++) {
900 free_rsp_buf(buftype[i], iovs[i].iov_base);
901 memset(&iovs[i], 0, sizeof(*iovs));
902 buftype[i] = CIFS_NO_BUFFER;
903 }
904 }
905
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)906 int smb2_query_path_info(const unsigned int xid,
907 struct cifs_tcon *tcon,
908 struct cifs_sb_info *cifs_sb,
909 const char *full_path,
910 struct cifs_open_info_data *data)
911 {
912 struct kvec in_iov[3], out_iov[5] = {};
913 struct cached_fid *cfid = NULL;
914 struct cifs_open_parms oparms;
915 struct cifsFileInfo *cfile;
916 __u32 create_options = 0;
917 int out_buftype[5] = {};
918 struct smb2_hdr *hdr;
919 int num_cmds = 0;
920 int cmds[3];
921 bool islink;
922 int rc, rc2;
923
924 data->adjust_tz = false;
925 data->reparse_point = false;
926
927 /*
928 * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.
929 * Create SMB2_query_posix_info worker function to do non-compounded
930 * query when we already have an open file handle for this. For now this
931 * is fast enough (always using the compounded version).
932 */
933 if (!tcon->posix_extensions) {
934 if (*full_path) {
935 rc = -ENOENT;
936 } else {
937 rc = open_cached_dir(xid, tcon, full_path,
938 cifs_sb, false, &cfid);
939 }
940 /* If it is a root and its handle is cached then use it */
941 if (!rc) {
942 if (cfid->file_all_info_is_valid) {
943 memcpy(&data->fi, &cfid->file_all_info,
944 sizeof(data->fi));
945 } else {
946 rc = SMB2_query_info(xid, tcon,
947 cfid->fid.persistent_fid,
948 cfid->fid.volatile_fid,
949 &data->fi);
950 }
951 close_cached_dir(cfid);
952 return rc;
953 }
954 cmds[num_cmds++] = SMB2_OP_QUERY_INFO;
955 } else {
956 cmds[num_cmds++] = SMB2_OP_POSIX_QUERY_INFO;
957 }
958
959 in_iov[0].iov_base = data;
960 in_iov[0].iov_len = sizeof(*data);
961 in_iov[1] = in_iov[0];
962 in_iov[2] = in_iov[0];
963
964 cifs_get_readable_path(tcon, full_path, &cfile);
965 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,
966 FILE_OPEN, create_options, ACL_NO_MODE);
967 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
968 &oparms, in_iov, cmds, num_cmds,
969 cfile, out_iov, out_buftype, NULL);
970 hdr = out_iov[0].iov_base;
971 /*
972 * If first iov is unset, then SMB session was dropped or we've got a
973 * cached open file (@cfile).
974 */
975 if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
976 goto out;
977
978 switch (rc) {
979 case 0:
980 rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
981 break;
982 case -EOPNOTSUPP:
983 /*
984 * BB TODO: When support for special files added to Samba
985 * re-verify this path.
986 */
987 rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
988 if (rc || !data->reparse_point)
989 goto out;
990
991 /*
992 * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
993 * response.
994 */
995 if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
996 cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
997 if (!tcon->posix_extensions)
998 cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
999
1000 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1001 FILE_READ_ATTRIBUTES |
1002 FILE_READ_EA | SYNCHRONIZE,
1003 FILE_OPEN, create_options |
1004 OPEN_REPARSE_POINT, ACL_NO_MODE);
1005 cifs_get_readable_path(tcon, full_path, &cfile);
1006 free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
1007 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1008 &oparms, in_iov, cmds, num_cmds,
1009 cfile, out_iov, out_buftype, NULL);
1010 if (rc && ea_unsupported(cmds, num_cmds,
1011 out_iov, out_buftype)) {
1012 if (data->reparse.tag != IO_REPARSE_TAG_LX_BLK &&
1013 data->reparse.tag != IO_REPARSE_TAG_LX_CHR)
1014 rc = 0;
1015 else
1016 rc = -EOPNOTSUPP;
1017 }
1018 break;
1019 case -EREMOTE:
1020 break;
1021 default:
1022 if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
1023 break;
1024 rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
1025 full_path, &islink);
1026 if (rc2) {
1027 rc = rc2;
1028 goto out;
1029 }
1030 if (islink)
1031 rc = -EREMOTE;
1032 }
1033
1034 out:
1035 free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
1036 return rc;
1037 }
1038
1039 int
smb2_mkdir(const unsigned int xid,struct inode * parent_inode,umode_t mode,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)1040 smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
1041 struct cifs_tcon *tcon, const char *name,
1042 struct cifs_sb_info *cifs_sb)
1043 {
1044 struct cifs_open_parms oparms;
1045
1046 oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
1047 FILE_CREATE, CREATE_NOT_FILE, mode);
1048 return smb2_compound_op(xid, tcon, cifs_sb,
1049 name, &oparms, NULL,
1050 &(int){SMB2_OP_MKDIR}, 1,
1051 NULL, NULL, NULL, NULL);
1052 }
1053
1054 void
smb2_mkdir_setinfo(struct inode * inode,const char * name,struct cifs_sb_info * cifs_sb,struct cifs_tcon * tcon,const unsigned int xid)1055 smb2_mkdir_setinfo(struct inode *inode, const char *name,
1056 struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
1057 const unsigned int xid)
1058 {
1059 struct cifs_open_parms oparms;
1060 FILE_BASIC_INFO data = {};
1061 struct cifsInodeInfo *cifs_i;
1062 struct cifsFileInfo *cfile;
1063 struct kvec in_iov;
1064 u32 dosattrs;
1065 int tmprc;
1066
1067 in_iov.iov_base = &data;
1068 in_iov.iov_len = sizeof(data);
1069 cifs_i = CIFS_I(inode);
1070 dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
1071 data.Attributes = cpu_to_le32(dosattrs);
1072 cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
1073 oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
1074 FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);
1075 tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
1076 &oparms, &in_iov,
1077 &(int){SMB2_OP_SET_INFO}, 1,
1078 cfile, NULL, NULL, NULL);
1079 if (tmprc == 0)
1080 cifs_i->cifsAttrs = dosattrs;
1081 }
1082
1083 int
smb2_rmdir(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)1084 smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1085 struct cifs_sb_info *cifs_sb)
1086 {
1087 struct cifs_open_parms oparms;
1088
1089 drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
1090 oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,
1091 FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
1092 return smb2_compound_op(xid, tcon, cifs_sb,
1093 name, &oparms, NULL,
1094 &(int){SMB2_OP_RMDIR}, 1,
1095 NULL, NULL, NULL, NULL);
1096 }
1097
1098 int
smb2_unlink(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb,struct dentry * dentry)1099 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1100 struct cifs_sb_info *cifs_sb, struct dentry *dentry)
1101 {
1102 struct cifs_open_parms oparms;
1103
1104 oparms = CIFS_OPARMS(cifs_sb, tcon, name,
1105 DELETE, FILE_OPEN,
1106 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
1107 ACL_NO_MODE);
1108 int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1109 NULL, &(int){SMB2_OP_DELETE}, 1,
1110 NULL, NULL, NULL, dentry);
1111 if (rc == -EINVAL) {
1112 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1113 rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1114 NULL, &(int){SMB2_OP_DELETE}, 1,
1115 NULL, NULL, NULL, NULL);
1116 }
1117 return rc;
1118 }
1119
smb2_set_path_attr(const unsigned int xid,struct cifs_tcon * tcon,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb,__u32 create_options,__u32 access,int command,struct cifsFileInfo * cfile,struct dentry * dentry)1120 static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
1121 const char *from_name, const char *to_name,
1122 struct cifs_sb_info *cifs_sb,
1123 __u32 create_options, __u32 access,
1124 int command, struct cifsFileInfo *cfile,
1125 struct dentry *dentry)
1126 {
1127 struct cifs_open_parms oparms;
1128 struct kvec in_iov;
1129 __le16 *smb2_to_name = NULL;
1130 int rc;
1131
1132 smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
1133 if (smb2_to_name == NULL) {
1134 rc = -ENOMEM;
1135 goto smb2_rename_path;
1136 }
1137 in_iov.iov_base = smb2_to_name;
1138 in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
1139 oparms = CIFS_OPARMS(cifs_sb, tcon, from_name, access, FILE_OPEN,
1140 create_options, ACL_NO_MODE);
1141 rc = smb2_compound_op(xid, tcon, cifs_sb, from_name,
1142 &oparms, &in_iov, &command, 1,
1143 cfile, NULL, NULL, dentry);
1144 smb2_rename_path:
1145 kfree(smb2_to_name);
1146 return rc;
1147 }
1148
smb2_rename_path(const unsigned int xid,struct cifs_tcon * tcon,struct dentry * source_dentry,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb)1149 int smb2_rename_path(const unsigned int xid,
1150 struct cifs_tcon *tcon,
1151 struct dentry *source_dentry,
1152 const char *from_name, const char *to_name,
1153 struct cifs_sb_info *cifs_sb)
1154 {
1155 struct cifsFileInfo *cfile;
1156 __u32 co = file_create_options(source_dentry);
1157
1158 drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
1159 cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
1160
1161 int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1162 co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
1163 if (rc == -EINVAL) {
1164 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1165 cifs_get_writable_path(tcon, from_name,
1166 FIND_WR_WITH_DELETE, &cfile);
1167 rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1168 co, DELETE, SMB2_OP_RENAME, cfile, NULL);
1169 }
1170 return rc;
1171 }
1172
smb2_create_hardlink(const unsigned int xid,struct cifs_tcon * tcon,struct dentry * source_dentry,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb)1173 int smb2_create_hardlink(const unsigned int xid,
1174 struct cifs_tcon *tcon,
1175 struct dentry *source_dentry,
1176 const char *from_name, const char *to_name,
1177 struct cifs_sb_info *cifs_sb)
1178 {
1179 __u32 co = file_create_options(source_dentry);
1180
1181 return smb2_set_path_attr(xid, tcon, from_name, to_name,
1182 cifs_sb, co, FILE_READ_ATTRIBUTES,
1183 SMB2_OP_HARDLINK, NULL, NULL);
1184 }
1185
1186 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,struct dentry * dentry)1187 smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
1188 const char *full_path, __u64 size,
1189 struct cifs_sb_info *cifs_sb, bool set_alloc,
1190 struct dentry *dentry)
1191 {
1192 struct cifs_open_parms oparms;
1193 struct cifsFileInfo *cfile;
1194 struct kvec in_iov;
1195 __le64 eof = cpu_to_le64(size);
1196 int rc;
1197
1198 in_iov.iov_base = &eof;
1199 in_iov.iov_len = sizeof(eof);
1200 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1201
1202 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
1203 FILE_OPEN, 0, ACL_NO_MODE);
1204 rc = smb2_compound_op(xid, tcon, cifs_sb,
1205 full_path, &oparms, &in_iov,
1206 &(int){SMB2_OP_SET_EOF}, 1,
1207 cfile, NULL, NULL, dentry);
1208 if (rc == -EINVAL) {
1209 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1210 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1211 rc = smb2_compound_op(xid, tcon, cifs_sb,
1212 full_path, &oparms, &in_iov,
1213 &(int){SMB2_OP_SET_EOF}, 1,
1214 cfile, NULL, NULL, NULL);
1215 }
1216 return rc;
1217 }
1218
1219 int
smb2_set_file_info(struct inode * inode,const char * full_path,FILE_BASIC_INFO * buf,const unsigned int xid)1220 smb2_set_file_info(struct inode *inode, const char *full_path,
1221 FILE_BASIC_INFO *buf, const unsigned int xid)
1222 {
1223 struct cifs_open_parms oparms;
1224 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1225 struct tcon_link *tlink;
1226 struct cifs_tcon *tcon;
1227 struct cifsFileInfo *cfile;
1228 struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
1229 int rc;
1230
1231 if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
1232 (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
1233 (buf->Attributes == 0))
1234 return 0; /* would be a no op, no sense sending this */
1235
1236 tlink = cifs_sb_tlink(cifs_sb);
1237 if (IS_ERR(tlink))
1238 return PTR_ERR(tlink);
1239 tcon = tlink_tcon(tlink);
1240
1241 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1242 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
1243 FILE_OPEN, 0, ACL_NO_MODE);
1244 rc = smb2_compound_op(xid, tcon, cifs_sb,
1245 full_path, &oparms, &in_iov,
1246 &(int){SMB2_OP_SET_INFO}, 1,
1247 cfile, NULL, NULL, NULL);
1248 cifs_put_tlink(tlink);
1249 return rc;
1250 }
1251
smb2_get_reparse_inode(struct cifs_open_info_data * data,struct super_block * sb,const unsigned int xid,struct cifs_tcon * tcon,const char * full_path,bool directory,struct kvec * reparse_iov,struct kvec * xattr_iov)1252 struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
1253 struct super_block *sb,
1254 const unsigned int xid,
1255 struct cifs_tcon *tcon,
1256 const char *full_path,
1257 bool directory,
1258 struct kvec *reparse_iov,
1259 struct kvec *xattr_iov)
1260 {
1261 struct cifs_open_parms oparms;
1262 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1263 struct cifsFileInfo *cfile;
1264 struct inode *new = NULL;
1265 int out_buftype[4] = {};
1266 struct kvec out_iov[4] = {};
1267 struct kvec in_iov[2];
1268 int cmds[2];
1269 int rc;
1270 int i;
1271
1272 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1273 SYNCHRONIZE | DELETE |
1274 FILE_READ_ATTRIBUTES |
1275 FILE_WRITE_ATTRIBUTES,
1276 FILE_CREATE,
1277 (directory ? CREATE_NOT_FILE : CREATE_NOT_DIR) | OPEN_REPARSE_POINT,
1278 ACL_NO_MODE);
1279 if (xattr_iov)
1280 oparms.ea_cctx = xattr_iov;
1281
1282 cmds[0] = SMB2_OP_SET_REPARSE;
1283 in_iov[0] = *reparse_iov;
1284 in_iov[1].iov_base = data;
1285 in_iov[1].iov_len = sizeof(*data);
1286
1287 if (tcon->posix_extensions) {
1288 cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
1289 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1290 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1291 in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
1292 if (!rc) {
1293 rc = smb311_posix_get_inode_info(&new, full_path,
1294 data, sb, xid);
1295 }
1296 } else {
1297 cmds[1] = SMB2_OP_QUERY_INFO;
1298 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1299 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1300 in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
1301 if (!rc) {
1302 rc = cifs_get_inode_info(&new, full_path,
1303 data, sb, xid, NULL);
1304 }
1305 }
1306
1307
1308 /*
1309 * If CREATE was successful but SMB2_OP_SET_REPARSE failed then
1310 * remove the intermediate object created by CREATE. Otherwise
1311 * empty object stay on the server when reparse call failed.
1312 */
1313 if (rc &&
1314 out_iov[0].iov_base != NULL && out_buftype[0] != CIFS_NO_BUFFER &&
1315 ((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_SUCCESS &&
1316 (out_iov[1].iov_base == NULL || out_buftype[1] == CIFS_NO_BUFFER ||
1317 ((struct smb2_hdr *)out_iov[1].iov_base)->Status != STATUS_SUCCESS))
1318 smb2_unlink(xid, tcon, full_path, cifs_sb, NULL);
1319
1320 for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
1321 free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
1322
1323 return rc ? ERR_PTR(rc) : new;
1324 }
1325
smb2_query_reparse_point(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,u32 * tag,struct kvec * rsp,int * rsp_buftype)1326 int smb2_query_reparse_point(const unsigned int xid,
1327 struct cifs_tcon *tcon,
1328 struct cifs_sb_info *cifs_sb,
1329 const char *full_path,
1330 u32 *tag, struct kvec *rsp,
1331 int *rsp_buftype)
1332 {
1333 struct cifs_open_parms oparms;
1334 struct cifs_open_info_data data = {};
1335 struct cifsFileInfo *cfile;
1336 struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
1337 int rc;
1338
1339 cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
1340
1341 cifs_get_readable_path(tcon, full_path, &cfile);
1342 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1343 FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,
1344 FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE);
1345 rc = smb2_compound_op(xid, tcon, cifs_sb,
1346 full_path, &oparms, &in_iov,
1347 &(int){SMB2_OP_GET_REPARSE}, 1,
1348 cfile, NULL, NULL, NULL);
1349 if (rc)
1350 goto out;
1351
1352 *tag = data.reparse.tag;
1353 *rsp = data.reparse.io.iov;
1354 *rsp_buftype = data.reparse.io.buftype;
1355 memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
1356 data.reparse.io.buftype = CIFS_NO_BUFFER;
1357 out:
1358 cifs_free_open_info(&data);
1359 return rc;
1360 }
1361