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 "smb2status.h" 28 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 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 /* 60 * note: If cfile is passed, the reference to it is dropped here. 61 * So make sure that you do not reuse cfile after return from this func. 62 * 63 * If passing @out_iov and @out_buftype, ensure to make them both large enough 64 * (>= 3) to hold all compounded responses. Caller is also responsible for 65 * freeing them up with free_rsp_buf(). 66 */ 67 static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, 68 struct cifs_sb_info *cifs_sb, const char *full_path, 69 __u32 desired_access, __u32 create_disposition, 70 __u32 create_options, umode_t mode, struct kvec *in_iov, 71 int *cmds, int num_cmds, struct cifsFileInfo *cfile, 72 __u8 **extbuf, size_t *extbuflen, 73 struct kvec *out_iov, int *out_buftype) 74 { 75 76 struct reparse_data_buffer *rbuf; 77 struct smb2_compound_vars *vars = NULL; 78 struct kvec *rsp_iov, *iov; 79 struct smb_rqst *rqst; 80 int rc; 81 __le16 *utf16_path = NULL; 82 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 83 struct cifs_fid fid; 84 struct cifs_ses *ses = tcon->ses; 85 struct TCP_Server_Info *server; 86 int num_rqst = 0, i; 87 int resp_buftype[MAX_COMPOUND]; 88 struct smb2_query_info_rsp *qi_rsp = NULL; 89 struct cifs_open_info_data *idata; 90 int flags = 0; 91 __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0}; 92 unsigned int size[2]; 93 void *data[2]; 94 int len; 95 96 vars = kzalloc(sizeof(*vars), GFP_ATOMIC); 97 if (vars == NULL) 98 return -ENOMEM; 99 rqst = &vars->rqst[0]; 100 rsp_iov = &vars->rsp_iov[0]; 101 102 server = cifs_pick_channel(ses); 103 104 if (smb3_encryption_required(tcon)) 105 flags |= CIFS_TRANSFORM_REQ; 106 107 for (i = 0; i < ARRAY_SIZE(resp_buftype); i++) 108 resp_buftype[i] = CIFS_NO_BUFFER; 109 110 /* We already have a handle so we can skip the open */ 111 if (cfile) 112 goto after_open; 113 114 /* Open */ 115 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 116 if (!utf16_path) { 117 rc = -ENOMEM; 118 goto finished; 119 } 120 121 vars->oparms = (struct cifs_open_parms) { 122 .tcon = tcon, 123 .path = full_path, 124 .desired_access = desired_access, 125 .disposition = create_disposition, 126 .create_options = cifs_create_options(cifs_sb, create_options), 127 .fid = &fid, 128 .mode = mode, 129 .cifs_sb = cifs_sb, 130 }; 131 132 rqst[num_rqst].rq_iov = &vars->open_iov[0]; 133 rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE; 134 rc = SMB2_open_init(tcon, server, 135 &rqst[num_rqst], &oplock, &vars->oparms, 136 utf16_path); 137 kfree(utf16_path); 138 if (rc) 139 goto finished; 140 141 smb2_set_next_command(tcon, &rqst[num_rqst]); 142 after_open: 143 num_rqst++; 144 rc = 0; 145 146 for (i = 0; i < num_cmds; i++) { 147 /* Operation */ 148 switch (cmds[i]) { 149 case SMB2_OP_QUERY_INFO: 150 rqst[num_rqst].rq_iov = &vars->qi_iov; 151 rqst[num_rqst].rq_nvec = 1; 152 153 if (cfile) { 154 rc = SMB2_query_info_init(tcon, server, 155 &rqst[num_rqst], 156 cfile->fid.persistent_fid, 157 cfile->fid.volatile_fid, 158 FILE_ALL_INFORMATION, 159 SMB2_O_INFO_FILE, 0, 160 sizeof(struct smb2_file_all_info) + 161 PATH_MAX * 2, 0, NULL); 162 } else { 163 rc = SMB2_query_info_init(tcon, server, 164 &rqst[num_rqst], 165 COMPOUND_FID, 166 COMPOUND_FID, 167 FILE_ALL_INFORMATION, 168 SMB2_O_INFO_FILE, 0, 169 sizeof(struct smb2_file_all_info) + 170 PATH_MAX * 2, 0, NULL); 171 if (!rc) { 172 smb2_set_next_command(tcon, &rqst[num_rqst]); 173 smb2_set_related(&rqst[num_rqst]); 174 } 175 } 176 177 if (rc) 178 goto finished; 179 num_rqst++; 180 trace_smb3_query_info_compound_enter(xid, ses->Suid, 181 tcon->tid, full_path); 182 break; 183 case SMB2_OP_POSIX_QUERY_INFO: 184 rqst[num_rqst].rq_iov = &vars->qi_iov; 185 rqst[num_rqst].rq_nvec = 1; 186 187 if (cfile) { 188 /* TBD: fix following to allow for longer SIDs */ 189 rc = SMB2_query_info_init(tcon, server, 190 &rqst[num_rqst], 191 cfile->fid.persistent_fid, 192 cfile->fid.volatile_fid, 193 SMB_FIND_FILE_POSIX_INFO, 194 SMB2_O_INFO_FILE, 0, 195 sizeof(struct smb311_posix_qinfo *) + 196 (PATH_MAX * 2) + 197 (sizeof(struct cifs_sid) * 2), 0, NULL); 198 } else { 199 rc = SMB2_query_info_init(tcon, server, 200 &rqst[num_rqst], 201 COMPOUND_FID, 202 COMPOUND_FID, 203 SMB_FIND_FILE_POSIX_INFO, 204 SMB2_O_INFO_FILE, 0, 205 sizeof(struct smb311_posix_qinfo *) + 206 (PATH_MAX * 2) + 207 (sizeof(struct cifs_sid) * 2), 0, NULL); 208 if (!rc) { 209 smb2_set_next_command(tcon, &rqst[num_rqst]); 210 smb2_set_related(&rqst[num_rqst]); 211 } 212 } 213 214 if (rc) 215 goto finished; 216 num_rqst++; 217 trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, 218 tcon->tid, full_path); 219 break; 220 case SMB2_OP_DELETE: 221 trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path); 222 break; 223 case SMB2_OP_MKDIR: 224 /* 225 * Directories are created through parameters in the 226 * SMB2_open() call. 227 */ 228 trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path); 229 break; 230 case SMB2_OP_RMDIR: 231 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 232 rqst[num_rqst].rq_nvec = 1; 233 234 size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */ 235 data[0] = &delete_pending[0]; 236 237 rc = SMB2_set_info_init(tcon, server, 238 &rqst[num_rqst], COMPOUND_FID, 239 COMPOUND_FID, current->tgid, 240 FILE_DISPOSITION_INFORMATION, 241 SMB2_O_INFO_FILE, 0, data, size); 242 if (rc) 243 goto finished; 244 smb2_set_next_command(tcon, &rqst[num_rqst]); 245 smb2_set_related(&rqst[num_rqst++]); 246 trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path); 247 break; 248 case SMB2_OP_SET_EOF: 249 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 250 rqst[num_rqst].rq_nvec = 1; 251 252 size[0] = in_iov[i].iov_len; 253 data[0] = in_iov[i].iov_base; 254 255 if (cfile) { 256 rc = SMB2_set_info_init(tcon, server, 257 &rqst[num_rqst], 258 cfile->fid.persistent_fid, 259 cfile->fid.volatile_fid, 260 current->tgid, 261 FILE_END_OF_FILE_INFORMATION, 262 SMB2_O_INFO_FILE, 0, 263 data, size); 264 } else { 265 rc = SMB2_set_info_init(tcon, server, 266 &rqst[num_rqst], 267 COMPOUND_FID, 268 COMPOUND_FID, 269 current->tgid, 270 FILE_END_OF_FILE_INFORMATION, 271 SMB2_O_INFO_FILE, 0, 272 data, size); 273 if (!rc) { 274 smb2_set_next_command(tcon, &rqst[num_rqst]); 275 smb2_set_related(&rqst[num_rqst]); 276 } 277 } 278 if (rc) 279 goto finished; 280 num_rqst++; 281 trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path); 282 break; 283 case SMB2_OP_SET_INFO: 284 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 285 rqst[num_rqst].rq_nvec = 1; 286 287 size[0] = in_iov[i].iov_len; 288 data[0] = in_iov[i].iov_base; 289 290 if (cfile) { 291 rc = SMB2_set_info_init(tcon, server, 292 &rqst[num_rqst], 293 cfile->fid.persistent_fid, 294 cfile->fid.volatile_fid, current->tgid, 295 FILE_BASIC_INFORMATION, 296 SMB2_O_INFO_FILE, 0, data, size); 297 } else { 298 rc = SMB2_set_info_init(tcon, server, 299 &rqst[num_rqst], 300 COMPOUND_FID, 301 COMPOUND_FID, current->tgid, 302 FILE_BASIC_INFORMATION, 303 SMB2_O_INFO_FILE, 0, data, size); 304 if (!rc) { 305 smb2_set_next_command(tcon, &rqst[num_rqst]); 306 smb2_set_related(&rqst[num_rqst]); 307 } 308 } 309 310 if (rc) 311 goto finished; 312 num_rqst++; 313 trace_smb3_set_info_compound_enter(xid, ses->Suid, 314 tcon->tid, full_path); 315 break; 316 case SMB2_OP_RENAME: 317 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 318 rqst[num_rqst].rq_nvec = 2; 319 320 len = in_iov[i].iov_len; 321 322 vars->rename_info.ReplaceIfExists = 1; 323 vars->rename_info.RootDirectory = 0; 324 vars->rename_info.FileNameLength = cpu_to_le32(len); 325 326 size[0] = sizeof(struct smb2_file_rename_info); 327 data[0] = &vars->rename_info; 328 329 size[1] = len + 2 /* null */; 330 data[1] = in_iov[i].iov_base; 331 332 if (cfile) { 333 rc = SMB2_set_info_init(tcon, server, 334 &rqst[num_rqst], 335 cfile->fid.persistent_fid, 336 cfile->fid.volatile_fid, 337 current->tgid, FILE_RENAME_INFORMATION, 338 SMB2_O_INFO_FILE, 0, data, size); 339 } else { 340 rc = SMB2_set_info_init(tcon, server, 341 &rqst[num_rqst], 342 COMPOUND_FID, COMPOUND_FID, 343 current->tgid, FILE_RENAME_INFORMATION, 344 SMB2_O_INFO_FILE, 0, data, size); 345 if (!rc) { 346 smb2_set_next_command(tcon, &rqst[num_rqst]); 347 smb2_set_related(&rqst[num_rqst]); 348 } 349 } 350 if (rc) 351 goto finished; 352 num_rqst++; 353 trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path); 354 break; 355 case SMB2_OP_HARDLINK: 356 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 357 rqst[num_rqst].rq_nvec = 2; 358 359 len = in_iov[i].iov_len; 360 361 vars->link_info.ReplaceIfExists = 0; 362 vars->link_info.RootDirectory = 0; 363 vars->link_info.FileNameLength = cpu_to_le32(len); 364 365 size[0] = sizeof(struct smb2_file_link_info); 366 data[0] = &vars->link_info; 367 368 size[1] = len + 2 /* null */; 369 data[1] = in_iov[i].iov_base; 370 371 rc = SMB2_set_info_init(tcon, server, 372 &rqst[num_rqst], COMPOUND_FID, 373 COMPOUND_FID, current->tgid, 374 FILE_LINK_INFORMATION, 375 SMB2_O_INFO_FILE, 0, data, size); 376 if (rc) 377 goto finished; 378 smb2_set_next_command(tcon, &rqst[num_rqst]); 379 smb2_set_related(&rqst[num_rqst++]); 380 trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path); 381 break; 382 case SMB2_OP_SET_REPARSE: 383 rqst[num_rqst].rq_iov = vars->io_iov; 384 rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov); 385 386 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst], 387 COMPOUND_FID, COMPOUND_FID, 388 FSCTL_SET_REPARSE_POINT, 389 in_iov[i].iov_base, 390 in_iov[i].iov_len, 0); 391 if (rc) 392 goto finished; 393 smb2_set_next_command(tcon, &rqst[num_rqst]); 394 smb2_set_related(&rqst[num_rqst++]); 395 trace_smb3_set_reparse_compound_enter(xid, ses->Suid, 396 tcon->tid, full_path); 397 break; 398 case SMB2_OP_GET_REPARSE: 399 rqst[num_rqst].rq_iov = vars->io_iov; 400 rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov); 401 402 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst], 403 COMPOUND_FID, COMPOUND_FID, 404 FSCTL_GET_REPARSE_POINT, 405 NULL, 0, CIFSMaxBufSize); 406 if (rc) 407 goto finished; 408 smb2_set_next_command(tcon, &rqst[num_rqst]); 409 smb2_set_related(&rqst[num_rqst++]); 410 trace_smb3_get_reparse_compound_enter(xid, ses->Suid, 411 tcon->tid, full_path); 412 break; 413 default: 414 cifs_dbg(VFS, "Invalid command\n"); 415 rc = -EINVAL; 416 } 417 } 418 if (rc) 419 goto finished; 420 421 /* We already have a handle so we can skip the close */ 422 if (cfile) 423 goto after_close; 424 /* Close */ 425 flags |= CIFS_CP_CREATE_CLOSE_OP; 426 rqst[num_rqst].rq_iov = &vars->close_iov; 427 rqst[num_rqst].rq_nvec = 1; 428 rc = SMB2_close_init(tcon, server, 429 &rqst[num_rqst], COMPOUND_FID, 430 COMPOUND_FID, false); 431 smb2_set_related(&rqst[num_rqst]); 432 if (rc) 433 goto finished; 434 after_close: 435 num_rqst++; 436 437 if (cfile) { 438 rc = compound_send_recv(xid, ses, server, 439 flags, num_rqst - 2, 440 &rqst[1], &resp_buftype[1], 441 &rsp_iov[1]); 442 } else 443 rc = compound_send_recv(xid, ses, server, 444 flags, num_rqst, 445 rqst, resp_buftype, 446 rsp_iov); 447 448 finished: 449 num_rqst = 0; 450 SMB2_open_free(&rqst[num_rqst++]); 451 if (rc == -EREMCHG) { 452 pr_warn_once("server share %s deleted\n", tcon->tree_name); 453 tcon->need_reconnect = true; 454 } 455 456 for (i = 0; i < num_cmds; i++) { 457 switch (cmds[i]) { 458 case SMB2_OP_QUERY_INFO: 459 idata = in_iov[i].iov_base; 460 if (rc == 0 && cfile && cfile->symlink_target) { 461 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 462 if (!idata->symlink_target) 463 rc = -ENOMEM; 464 } 465 if (rc == 0) { 466 qi_rsp = (struct smb2_query_info_rsp *) 467 rsp_iov[i + 1].iov_base; 468 rc = smb2_validate_and_copy_iov( 469 le16_to_cpu(qi_rsp->OutputBufferOffset), 470 le32_to_cpu(qi_rsp->OutputBufferLength), 471 &rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi); 472 } 473 SMB2_query_info_free(&rqst[num_rqst++]); 474 if (rc) 475 trace_smb3_query_info_compound_err(xid, ses->Suid, 476 tcon->tid, rc); 477 else 478 trace_smb3_query_info_compound_done(xid, ses->Suid, 479 tcon->tid); 480 break; 481 case SMB2_OP_POSIX_QUERY_INFO: 482 idata = in_iov[i].iov_base; 483 if (rc == 0 && cfile && cfile->symlink_target) { 484 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 485 if (!idata->symlink_target) 486 rc = -ENOMEM; 487 } 488 if (rc == 0) { 489 qi_rsp = (struct smb2_query_info_rsp *) 490 rsp_iov[i + 1].iov_base; 491 rc = smb2_validate_and_copy_iov( 492 le16_to_cpu(qi_rsp->OutputBufferOffset), 493 le32_to_cpu(qi_rsp->OutputBufferLength), 494 &rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */, 495 (char *)&idata->posix_fi); 496 } 497 if (rc == 0) { 498 unsigned int length = le32_to_cpu(qi_rsp->OutputBufferLength); 499 500 if (length > sizeof(idata->posix_fi)) { 501 char *base = (char *)rsp_iov[i + 1].iov_base + 502 le16_to_cpu(qi_rsp->OutputBufferOffset) + 503 sizeof(idata->posix_fi); 504 *extbuflen = length - sizeof(idata->posix_fi); 505 *extbuf = kmemdup(base, *extbuflen, GFP_KERNEL); 506 if (!*extbuf) 507 rc = -ENOMEM; 508 } else { 509 rc = -EINVAL; 510 } 511 } 512 SMB2_query_info_free(&rqst[num_rqst++]); 513 if (rc) 514 trace_smb3_posix_query_info_compound_err(xid, ses->Suid, 515 tcon->tid, rc); 516 else 517 trace_smb3_posix_query_info_compound_done(xid, ses->Suid, 518 tcon->tid); 519 break; 520 case SMB2_OP_DELETE: 521 if (rc) 522 trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc); 523 else 524 trace_smb3_delete_done(xid, ses->Suid, tcon->tid); 525 break; 526 case SMB2_OP_MKDIR: 527 if (rc) 528 trace_smb3_mkdir_err(xid, ses->Suid, tcon->tid, rc); 529 else 530 trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid); 531 break; 532 case SMB2_OP_HARDLINK: 533 if (rc) 534 trace_smb3_hardlink_err(xid, ses->Suid, tcon->tid, rc); 535 else 536 trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid); 537 SMB2_set_info_free(&rqst[num_rqst++]); 538 break; 539 case SMB2_OP_RENAME: 540 if (rc) 541 trace_smb3_rename_err(xid, ses->Suid, tcon->tid, rc); 542 else 543 trace_smb3_rename_done(xid, ses->Suid, tcon->tid); 544 SMB2_set_info_free(&rqst[num_rqst++]); 545 break; 546 case SMB2_OP_RMDIR: 547 if (rc) 548 trace_smb3_rmdir_err(xid, ses->Suid, tcon->tid, rc); 549 else 550 trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid); 551 SMB2_set_info_free(&rqst[num_rqst++]); 552 break; 553 case SMB2_OP_SET_EOF: 554 if (rc) 555 trace_smb3_set_eof_err(xid, ses->Suid, tcon->tid, rc); 556 else 557 trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid); 558 SMB2_set_info_free(&rqst[num_rqst++]); 559 break; 560 case SMB2_OP_SET_INFO: 561 if (rc) 562 trace_smb3_set_info_compound_err(xid, ses->Suid, 563 tcon->tid, rc); 564 else 565 trace_smb3_set_info_compound_done(xid, ses->Suid, 566 tcon->tid); 567 SMB2_set_info_free(&rqst[num_rqst++]); 568 break; 569 case SMB2_OP_SET_REPARSE: 570 if (rc) { 571 trace_smb3_set_reparse_compound_err(xid, ses->Suid, 572 tcon->tid, rc); 573 } else { 574 trace_smb3_set_reparse_compound_done(xid, ses->Suid, 575 tcon->tid); 576 } 577 SMB2_ioctl_free(&rqst[num_rqst++]); 578 break; 579 case SMB2_OP_GET_REPARSE: 580 if (!rc) { 581 iov = &rsp_iov[i + 1]; 582 idata = in_iov[i].iov_base; 583 idata->reparse.io.iov = *iov; 584 idata->reparse.io.buftype = resp_buftype[i + 1]; 585 rbuf = reparse_buf_ptr(iov); 586 if (IS_ERR(rbuf)) { 587 rc = PTR_ERR(rbuf); 588 trace_smb3_set_reparse_compound_err(xid, ses->Suid, 589 tcon->tid, rc); 590 } else { 591 idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag); 592 trace_smb3_set_reparse_compound_done(xid, ses->Suid, 593 tcon->tid); 594 } 595 memset(iov, 0, sizeof(*iov)); 596 resp_buftype[i + 1] = CIFS_NO_BUFFER; 597 } else { 598 trace_smb3_set_reparse_compound_err(xid, ses->Suid, 599 tcon->tid, rc); 600 } 601 SMB2_ioctl_free(&rqst[num_rqst++]); 602 break; 603 } 604 } 605 SMB2_close_free(&rqst[num_rqst]); 606 607 if (cfile) 608 cifsFileInfo_put(cfile); 609 610 num_cmds += 2; 611 if (out_iov && out_buftype) { 612 memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov)); 613 memcpy(out_buftype, resp_buftype, 614 num_cmds * sizeof(*out_buftype)); 615 } else { 616 for (i = 0; i < num_cmds; i++) 617 free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base); 618 } 619 kfree(vars); 620 return rc; 621 } 622 623 static int parse_create_response(struct cifs_open_info_data *data, 624 struct cifs_sb_info *cifs_sb, 625 const struct kvec *iov) 626 { 627 struct smb2_create_rsp *rsp = iov->iov_base; 628 bool reparse_point = false; 629 u32 tag = 0; 630 int rc = 0; 631 632 switch (rsp->hdr.Status) { 633 case STATUS_IO_REPARSE_TAG_NOT_HANDLED: 634 reparse_point = true; 635 break; 636 case STATUS_STOPPED_ON_SYMLINK: 637 rc = smb2_parse_symlink_response(cifs_sb, iov, 638 &data->symlink_target); 639 if (rc) 640 return rc; 641 tag = IO_REPARSE_TAG_SYMLINK; 642 reparse_point = true; 643 break; 644 case STATUS_SUCCESS: 645 reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT); 646 break; 647 } 648 data->reparse_point = reparse_point; 649 data->reparse.tag = tag; 650 return rc; 651 } 652 653 int smb2_query_path_info(const unsigned int xid, 654 struct cifs_tcon *tcon, 655 struct cifs_sb_info *cifs_sb, 656 const char *full_path, 657 struct cifs_open_info_data *data) 658 { 659 __u32 create_options = 0; 660 struct cifsFileInfo *cfile; 661 struct cached_fid *cfid = NULL; 662 struct smb2_hdr *hdr; 663 struct kvec in_iov[2], out_iov[3] = {}; 664 int out_buftype[3] = {}; 665 int cmds[2] = { SMB2_OP_QUERY_INFO, }; 666 bool islink; 667 int i, num_cmds; 668 int rc, rc2; 669 670 data->adjust_tz = false; 671 data->reparse_point = false; 672 673 if (strcmp(full_path, "")) 674 rc = -ENOENT; 675 else 676 rc = open_cached_dir(xid, tcon, full_path, cifs_sb, false, &cfid); 677 /* If it is a root and its handle is cached then use it */ 678 if (!rc) { 679 if (cfid->file_all_info_is_valid) { 680 memcpy(&data->fi, &cfid->file_all_info, sizeof(data->fi)); 681 } else { 682 rc = SMB2_query_info(xid, tcon, cfid->fid.persistent_fid, 683 cfid->fid.volatile_fid, &data->fi); 684 } 685 close_cached_dir(cfid); 686 return rc; 687 } 688 689 in_iov[0].iov_base = data; 690 in_iov[0].iov_len = sizeof(*data); 691 in_iov[1] = in_iov[0]; 692 693 cifs_get_readable_path(tcon, full_path, &cfile); 694 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 695 FILE_READ_ATTRIBUTES, FILE_OPEN, 696 create_options, ACL_NO_MODE, 697 in_iov, cmds, 1, cfile, 698 NULL, NULL, out_iov, out_buftype); 699 hdr = out_iov[0].iov_base; 700 /* 701 * If first iov is unset, then SMB session was dropped or we've got a 702 * cached open file (@cfile). 703 */ 704 if (!hdr || out_buftype[0] == CIFS_NO_BUFFER) 705 goto out; 706 707 switch (rc) { 708 case 0: 709 case -EOPNOTSUPP: 710 rc = parse_create_response(data, cifs_sb, &out_iov[0]); 711 if (rc || !data->reparse_point) 712 goto out; 713 714 if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) { 715 /* symlink already parsed in create response */ 716 num_cmds = 1; 717 } else { 718 cmds[1] = SMB2_OP_GET_REPARSE; 719 num_cmds = 2; 720 } 721 create_options |= OPEN_REPARSE_POINT; 722 cifs_get_readable_path(tcon, full_path, &cfile); 723 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 724 FILE_READ_ATTRIBUTES, FILE_OPEN, 725 create_options, ACL_NO_MODE, in_iov, cmds, 726 num_cmds, cfile, NULL, NULL, NULL, NULL); 727 break; 728 case -EREMOTE: 729 break; 730 default: 731 if (hdr->Status != STATUS_OBJECT_NAME_INVALID) 732 break; 733 rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb, 734 full_path, &islink); 735 if (rc2) { 736 rc = rc2; 737 goto out; 738 } 739 if (islink) 740 rc = -EREMOTE; 741 } 742 743 out: 744 for (i = 0; i < ARRAY_SIZE(out_buftype); i++) 745 free_rsp_buf(out_buftype[i], out_iov[i].iov_base); 746 return rc; 747 } 748 749 int smb311_posix_query_path_info(const unsigned int xid, 750 struct cifs_tcon *tcon, 751 struct cifs_sb_info *cifs_sb, 752 const char *full_path, 753 struct cifs_open_info_data *data, 754 struct cifs_sid *owner, 755 struct cifs_sid *group) 756 { 757 int rc; 758 __u32 create_options = 0; 759 struct cifsFileInfo *cfile; 760 struct kvec in_iov[2], out_iov[3] = {}; 761 int out_buftype[3] = {}; 762 __u8 *sidsbuf = NULL; 763 __u8 *sidsbuf_end = NULL; 764 size_t sidsbuflen = 0; 765 size_t owner_len, group_len; 766 int cmds[2] = { SMB2_OP_POSIX_QUERY_INFO, }; 767 int i, num_cmds; 768 769 data->adjust_tz = false; 770 data->reparse_point = false; 771 772 /* 773 * BB TODO: Add support for using the cached root handle. 774 * Create SMB2_query_posix_info worker function to do non-compounded query 775 * when we already have an open file handle for this. For now this is fast enough 776 * (always using the compounded version). 777 */ 778 in_iov[0].iov_base = data; 779 in_iov[0].iov_len = sizeof(*data); 780 in_iov[1] = in_iov[0]; 781 782 cifs_get_readable_path(tcon, full_path, &cfile); 783 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 784 FILE_READ_ATTRIBUTES, FILE_OPEN, 785 create_options, ACL_NO_MODE, in_iov, cmds, 1, 786 cfile, &sidsbuf, &sidsbuflen, out_iov, out_buftype); 787 /* 788 * If first iov is unset, then SMB session was dropped or we've got a 789 * cached open file (@cfile). 790 */ 791 if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER) 792 goto out; 793 794 switch (rc) { 795 case 0: 796 case -EOPNOTSUPP: 797 /* BB TODO: When support for special files added to Samba re-verify this path */ 798 rc = parse_create_response(data, cifs_sb, &out_iov[0]); 799 if (rc || !data->reparse_point) 800 goto out; 801 802 if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) { 803 /* symlink already parsed in create response */ 804 num_cmds = 1; 805 } else { 806 cmds[1] = SMB2_OP_GET_REPARSE; 807 num_cmds = 2; 808 } 809 create_options |= OPEN_REPARSE_POINT; 810 cifs_get_readable_path(tcon, full_path, &cfile); 811 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 812 FILE_READ_ATTRIBUTES, FILE_OPEN, 813 create_options, ACL_NO_MODE, in_iov, cmds, 814 num_cmds, cfile, &sidsbuf, &sidsbuflen, NULL, NULL); 815 break; 816 } 817 818 out: 819 if (rc == 0) { 820 sidsbuf_end = sidsbuf + sidsbuflen; 821 822 owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end); 823 if (owner_len == -1) { 824 rc = -EINVAL; 825 goto out; 826 } 827 memcpy(owner, sidsbuf, owner_len); 828 829 group_len = posix_info_sid_size( 830 sidsbuf + owner_len, sidsbuf_end); 831 if (group_len == -1) { 832 rc = -EINVAL; 833 goto out; 834 } 835 memcpy(group, sidsbuf + owner_len, group_len); 836 } 837 838 kfree(sidsbuf); 839 for (i = 0; i < ARRAY_SIZE(out_buftype); i++) 840 free_rsp_buf(out_buftype[i], out_iov[i].iov_base); 841 return rc; 842 } 843 844 int 845 smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode, 846 struct cifs_tcon *tcon, const char *name, 847 struct cifs_sb_info *cifs_sb) 848 { 849 return smb2_compound_op(xid, tcon, cifs_sb, name, 850 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 851 CREATE_NOT_FILE, mode, NULL, 852 &(int){SMB2_OP_MKDIR}, 1, 853 NULL, NULL, NULL, NULL, NULL); 854 } 855 856 void 857 smb2_mkdir_setinfo(struct inode *inode, const char *name, 858 struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, 859 const unsigned int xid) 860 { 861 FILE_BASIC_INFO data = {}; 862 struct cifsInodeInfo *cifs_i; 863 struct cifsFileInfo *cfile; 864 struct kvec in_iov; 865 u32 dosattrs; 866 int tmprc; 867 868 in_iov.iov_base = &data; 869 in_iov.iov_len = sizeof(data); 870 cifs_i = CIFS_I(inode); 871 dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; 872 data.Attributes = cpu_to_le32(dosattrs); 873 cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile); 874 tmprc = smb2_compound_op(xid, tcon, cifs_sb, name, 875 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 876 CREATE_NOT_FILE, ACL_NO_MODE, &in_iov, 877 &(int){SMB2_OP_SET_INFO}, 1, 878 cfile, NULL, NULL, NULL, NULL); 879 if (tmprc == 0) 880 cifs_i->cifsAttrs = dosattrs; 881 } 882 883 int 884 smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 885 struct cifs_sb_info *cifs_sb) 886 { 887 drop_cached_dir_by_name(xid, tcon, name, cifs_sb); 888 return smb2_compound_op(xid, tcon, cifs_sb, name, 889 DELETE, FILE_OPEN, CREATE_NOT_FILE, 890 ACL_NO_MODE, NULL, &(int){SMB2_OP_RMDIR}, 1, 891 NULL, NULL, NULL, NULL, NULL); 892 } 893 894 int 895 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 896 struct cifs_sb_info *cifs_sb) 897 { 898 return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 899 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, 900 ACL_NO_MODE, NULL, &(int){SMB2_OP_DELETE}, 1, 901 NULL, NULL, NULL, NULL, NULL); 902 } 903 904 static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, 905 const char *from_name, const char *to_name, 906 struct cifs_sb_info *cifs_sb, 907 __u32 create_options, __u32 access, 908 int command, struct cifsFileInfo *cfile) 909 { 910 struct kvec in_iov; 911 __le16 *smb2_to_name = NULL; 912 int rc; 913 914 smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb); 915 if (smb2_to_name == NULL) { 916 rc = -ENOMEM; 917 goto smb2_rename_path; 918 } 919 in_iov.iov_base = smb2_to_name; 920 in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX); 921 rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, 922 FILE_OPEN, create_options, ACL_NO_MODE, &in_iov, 923 &command, 1, cfile, NULL, NULL, NULL, NULL); 924 smb2_rename_path: 925 kfree(smb2_to_name); 926 return rc; 927 } 928 929 int smb2_rename_path(const unsigned int xid, 930 struct cifs_tcon *tcon, 931 struct dentry *source_dentry, 932 const char *from_name, const char *to_name, 933 struct cifs_sb_info *cifs_sb) 934 { 935 struct cifsFileInfo *cfile; 936 __u32 co = file_create_options(source_dentry); 937 938 drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb); 939 cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile); 940 941 return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, 942 co, DELETE, SMB2_OP_RENAME, cfile); 943 } 944 945 int smb2_create_hardlink(const unsigned int xid, 946 struct cifs_tcon *tcon, 947 struct dentry *source_dentry, 948 const char *from_name, const char *to_name, 949 struct cifs_sb_info *cifs_sb) 950 { 951 __u32 co = file_create_options(source_dentry); 952 953 return smb2_set_path_attr(xid, tcon, from_name, to_name, 954 cifs_sb, co, FILE_READ_ATTRIBUTES, 955 SMB2_OP_HARDLINK, NULL); 956 } 957 958 int 959 smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, 960 const char *full_path, __u64 size, 961 struct cifs_sb_info *cifs_sb, bool set_alloc) 962 { 963 struct cifsFileInfo *cfile; 964 struct kvec in_iov; 965 __le64 eof = cpu_to_le64(size); 966 967 in_iov.iov_base = &eof; 968 in_iov.iov_len = sizeof(eof); 969 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 970 return smb2_compound_op(xid, tcon, cifs_sb, full_path, 971 FILE_WRITE_DATA, FILE_OPEN, 972 0, ACL_NO_MODE, &in_iov, 973 &(int){SMB2_OP_SET_EOF}, 1, 974 cfile, NULL, NULL, NULL, NULL); 975 } 976 977 int 978 smb2_set_file_info(struct inode *inode, const char *full_path, 979 FILE_BASIC_INFO *buf, const unsigned int xid) 980 { 981 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 982 struct tcon_link *tlink; 983 struct cifs_tcon *tcon; 984 struct cifsFileInfo *cfile; 985 struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), }; 986 int rc; 987 988 if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) && 989 (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) && 990 (buf->Attributes == 0)) 991 return 0; /* would be a no op, no sense sending this */ 992 993 tlink = cifs_sb_tlink(cifs_sb); 994 if (IS_ERR(tlink)) 995 return PTR_ERR(tlink); 996 tcon = tlink_tcon(tlink); 997 998 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 999 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 1000 FILE_WRITE_ATTRIBUTES, FILE_OPEN, 1001 0, ACL_NO_MODE, &in_iov, 1002 &(int){SMB2_OP_SET_INFO}, 1, cfile, 1003 NULL, NULL, NULL, NULL); 1004 cifs_put_tlink(tlink); 1005 return rc; 1006 } 1007 1008 struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, 1009 struct super_block *sb, 1010 const unsigned int xid, 1011 struct cifs_tcon *tcon, 1012 const char *full_path, 1013 struct kvec *iov) 1014 { 1015 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1016 struct cifsFileInfo *cfile; 1017 struct inode *new = NULL; 1018 struct kvec in_iov[2]; 1019 int cmds[2]; 1020 int da, co, cd; 1021 int rc; 1022 1023 da = SYNCHRONIZE | DELETE | 1024 FILE_READ_ATTRIBUTES | 1025 FILE_WRITE_ATTRIBUTES; 1026 co = CREATE_NOT_DIR | OPEN_REPARSE_POINT; 1027 cd = FILE_CREATE; 1028 cmds[0] = SMB2_OP_SET_REPARSE; 1029 in_iov[0] = *iov; 1030 in_iov[1].iov_base = data; 1031 in_iov[1].iov_len = sizeof(*data); 1032 1033 if (tcon->posix_extensions) { 1034 cmds[1] = SMB2_OP_POSIX_QUERY_INFO; 1035 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 1036 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 1037 da, cd, co, ACL_NO_MODE, in_iov, 1038 cmds, 2, cfile, NULL, NULL, NULL, NULL); 1039 if (!rc) { 1040 rc = smb311_posix_get_inode_info(&new, full_path, 1041 data, sb, xid); 1042 } 1043 } else { 1044 cmds[1] = SMB2_OP_QUERY_INFO; 1045 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 1046 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 1047 da, cd, co, ACL_NO_MODE, in_iov, 1048 cmds, 2, cfile, NULL, NULL, NULL, NULL); 1049 if (!rc) { 1050 rc = cifs_get_inode_info(&new, full_path, 1051 data, sb, xid, NULL); 1052 } 1053 } 1054 return rc ? ERR_PTR(rc) : new; 1055 } 1056 1057 int smb2_query_reparse_point(const unsigned int xid, 1058 struct cifs_tcon *tcon, 1059 struct cifs_sb_info *cifs_sb, 1060 const char *full_path, 1061 u32 *tag, struct kvec *rsp, 1062 int *rsp_buftype) 1063 { 1064 struct cifs_open_info_data data = {}; 1065 struct cifsFileInfo *cfile; 1066 struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), }; 1067 int rc; 1068 1069 cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); 1070 1071 cifs_get_readable_path(tcon, full_path, &cfile); 1072 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 1073 FILE_READ_ATTRIBUTES, FILE_OPEN, 1074 OPEN_REPARSE_POINT, ACL_NO_MODE, &in_iov, 1075 &(int){SMB2_OP_GET_REPARSE}, 1, cfile, 1076 NULL, NULL, NULL, NULL); 1077 if (rc) 1078 goto out; 1079 1080 *tag = data.reparse.tag; 1081 *rsp = data.reparse.io.iov; 1082 *rsp_buftype = data.reparse.io.buftype; 1083 memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov)); 1084 data.reparse.io.buftype = CIFS_NO_BUFFER; 1085 out: 1086 cifs_free_open_info(&data); 1087 return rc; 1088 } 1089