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_create_rsp *create_rsp = NULL;
180 struct smb2_query_info_rsp *qi_rsp = NULL;
181 struct smb2_compound_vars *vars = NULL;
182 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
183 struct cifs_open_info_data *idata;
184 struct cifs_ses *ses = tcon->ses;
185 struct reparse_data_buffer *rbuf;
186 struct TCP_Server_Info *server;
187 int resp_buftype[MAX_COMPOUND];
188 int retries = 0, cur_sleep = 1;
189 __u8 delete_pending[8] = {1,};
190 struct kvec *rsp_iov, *iov;
191 struct inode *inode = NULL;
192 __le16 *utf16_path = NULL;
193 struct smb_rqst *rqst;
194 unsigned int size[2];
195 struct cifs_fid fid;
196 int num_rqst = 0, i;
197 unsigned int len;
198 int tmp_rc, rc;
199 int flags = 0;
200 void *data[2];
201
202 replay_again:
203 /* reinitialize for possible replay */
204 flags = 0;
205 oplock = SMB2_OPLOCK_LEVEL_NONE;
206 num_rqst = 0;
207 server = cifs_pick_channel(ses);
208
209 vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
210 if (vars == NULL)
211 return -ENOMEM;
212 rqst = &vars->rqst[0];
213 rsp_iov = &vars->rsp_iov[0];
214
215 if (smb3_encryption_required(tcon))
216 flags |= CIFS_TRANSFORM_REQ;
217
218 for (i = 0; i < ARRAY_SIZE(resp_buftype); i++)
219 resp_buftype[i] = CIFS_NO_BUFFER;
220
221 /* We already have a handle so we can skip the open */
222 if (cfile)
223 goto after_open;
224
225 /* Open */
226 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
227 if (!utf16_path) {
228 rc = -ENOMEM;
229 goto finished;
230 }
231
232 /* if there is an existing lease, reuse it */
233
234 /*
235 * note: files with hardlinks cause unexpected behaviour. As per MS-SMB2,
236 * lease keys are associated with the filepath. We are maintaining lease keys
237 * with the inode on the client. If the file has hardlinks, it is possible
238 * that the lease for a file be reused for an operation on its hardlink or
239 * vice versa.
240 * As a workaround, send request using an existing lease key and if the server
241 * returns STATUS_INVALID_PARAMETER, which maps to EINVAL, send the request
242 * again without the lease.
243 */
244 if (dentry) {
245 inode = d_inode(dentry);
246 if (CIFS_I(inode)->lease_granted && server->ops->get_lease_key) {
247 oplock = SMB2_OPLOCK_LEVEL_LEASE;
248 server->ops->get_lease_key(inode, &fid);
249 }
250 }
251
252 vars->oparms = *oparms;
253 vars->oparms.fid = &fid;
254
255 rqst[num_rqst].rq_iov = &vars->open_iov[0];
256 rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
257 rc = SMB2_open_init(tcon, server,
258 &rqst[num_rqst], &oplock, &vars->oparms,
259 utf16_path);
260 kfree(utf16_path);
261 if (rc)
262 goto finished;
263
264 smb2_set_next_command(tcon, &rqst[num_rqst]);
265 after_open:
266 num_rqst++;
267 rc = 0;
268
269 i = 0;
270
271 /* Skip the leading explicit OPEN operation */
272 if (num_cmds > 0 && cmds[0] == SMB2_OP_OPEN_QUERY)
273 i++;
274
275 for (; i < num_cmds; i++) {
276 /* Operation */
277 switch (cmds[i]) {
278 case SMB2_OP_QUERY_INFO:
279 rqst[num_rqst].rq_iov = &vars->qi_iov;
280 rqst[num_rqst].rq_nvec = 1;
281
282 if (cfile) {
283 rc = SMB2_query_info_init(tcon, server,
284 &rqst[num_rqst],
285 cfile->fid.persistent_fid,
286 cfile->fid.volatile_fid,
287 FILE_ALL_INFORMATION,
288 SMB2_O_INFO_FILE, 0,
289 sizeof(struct smb2_file_all_info) +
290 PATH_MAX * 2, 0, NULL);
291 } else {
292 rc = SMB2_query_info_init(tcon, server,
293 &rqst[num_rqst],
294 COMPOUND_FID,
295 COMPOUND_FID,
296 FILE_ALL_INFORMATION,
297 SMB2_O_INFO_FILE, 0,
298 sizeof(struct smb2_file_all_info) +
299 PATH_MAX * 2, 0, NULL);
300 }
301 if (!rc && (!cfile || num_rqst > 1)) {
302 smb2_set_next_command(tcon, &rqst[num_rqst]);
303 smb2_set_related(&rqst[num_rqst]);
304 } else if (rc) {
305 goto finished;
306 }
307 num_rqst++;
308 trace_smb3_query_info_compound_enter(xid, tcon->tid,
309 ses->Suid, full_path);
310 break;
311 case SMB2_OP_POSIX_QUERY_INFO:
312 rqst[num_rqst].rq_iov = &vars->qi_iov;
313 rqst[num_rqst].rq_nvec = 1;
314
315 if (cfile) {
316 /* TBD: fix following to allow for longer SIDs */
317 rc = SMB2_query_info_init(tcon, server,
318 &rqst[num_rqst],
319 cfile->fid.persistent_fid,
320 cfile->fid.volatile_fid,
321 SMB_FIND_FILE_POSIX_INFO,
322 SMB2_O_INFO_FILE, 0,
323 sizeof(struct smb311_posix_qinfo *) +
324 (PATH_MAX * 2) +
325 (sizeof(struct smb_sid) * 2), 0, NULL);
326 } else {
327 rc = SMB2_query_info_init(tcon, server,
328 &rqst[num_rqst],
329 COMPOUND_FID,
330 COMPOUND_FID,
331 SMB_FIND_FILE_POSIX_INFO,
332 SMB2_O_INFO_FILE, 0,
333 sizeof(struct smb311_posix_qinfo *) +
334 (PATH_MAX * 2) +
335 (sizeof(struct smb_sid) * 2), 0, NULL);
336 }
337 if (!rc && (!cfile || num_rqst > 1)) {
338 smb2_set_next_command(tcon, &rqst[num_rqst]);
339 smb2_set_related(&rqst[num_rqst]);
340 } else if (rc) {
341 goto finished;
342 }
343 num_rqst++;
344 trace_smb3_posix_query_info_compound_enter(xid, tcon->tid,
345 ses->Suid, full_path);
346 break;
347 case SMB2_OP_DELETE:
348 trace_smb3_delete_enter(xid, tcon->tid, ses->Suid, full_path);
349 break;
350 case SMB2_OP_MKDIR:
351 /*
352 * Directories are created through parameters in the
353 * SMB2_open() call.
354 */
355 trace_smb3_mkdir_enter(xid, tcon->tid, ses->Suid, full_path);
356 break;
357 case SMB2_OP_RMDIR:
358 rqst[num_rqst].rq_iov = &vars->si_iov[0];
359 rqst[num_rqst].rq_nvec = 1;
360
361 size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
362 data[0] = &delete_pending[0];
363
364 rc = SMB2_set_info_init(tcon, server,
365 &rqst[num_rqst], COMPOUND_FID,
366 COMPOUND_FID, current->tgid,
367 FILE_DISPOSITION_INFORMATION,
368 SMB2_O_INFO_FILE, 0, data, size);
369 if (rc)
370 goto finished;
371 smb2_set_next_command(tcon, &rqst[num_rqst]);
372 smb2_set_related(&rqst[num_rqst++]);
373 trace_smb3_rmdir_enter(xid, tcon->tid, ses->Suid, full_path);
374 break;
375 case SMB2_OP_SET_EOF:
376 rqst[num_rqst].rq_iov = &vars->si_iov[0];
377 rqst[num_rqst].rq_nvec = 1;
378
379 size[0] = in_iov[i].iov_len;
380 data[0] = in_iov[i].iov_base;
381
382 if (cfile) {
383 rc = SMB2_set_info_init(tcon, server,
384 &rqst[num_rqst],
385 cfile->fid.persistent_fid,
386 cfile->fid.volatile_fid,
387 current->tgid,
388 FILE_END_OF_FILE_INFORMATION,
389 SMB2_O_INFO_FILE, 0,
390 data, size);
391 } else {
392 rc = SMB2_set_info_init(tcon, server,
393 &rqst[num_rqst],
394 COMPOUND_FID,
395 COMPOUND_FID,
396 current->tgid,
397 FILE_END_OF_FILE_INFORMATION,
398 SMB2_O_INFO_FILE, 0,
399 data, size);
400 }
401 if (!rc && (!cfile || num_rqst > 1)) {
402 smb2_set_next_command(tcon, &rqst[num_rqst]);
403 smb2_set_related(&rqst[num_rqst]);
404 } else if (rc) {
405 goto finished;
406 }
407 num_rqst++;
408 trace_smb3_set_eof_enter(xid, tcon->tid, ses->Suid, full_path);
409 break;
410 case SMB2_OP_SET_INFO:
411 rqst[num_rqst].rq_iov = &vars->si_iov[0];
412 rqst[num_rqst].rq_nvec = 1;
413
414 size[0] = in_iov[i].iov_len;
415 data[0] = in_iov[i].iov_base;
416
417 if (cfile) {
418 rc = SMB2_set_info_init(tcon, server,
419 &rqst[num_rqst],
420 cfile->fid.persistent_fid,
421 cfile->fid.volatile_fid, current->tgid,
422 FILE_BASIC_INFORMATION,
423 SMB2_O_INFO_FILE, 0, data, size);
424 } else {
425 rc = SMB2_set_info_init(tcon, server,
426 &rqst[num_rqst],
427 COMPOUND_FID,
428 COMPOUND_FID, current->tgid,
429 FILE_BASIC_INFORMATION,
430 SMB2_O_INFO_FILE, 0, data, size);
431 }
432 if (!rc && (!cfile || num_rqst > 1)) {
433 smb2_set_next_command(tcon, &rqst[num_rqst]);
434 smb2_set_related(&rqst[num_rqst]);
435 } else if (rc) {
436 goto finished;
437 }
438 num_rqst++;
439 trace_smb3_set_info_compound_enter(xid, tcon->tid,
440 ses->Suid, full_path);
441 break;
442 case SMB2_OP_RENAME:
443 rqst[num_rqst].rq_iov = &vars->si_iov[0];
444 rqst[num_rqst].rq_nvec = 2;
445
446 len = in_iov[i].iov_len;
447
448 vars->rename_info.ReplaceIfExists = 1;
449 vars->rename_info.RootDirectory = 0;
450 vars->rename_info.FileNameLength = cpu_to_le32(len);
451
452 size[0] = sizeof(struct smb2_file_rename_info);
453 data[0] = &vars->rename_info;
454
455 size[1] = len + 2 /* null */;
456 data[1] = in_iov[i].iov_base;
457
458 if (cfile) {
459 rc = SMB2_set_info_init(tcon, server,
460 &rqst[num_rqst],
461 cfile->fid.persistent_fid,
462 cfile->fid.volatile_fid,
463 current->tgid, FILE_RENAME_INFORMATION,
464 SMB2_O_INFO_FILE, 0, data, size);
465 } else {
466 rc = SMB2_set_info_init(tcon, server,
467 &rqst[num_rqst],
468 COMPOUND_FID, COMPOUND_FID,
469 current->tgid, FILE_RENAME_INFORMATION,
470 SMB2_O_INFO_FILE, 0, data, size);
471 }
472 if (!rc && (!cfile || num_rqst > 1)) {
473 smb2_set_next_command(tcon, &rqst[num_rqst]);
474 smb2_set_related(&rqst[num_rqst]);
475 } else if (rc) {
476 goto finished;
477 }
478 num_rqst++;
479 trace_smb3_rename_enter(xid, tcon->tid, ses->Suid, full_path);
480 break;
481 case SMB2_OP_HARDLINK:
482 rqst[num_rqst].rq_iov = &vars->si_iov[0];
483 rqst[num_rqst].rq_nvec = 2;
484
485 len = in_iov[i].iov_len;
486
487 vars->link_info.ReplaceIfExists = 0;
488 vars->link_info.RootDirectory = 0;
489 vars->link_info.FileNameLength = cpu_to_le32(len);
490
491 size[0] = sizeof(struct smb2_file_link_info);
492 data[0] = &vars->link_info;
493
494 size[1] = len + 2 /* null */;
495 data[1] = in_iov[i].iov_base;
496
497 rc = SMB2_set_info_init(tcon, server,
498 &rqst[num_rqst], COMPOUND_FID,
499 COMPOUND_FID, current->tgid,
500 FILE_LINK_INFORMATION,
501 SMB2_O_INFO_FILE, 0, data, size);
502 if (rc)
503 goto finished;
504 smb2_set_next_command(tcon, &rqst[num_rqst]);
505 smb2_set_related(&rqst[num_rqst++]);
506 trace_smb3_hardlink_enter(xid, tcon->tid, ses->Suid, full_path);
507 break;
508 case SMB2_OP_SET_REPARSE:
509 rqst[num_rqst].rq_iov = vars->io_iov;
510 rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
511
512 if (cfile) {
513 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
514 cfile->fid.persistent_fid,
515 cfile->fid.volatile_fid,
516 FSCTL_SET_REPARSE_POINT,
517 in_iov[i].iov_base,
518 in_iov[i].iov_len, 0);
519 } else {
520 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
521 COMPOUND_FID, COMPOUND_FID,
522 FSCTL_SET_REPARSE_POINT,
523 in_iov[i].iov_base,
524 in_iov[i].iov_len, 0);
525 }
526 if (!rc && (!cfile || num_rqst > 1)) {
527 smb2_set_next_command(tcon, &rqst[num_rqst]);
528 smb2_set_related(&rqst[num_rqst]);
529 } else if (rc) {
530 goto finished;
531 }
532 num_rqst++;
533 trace_smb3_set_reparse_compound_enter(xid, tcon->tid,
534 ses->Suid, full_path);
535 break;
536 case SMB2_OP_GET_REPARSE:
537 rqst[num_rqst].rq_iov = vars->io_iov;
538 rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
539
540 if (cfile) {
541 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
542 cfile->fid.persistent_fid,
543 cfile->fid.volatile_fid,
544 FSCTL_GET_REPARSE_POINT,
545 NULL, 0, CIFSMaxBufSize);
546 } else {
547 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
548 COMPOUND_FID, COMPOUND_FID,
549 FSCTL_GET_REPARSE_POINT,
550 NULL, 0, CIFSMaxBufSize);
551 }
552 if (!rc && (!cfile || num_rqst > 1)) {
553 smb2_set_next_command(tcon, &rqst[num_rqst]);
554 smb2_set_related(&rqst[num_rqst]);
555 } else if (rc) {
556 goto finished;
557 }
558 num_rqst++;
559 trace_smb3_get_reparse_compound_enter(xid, tcon->tid,
560 ses->Suid, full_path);
561 break;
562 case SMB2_OP_QUERY_WSL_EA:
563 rqst[num_rqst].rq_iov = &vars->ea_iov;
564 rqst[num_rqst].rq_nvec = 1;
565
566 if (cfile) {
567 rc = SMB2_query_info_init(tcon, server,
568 &rqst[num_rqst],
569 cfile->fid.persistent_fid,
570 cfile->fid.volatile_fid,
571 FILE_FULL_EA_INFORMATION,
572 SMB2_O_INFO_FILE, 0,
573 SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
574 sizeof(wsl_query_eas),
575 (void *)wsl_query_eas);
576 } else {
577 rc = SMB2_query_info_init(tcon, server,
578 &rqst[num_rqst],
579 COMPOUND_FID,
580 COMPOUND_FID,
581 FILE_FULL_EA_INFORMATION,
582 SMB2_O_INFO_FILE, 0,
583 SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
584 sizeof(wsl_query_eas),
585 (void *)wsl_query_eas);
586 }
587 if (!rc && (!cfile || num_rqst > 1)) {
588 smb2_set_next_command(tcon, &rqst[num_rqst]);
589 smb2_set_related(&rqst[num_rqst]);
590 } else if (rc) {
591 goto finished;
592 }
593 num_rqst++;
594 trace_smb3_query_wsl_ea_compound_enter(xid, tcon->tid,
595 ses->Suid, full_path);
596 break;
597 default:
598 cifs_dbg(VFS, "Invalid command\n");
599 rc = -EINVAL;
600 }
601 }
602 if (rc)
603 goto finished;
604
605 /* We already have a handle so we can skip the close */
606 if (cfile)
607 goto after_close;
608 /* Close */
609 flags |= CIFS_CP_CREATE_CLOSE_OP;
610 rqst[num_rqst].rq_iov = &vars->close_iov;
611 rqst[num_rqst].rq_nvec = 1;
612 rc = SMB2_close_init(tcon, server,
613 &rqst[num_rqst], COMPOUND_FID,
614 COMPOUND_FID, false);
615 smb2_set_related(&rqst[num_rqst]);
616 if (rc)
617 goto finished;
618 after_close:
619 num_rqst++;
620
621 if (cfile) {
622 if (retries)
623 for (i = 1; i < num_rqst - 2; i++)
624 smb2_set_replay(server, &rqst[i]);
625
626 rc = compound_send_recv(xid, ses, server,
627 flags, num_rqst - 2,
628 &rqst[1], &resp_buftype[1],
629 &rsp_iov[1]);
630 } else {
631 if (retries)
632 for (i = 0; i < num_rqst; i++)
633 smb2_set_replay(server, &rqst[i]);
634
635 rc = compound_send_recv(xid, ses, server,
636 flags, num_rqst,
637 rqst, resp_buftype,
638 rsp_iov);
639 }
640
641 finished:
642 num_rqst = 0;
643 SMB2_open_free(&rqst[num_rqst++]);
644 if (rc == -EREMCHG) {
645 pr_warn_once("server share %s deleted\n", tcon->tree_name);
646 tcon->need_reconnect = true;
647 }
648
649 tmp_rc = rc;
650
651 if (rc == 0 && num_cmds > 0 && cmds[0] == SMB2_OP_OPEN_QUERY) {
652 create_rsp = rsp_iov[0].iov_base;
653 idata = in_iov[0].iov_base;
654 idata->fi.CreationTime = create_rsp->CreationTime;
655 idata->fi.LastAccessTime = create_rsp->LastAccessTime;
656 idata->fi.LastWriteTime = create_rsp->LastWriteTime;
657 idata->fi.ChangeTime = create_rsp->ChangeTime;
658 idata->fi.Attributes = create_rsp->FileAttributes;
659 idata->fi.AllocationSize = create_rsp->AllocationSize;
660 idata->fi.EndOfFile = create_rsp->EndofFile;
661 if (le32_to_cpu(idata->fi.NumberOfLinks) == 0)
662 idata->fi.NumberOfLinks = cpu_to_le32(1); /* dummy value */
663 idata->fi.DeletePending = 0;
664 idata->fi.Directory = !!(le32_to_cpu(create_rsp->FileAttributes) & ATTR_DIRECTORY);
665
666 /* smb2_parse_contexts() fills idata->fi.IndexNumber */
667 rc = smb2_parse_contexts(server, &rsp_iov[0], &oparms->fid->epoch,
668 oparms->fid->lease_key, &oplock, &idata->fi, NULL);
669 if (rc)
670 cifs_dbg(VFS, "rc: %d parsing context of compound op\n", rc);
671 }
672
673 for (i = 0; i < num_cmds; i++) {
674 char *buf = rsp_iov[i + i].iov_base;
675
676 if (buf && resp_buftype[i + 1] != CIFS_NO_BUFFER)
677 rc = server->ops->map_error(buf, false);
678 else
679 rc = tmp_rc;
680 switch (cmds[i]) {
681 case SMB2_OP_QUERY_INFO:
682 idata = in_iov[i].iov_base;
683 idata->contains_posix_file_info = false;
684 if (rc == 0 && cfile && cfile->symlink_target) {
685 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
686 if (!idata->symlink_target)
687 rc = -ENOMEM;
688 }
689 if (rc == 0) {
690 qi_rsp = (struct smb2_query_info_rsp *)
691 rsp_iov[i + 1].iov_base;
692 rc = smb2_validate_and_copy_iov(
693 le16_to_cpu(qi_rsp->OutputBufferOffset),
694 le32_to_cpu(qi_rsp->OutputBufferLength),
695 &rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi);
696 }
697 SMB2_query_info_free(&rqst[num_rqst++]);
698 if (rc)
699 trace_smb3_query_info_compound_err(xid, tcon->tid,
700 ses->Suid, rc);
701 else
702 trace_smb3_query_info_compound_done(xid, tcon->tid,
703 ses->Suid);
704 break;
705 case SMB2_OP_POSIX_QUERY_INFO:
706 idata = in_iov[i].iov_base;
707 idata->contains_posix_file_info = true;
708 if (rc == 0 && cfile && cfile->symlink_target) {
709 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
710 if (!idata->symlink_target)
711 rc = -ENOMEM;
712 }
713 if (rc == 0) {
714 qi_rsp = (struct smb2_query_info_rsp *)
715 rsp_iov[i + 1].iov_base;
716 rc = smb2_validate_and_copy_iov(
717 le16_to_cpu(qi_rsp->OutputBufferOffset),
718 le32_to_cpu(qi_rsp->OutputBufferLength),
719 &rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,
720 (char *)&idata->posix_fi);
721 }
722 if (rc == 0)
723 rc = parse_posix_sids(idata, &rsp_iov[i + 1]);
724
725 SMB2_query_info_free(&rqst[num_rqst++]);
726 if (rc)
727 trace_smb3_posix_query_info_compound_err(xid, tcon->tid,
728 ses->Suid, rc);
729 else
730 trace_smb3_posix_query_info_compound_done(xid, tcon->tid,
731 ses->Suid);
732 break;
733 case SMB2_OP_DELETE:
734 if (rc)
735 trace_smb3_delete_err(xid, tcon->tid, ses->Suid, rc);
736 else {
737 /*
738 * If dentry (hence, inode) is NULL, lease break is going to
739 * take care of degrading leases on handles for deleted files.
740 */
741 if (inode)
742 cifs_mark_open_handles_for_deleted_file(inode, full_path);
743 trace_smb3_delete_done(xid, tcon->tid, ses->Suid);
744 }
745 break;
746 case SMB2_OP_MKDIR:
747 if (rc)
748 trace_smb3_mkdir_err(xid, tcon->tid, ses->Suid, rc);
749 else
750 trace_smb3_mkdir_done(xid, tcon->tid, ses->Suid);
751 break;
752 case SMB2_OP_HARDLINK:
753 if (rc)
754 trace_smb3_hardlink_err(xid, tcon->tid, ses->Suid, rc);
755 else
756 trace_smb3_hardlink_done(xid, tcon->tid, ses->Suid);
757 SMB2_set_info_free(&rqst[num_rqst++]);
758 break;
759 case SMB2_OP_RENAME:
760 if (rc)
761 trace_smb3_rename_err(xid, tcon->tid, ses->Suid, rc);
762 else
763 trace_smb3_rename_done(xid, tcon->tid, ses->Suid);
764 SMB2_set_info_free(&rqst[num_rqst++]);
765 break;
766 case SMB2_OP_RMDIR:
767 if (rc)
768 trace_smb3_rmdir_err(xid, tcon->tid, ses->Suid, rc);
769 else
770 trace_smb3_rmdir_done(xid, tcon->tid, ses->Suid);
771 SMB2_set_info_free(&rqst[num_rqst++]);
772 break;
773 case SMB2_OP_SET_EOF:
774 if (rc)
775 trace_smb3_set_eof_err(xid, tcon->tid, ses->Suid, rc);
776 else
777 trace_smb3_set_eof_done(xid, tcon->tid, ses->Suid);
778 SMB2_set_info_free(&rqst[num_rqst++]);
779 break;
780 case SMB2_OP_SET_INFO:
781 if (rc)
782 trace_smb3_set_info_compound_err(xid, tcon->tid,
783 ses->Suid, rc);
784 else
785 trace_smb3_set_info_compound_done(xid, tcon->tid,
786 ses->Suid);
787 SMB2_set_info_free(&rqst[num_rqst++]);
788 break;
789 case SMB2_OP_SET_REPARSE:
790 if (rc) {
791 trace_smb3_set_reparse_compound_err(xid, tcon->tid,
792 ses->Suid, rc);
793 } else {
794 trace_smb3_set_reparse_compound_done(xid, tcon->tid,
795 ses->Suid);
796 }
797 SMB2_ioctl_free(&rqst[num_rqst++]);
798 break;
799 case SMB2_OP_GET_REPARSE:
800 if (!rc) {
801 iov = &rsp_iov[i + 1];
802 idata = in_iov[i].iov_base;
803 idata->reparse.io.iov = *iov;
804 idata->reparse.io.buftype = resp_buftype[i + 1];
805 idata->contains_posix_file_info = false; /* BB VERIFY */
806 rbuf = reparse_buf_ptr(iov);
807 if (IS_ERR(rbuf)) {
808 rc = PTR_ERR(rbuf);
809 trace_smb3_get_reparse_compound_err(xid, tcon->tid,
810 ses->Suid, rc);
811 } else {
812 idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
813 trace_smb3_get_reparse_compound_done(xid, tcon->tid,
814 ses->Suid);
815 }
816 memset(iov, 0, sizeof(*iov));
817 resp_buftype[i + 1] = CIFS_NO_BUFFER;
818 } else {
819 trace_smb3_get_reparse_compound_err(xid, tcon->tid,
820 ses->Suid, rc);
821 }
822 SMB2_ioctl_free(&rqst[num_rqst++]);
823 break;
824 case SMB2_OP_QUERY_WSL_EA:
825 if (!rc) {
826 idata = in_iov[i].iov_base;
827 idata->contains_posix_file_info = false;
828 qi_rsp = rsp_iov[i + 1].iov_base;
829 data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
830 size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);
831 rc = check_wsl_eas(&rsp_iov[i + 1]);
832 if (!rc) {
833 memcpy(idata->wsl.eas, data[0], size[0]);
834 idata->wsl.eas_len = size[0];
835 }
836 }
837 if (!rc) {
838 trace_smb3_query_wsl_ea_compound_done(xid, tcon->tid,
839 ses->Suid);
840 } else {
841 trace_smb3_query_wsl_ea_compound_err(xid, tcon->tid,
842 ses->Suid, rc);
843 }
844 SMB2_query_info_free(&rqst[num_rqst++]);
845 break;
846 }
847 }
848 SMB2_close_free(&rqst[num_rqst]);
849 rc = tmp_rc;
850
851 num_cmds += 2;
852 if (out_iov && out_buftype) {
853 memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
854 memcpy(out_buftype, resp_buftype,
855 num_cmds * sizeof(*out_buftype));
856 } else {
857 for (i = 0; i < num_cmds; i++)
858 free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
859 }
860 num_cmds -= 2; /* correct num_cmds as there could be a retry */
861 kfree(vars);
862
863 if (is_replayable_error(rc) &&
864 smb2_should_replay(tcon, &retries, &cur_sleep))
865 goto replay_again;
866
867 if (cfile)
868 cifsFileInfo_put(cfile);
869
870 return rc;
871 }
872
parse_create_response(struct cifs_open_info_data * data,struct cifs_sb_info * cifs_sb,const char * full_path,const struct kvec * iov)873 static int parse_create_response(struct cifs_open_info_data *data,
874 struct cifs_sb_info *cifs_sb,
875 const char *full_path,
876 const struct kvec *iov)
877 {
878 struct smb2_create_rsp *rsp = iov->iov_base;
879 bool reparse_point = false;
880 u32 tag = 0;
881 int rc = 0;
882
883 switch (rsp->hdr.Status) {
884 case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
885 reparse_point = true;
886 break;
887 case STATUS_STOPPED_ON_SYMLINK:
888 rc = smb2_parse_symlink_response(cifs_sb, iov,
889 full_path,
890 &data->symlink_target);
891 if (rc)
892 return rc;
893 tag = IO_REPARSE_TAG_SYMLINK;
894 reparse_point = true;
895 break;
896 case STATUS_SUCCESS:
897 reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
898 break;
899 }
900 data->reparse_point = reparse_point;
901 data->reparse.tag = tag;
902 return rc;
903 }
904
905 /* 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)906 static bool ea_unsupported(int *cmds, int num_cmds,
907 struct kvec *out_iov, int *out_buftype)
908 {
909 int i;
910
911 if (cmds[num_cmds - 1] != SMB2_OP_QUERY_WSL_EA)
912 return false;
913
914 for (i = 1; i < num_cmds - 1; i++) {
915 struct smb2_hdr *hdr = out_iov[i].iov_base;
916
917 if (out_buftype[i] == CIFS_NO_BUFFER || !hdr ||
918 hdr->Status != STATUS_SUCCESS)
919 return false;
920 }
921 return true;
922 }
923
free_rsp_iov(struct kvec * iovs,int * buftype,int count)924 static inline void free_rsp_iov(struct kvec *iovs, int *buftype, int count)
925 {
926 int i;
927
928 for (i = 0; i < count; i++) {
929 free_rsp_buf(buftype[i], iovs[i].iov_base);
930 memset(&iovs[i], 0, sizeof(*iovs));
931 buftype[i] = CIFS_NO_BUFFER;
932 }
933 }
934
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)935 int smb2_query_path_info(const unsigned int xid,
936 struct cifs_tcon *tcon,
937 struct cifs_sb_info *cifs_sb,
938 const char *full_path,
939 struct cifs_open_info_data *data)
940 {
941 struct kvec in_iov[3], out_iov[5] = {};
942 struct cached_fid *cfid = NULL;
943 struct cifs_open_parms oparms;
944 struct cifsFileInfo *cfile;
945 __u32 create_options = 0;
946 int out_buftype[5] = {};
947 struct smb2_hdr *hdr;
948 int num_cmds = 0;
949 int cmds[3];
950 bool islink;
951 int rc, rc2;
952
953 data->adjust_tz = false;
954 data->reparse_point = false;
955
956 /*
957 * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.
958 * Create SMB2_query_posix_info worker function to do non-compounded
959 * query when we already have an open file handle for this. For now this
960 * is fast enough (always using the compounded version).
961 */
962 if (!tcon->posix_extensions) {
963 if (*full_path) {
964 rc = -ENOENT;
965 } else {
966 rc = open_cached_dir(xid, tcon, full_path,
967 cifs_sb, false, &cfid);
968 }
969 /* If it is a root and its handle is cached then use it */
970 if (!rc) {
971 if (cfid->file_all_info_is_valid) {
972 memcpy(&data->fi, &cfid->file_all_info,
973 sizeof(data->fi));
974 } else {
975 rc = SMB2_query_info(xid, tcon,
976 cfid->fid.persistent_fid,
977 cfid->fid.volatile_fid,
978 &data->fi);
979 }
980 close_cached_dir(cfid);
981 return rc;
982 }
983 cmds[num_cmds++] = SMB2_OP_QUERY_INFO;
984 } else {
985 cmds[num_cmds++] = SMB2_OP_POSIX_QUERY_INFO;
986 }
987
988 in_iov[0].iov_base = data;
989 in_iov[0].iov_len = sizeof(*data);
990 in_iov[1] = in_iov[0];
991 in_iov[2] = in_iov[0];
992
993 cifs_get_readable_path(tcon, full_path, &cfile);
994 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,
995 FILE_OPEN, create_options, ACL_NO_MODE);
996 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
997 &oparms, in_iov, cmds, num_cmds,
998 cfile, out_iov, out_buftype, NULL);
999 hdr = out_iov[0].iov_base;
1000 /*
1001 * If first iov is unset, then SMB session was dropped or we've got a
1002 * cached open file (@cfile).
1003 */
1004 if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
1005 goto out;
1006
1007 switch (rc) {
1008 case 0:
1009 rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
1010 break;
1011 case -EACCES:
1012 /*
1013 * If SMB2_OP_QUERY_INFO (called when POSIX extensions are not used) failed with
1014 * STATUS_ACCESS_DENIED then it means that caller does not have permission to
1015 * open the path with FILE_READ_ATTRIBUTES access and therefore cannot issue
1016 * SMB2_OP_QUERY_INFO command.
1017 *
1018 * There is an alternative way how to query limited information about path but still
1019 * suitable for stat() syscall. SMB2 OPEN/CREATE operation returns in its successful
1020 * response subset of query information.
1021 *
1022 * So try to open the path without FILE_READ_ATTRIBUTES but with MAXIMUM_ALLOWED
1023 * access which will grant the maximum possible access to the file and the response
1024 * will contain required query information for stat() syscall.
1025 */
1026
1027 if (tcon->posix_extensions)
1028 break;
1029
1030 num_cmds = 1;
1031 cmds[0] = SMB2_OP_OPEN_QUERY;
1032 in_iov[0].iov_base = data;
1033 in_iov[0].iov_len = sizeof(*data);
1034 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, MAXIMUM_ALLOWED,
1035 FILE_OPEN, create_options, ACL_NO_MODE);
1036 free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
1037 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1038 &oparms, in_iov, cmds, num_cmds,
1039 cfile, out_iov, out_buftype, NULL);
1040
1041 hdr = out_iov[0].iov_base;
1042 if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
1043 goto out;
1044
1045 if (!rc)
1046 rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
1047 break;
1048 case -EOPNOTSUPP:
1049 /*
1050 * BB TODO: When support for special files added to Samba
1051 * re-verify this path.
1052 */
1053 rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
1054 if (rc || !data->reparse_point)
1055 goto out;
1056
1057 /*
1058 * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
1059 * response.
1060 */
1061 if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
1062 cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
1063 if (!tcon->posix_extensions)
1064 cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
1065
1066 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1067 FILE_READ_ATTRIBUTES |
1068 FILE_READ_EA | SYNCHRONIZE,
1069 FILE_OPEN, create_options |
1070 OPEN_REPARSE_POINT, ACL_NO_MODE);
1071 cifs_get_readable_path(tcon, full_path, &cfile);
1072 free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
1073 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1074 &oparms, in_iov, cmds, num_cmds,
1075 cfile, out_iov, out_buftype, NULL);
1076 if (rc && ea_unsupported(cmds, num_cmds,
1077 out_iov, out_buftype)) {
1078 if (data->reparse.tag != IO_REPARSE_TAG_LX_BLK &&
1079 data->reparse.tag != IO_REPARSE_TAG_LX_CHR)
1080 rc = 0;
1081 else
1082 rc = -EOPNOTSUPP;
1083 }
1084
1085 if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc) {
1086 bool directory = le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY;
1087 rc = smb2_fix_symlink_target_type(&data->symlink_target, directory, cifs_sb);
1088 }
1089 break;
1090 case -EREMOTE:
1091 break;
1092 default:
1093 if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
1094 break;
1095 rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
1096 full_path, &islink);
1097 if (rc2) {
1098 rc = rc2;
1099 goto out;
1100 }
1101 if (islink)
1102 rc = -EREMOTE;
1103 }
1104
1105 out:
1106 free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
1107 return rc;
1108 }
1109
1110 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)1111 smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
1112 struct cifs_tcon *tcon, const char *name,
1113 struct cifs_sb_info *cifs_sb)
1114 {
1115 struct cifs_open_parms oparms;
1116
1117 oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
1118 FILE_CREATE, CREATE_NOT_FILE, mode);
1119 return smb2_compound_op(xid, tcon, cifs_sb,
1120 name, &oparms, NULL,
1121 &(int){SMB2_OP_MKDIR}, 1,
1122 NULL, NULL, NULL, NULL);
1123 }
1124
1125 void
smb2_mkdir_setinfo(struct inode * inode,const char * name,struct cifs_sb_info * cifs_sb,struct cifs_tcon * tcon,const unsigned int xid)1126 smb2_mkdir_setinfo(struct inode *inode, const char *name,
1127 struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
1128 const unsigned int xid)
1129 {
1130 struct cifs_open_parms oparms;
1131 FILE_BASIC_INFO data = {};
1132 struct cifsInodeInfo *cifs_i;
1133 struct cifsFileInfo *cfile;
1134 struct kvec in_iov;
1135 u32 dosattrs;
1136 int tmprc;
1137
1138 in_iov.iov_base = &data;
1139 in_iov.iov_len = sizeof(data);
1140 cifs_i = CIFS_I(inode);
1141 dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
1142 data.Attributes = cpu_to_le32(dosattrs);
1143 cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
1144 oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
1145 FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);
1146 tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
1147 &oparms, &in_iov,
1148 &(int){SMB2_OP_SET_INFO}, 1,
1149 cfile, NULL, NULL, NULL);
1150 if (tmprc == 0)
1151 cifs_i->cifsAttrs = dosattrs;
1152 }
1153
1154 int
smb2_rmdir(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)1155 smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1156 struct cifs_sb_info *cifs_sb)
1157 {
1158 struct cifs_open_parms oparms;
1159
1160 drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
1161 oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,
1162 FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
1163 return smb2_compound_op(xid, tcon, cifs_sb,
1164 name, &oparms, NULL,
1165 &(int){SMB2_OP_RMDIR}, 1,
1166 NULL, NULL, NULL, NULL);
1167 }
1168
1169 int
smb2_unlink(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb,struct dentry * dentry)1170 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1171 struct cifs_sb_info *cifs_sb, struct dentry *dentry)
1172 {
1173 struct cifs_open_parms oparms;
1174
1175 oparms = CIFS_OPARMS(cifs_sb, tcon, name,
1176 DELETE, FILE_OPEN,
1177 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
1178 ACL_NO_MODE);
1179 int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1180 NULL, &(int){SMB2_OP_DELETE}, 1,
1181 NULL, NULL, NULL, dentry);
1182 if (rc == -EINVAL) {
1183 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1184 rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1185 NULL, &(int){SMB2_OP_DELETE}, 1,
1186 NULL, NULL, NULL, NULL);
1187 }
1188 return rc;
1189 }
1190
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)1191 static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
1192 const char *from_name, const char *to_name,
1193 struct cifs_sb_info *cifs_sb,
1194 __u32 create_options, __u32 access,
1195 int command, struct cifsFileInfo *cfile,
1196 struct dentry *dentry)
1197 {
1198 struct cifs_open_parms oparms;
1199 struct kvec in_iov;
1200 __le16 *smb2_to_name = NULL;
1201 int rc;
1202
1203 smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
1204 if (smb2_to_name == NULL) {
1205 rc = -ENOMEM;
1206 goto smb2_rename_path;
1207 }
1208 in_iov.iov_base = smb2_to_name;
1209 in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
1210 oparms = CIFS_OPARMS(cifs_sb, tcon, from_name, access, FILE_OPEN,
1211 create_options, ACL_NO_MODE);
1212 rc = smb2_compound_op(xid, tcon, cifs_sb, from_name,
1213 &oparms, &in_iov, &command, 1,
1214 cfile, NULL, NULL, dentry);
1215 smb2_rename_path:
1216 kfree(smb2_to_name);
1217 return rc;
1218 }
1219
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)1220 int smb2_rename_path(const unsigned int xid,
1221 struct cifs_tcon *tcon,
1222 struct dentry *source_dentry,
1223 const char *from_name, const char *to_name,
1224 struct cifs_sb_info *cifs_sb)
1225 {
1226 struct cifsFileInfo *cfile;
1227 __u32 co = file_create_options(source_dentry);
1228
1229 drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
1230 cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
1231
1232 int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1233 co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
1234 if (rc == -EINVAL) {
1235 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1236 cifs_get_writable_path(tcon, from_name,
1237 FIND_WR_WITH_DELETE, &cfile);
1238 rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1239 co, DELETE, SMB2_OP_RENAME, cfile, NULL);
1240 }
1241 return rc;
1242 }
1243
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)1244 int smb2_create_hardlink(const unsigned int xid,
1245 struct cifs_tcon *tcon,
1246 struct dentry *source_dentry,
1247 const char *from_name, const char *to_name,
1248 struct cifs_sb_info *cifs_sb)
1249 {
1250 __u32 co = file_create_options(source_dentry);
1251
1252 return smb2_set_path_attr(xid, tcon, from_name, to_name,
1253 cifs_sb, co, FILE_READ_ATTRIBUTES,
1254 SMB2_OP_HARDLINK, NULL, NULL);
1255 }
1256
1257 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)1258 smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
1259 const char *full_path, __u64 size,
1260 struct cifs_sb_info *cifs_sb, bool set_alloc,
1261 struct dentry *dentry)
1262 {
1263 struct cifs_open_parms oparms;
1264 struct cifsFileInfo *cfile;
1265 struct kvec in_iov;
1266 __le64 eof = cpu_to_le64(size);
1267 int rc;
1268
1269 in_iov.iov_base = &eof;
1270 in_iov.iov_len = sizeof(eof);
1271 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1272
1273 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
1274 FILE_OPEN, 0, ACL_NO_MODE);
1275 rc = smb2_compound_op(xid, tcon, cifs_sb,
1276 full_path, &oparms, &in_iov,
1277 &(int){SMB2_OP_SET_EOF}, 1,
1278 cfile, NULL, NULL, dentry);
1279 if (rc == -EINVAL) {
1280 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1281 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1282 rc = smb2_compound_op(xid, tcon, cifs_sb,
1283 full_path, &oparms, &in_iov,
1284 &(int){SMB2_OP_SET_EOF}, 1,
1285 cfile, NULL, NULL, NULL);
1286 }
1287 return rc;
1288 }
1289
1290 int
smb2_set_file_info(struct inode * inode,const char * full_path,FILE_BASIC_INFO * buf,const unsigned int xid)1291 smb2_set_file_info(struct inode *inode, const char *full_path,
1292 FILE_BASIC_INFO *buf, const unsigned int xid)
1293 {
1294 struct cifs_open_parms oparms;
1295 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1296 struct tcon_link *tlink;
1297 struct cifs_tcon *tcon;
1298 struct cifsFileInfo *cfile;
1299 struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
1300 int rc;
1301
1302 if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
1303 (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
1304 (buf->Attributes == 0))
1305 return 0; /* would be a no op, no sense sending this */
1306
1307 tlink = cifs_sb_tlink(cifs_sb);
1308 if (IS_ERR(tlink))
1309 return PTR_ERR(tlink);
1310 tcon = tlink_tcon(tlink);
1311
1312 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1313 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
1314 FILE_OPEN, 0, ACL_NO_MODE);
1315 rc = smb2_compound_op(xid, tcon, cifs_sb,
1316 full_path, &oparms, &in_iov,
1317 &(int){SMB2_OP_SET_INFO}, 1,
1318 cfile, NULL, NULL, NULL);
1319 cifs_put_tlink(tlink);
1320 return rc;
1321 }
1322
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)1323 struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
1324 struct super_block *sb,
1325 const unsigned int xid,
1326 struct cifs_tcon *tcon,
1327 const char *full_path,
1328 bool directory,
1329 struct kvec *reparse_iov,
1330 struct kvec *xattr_iov)
1331 {
1332 struct cifs_open_parms oparms;
1333 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1334 struct cifsFileInfo *cfile;
1335 struct inode *new = NULL;
1336 int out_buftype[4] = {};
1337 struct kvec out_iov[4] = {};
1338 struct kvec in_iov[2];
1339 int cmds[2];
1340 int rc;
1341 int i;
1342
1343 /*
1344 * If server filesystem does not support reparse points then do not
1345 * attempt to create reparse point. This will prevent creating unusable
1346 * empty object on the server.
1347 */
1348 if (!(le32_to_cpu(tcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS))
1349 return ERR_PTR(-EOPNOTSUPP);
1350
1351 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1352 SYNCHRONIZE | DELETE |
1353 FILE_READ_ATTRIBUTES |
1354 FILE_WRITE_ATTRIBUTES,
1355 FILE_CREATE,
1356 (directory ? CREATE_NOT_FILE : CREATE_NOT_DIR) | OPEN_REPARSE_POINT,
1357 ACL_NO_MODE);
1358 if (xattr_iov)
1359 oparms.ea_cctx = xattr_iov;
1360
1361 cmds[0] = SMB2_OP_SET_REPARSE;
1362 in_iov[0] = *reparse_iov;
1363 in_iov[1].iov_base = data;
1364 in_iov[1].iov_len = sizeof(*data);
1365
1366 if (tcon->posix_extensions) {
1367 cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
1368 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1369 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1370 in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
1371 if (!rc) {
1372 rc = smb311_posix_get_inode_info(&new, full_path,
1373 data, sb, xid);
1374 }
1375 } else {
1376 cmds[1] = SMB2_OP_QUERY_INFO;
1377 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1378 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1379 in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
1380 if (!rc) {
1381 rc = cifs_get_inode_info(&new, full_path,
1382 data, sb, xid, NULL);
1383 }
1384 }
1385
1386
1387 /*
1388 * If CREATE was successful but SMB2_OP_SET_REPARSE failed then
1389 * remove the intermediate object created by CREATE. Otherwise
1390 * empty object stay on the server when reparse call failed.
1391 */
1392 if (rc &&
1393 out_iov[0].iov_base != NULL && out_buftype[0] != CIFS_NO_BUFFER &&
1394 ((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_SUCCESS &&
1395 (out_iov[1].iov_base == NULL || out_buftype[1] == CIFS_NO_BUFFER ||
1396 ((struct smb2_hdr *)out_iov[1].iov_base)->Status != STATUS_SUCCESS))
1397 smb2_unlink(xid, tcon, full_path, cifs_sb, NULL);
1398
1399 for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
1400 free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
1401
1402 return rc ? ERR_PTR(rc) : new;
1403 }
1404
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)1405 int smb2_query_reparse_point(const unsigned int xid,
1406 struct cifs_tcon *tcon,
1407 struct cifs_sb_info *cifs_sb,
1408 const char *full_path,
1409 u32 *tag, struct kvec *rsp,
1410 int *rsp_buftype)
1411 {
1412 struct cifs_open_parms oparms;
1413 struct cifs_open_info_data data = {};
1414 struct cifsFileInfo *cfile;
1415 struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
1416 int rc;
1417
1418 cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
1419
1420 cifs_get_readable_path(tcon, full_path, &cfile);
1421 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1422 FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,
1423 FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE);
1424 rc = smb2_compound_op(xid, tcon, cifs_sb,
1425 full_path, &oparms, &in_iov,
1426 &(int){SMB2_OP_GET_REPARSE}, 1,
1427 cfile, NULL, NULL, NULL);
1428 if (rc)
1429 goto out;
1430
1431 *tag = data.reparse.tag;
1432 *rsp = data.reparse.io.iov;
1433 *rsp_buftype = data.reparse.io.buftype;
1434 memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
1435 data.reparse.io.buftype = CIFS_NO_BUFFER;
1436 out:
1437 cifs_free_open_info(&data);
1438 return rc;
1439 }
1440