1 // SPDX-License-Identifier: LGPL-2.1 2 /* 3 * 4 * Copyright (C) International Business Machines Corp., 2002,2008 5 * Author(s): Steve French (sfrench@us.ibm.com) 6 * 7 */ 8 #include <linux/fs.h> 9 #include <linux/stat.h> 10 #include <linux/slab.h> 11 #include <linux/namei.h> 12 #include "cifsfs.h" 13 #include "cifspdu.h" 14 #include "cifsglob.h" 15 #include "cifsproto.h" 16 #include "cifs_debug.h" 17 #include "cifs_fs_sb.h" 18 #include "cifs_unicode.h" 19 #include "smb2proto.h" 20 #include "cifs_ioctl.h" 21 22 /* 23 * M-F Symlink Functions - Begin 24 */ 25 26 #define CIFS_MF_SYMLINK_LEN_OFFSET (4+1) 27 #define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1)) 28 #define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1)) 29 #define CIFS_MF_SYMLINK_LINK_MAXLEN (1024) 30 #define CIFS_MF_SYMLINK_FILE_SIZE \ 31 (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN) 32 33 #define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n" 34 #define CIFS_MF_SYMLINK_MD5_FORMAT "%16phN\n" 35 #define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash 36 37 static int 38 symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) 39 { 40 int rc; 41 struct shash_desc *md5 = NULL; 42 43 rc = cifs_alloc_hash("md5", &md5); 44 if (rc) 45 return rc; 46 47 rc = crypto_shash_digest(md5, link_str, link_len, md5_hash); 48 if (rc) 49 cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); 50 cifs_free_hash(&md5); 51 return rc; 52 } 53 54 static int 55 parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len, 56 char **_link_str) 57 { 58 int rc; 59 unsigned int link_len; 60 const char *md5_str1; 61 const char *link_str; 62 u8 md5_hash[16]; 63 char md5_str2[34]; 64 65 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE) 66 return -EINVAL; 67 68 md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET]; 69 link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET]; 70 71 rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len); 72 if (rc != 1) 73 return -EINVAL; 74 75 if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN) 76 return -EINVAL; 77 78 rc = symlink_hash(link_len, link_str, md5_hash); 79 if (rc) { 80 cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc); 81 return rc; 82 } 83 84 scnprintf(md5_str2, sizeof(md5_str2), 85 CIFS_MF_SYMLINK_MD5_FORMAT, 86 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); 87 88 if (strncmp(md5_str1, md5_str2, 17) != 0) 89 return -EINVAL; 90 91 if (_link_str) { 92 *_link_str = kstrndup(link_str, link_len, GFP_KERNEL); 93 if (!*_link_str) 94 return -ENOMEM; 95 } 96 97 *_link_len = link_len; 98 return 0; 99 } 100 101 static int 102 format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str) 103 { 104 int rc; 105 unsigned int link_len; 106 unsigned int ofs; 107 u8 md5_hash[16]; 108 109 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE) 110 return -EINVAL; 111 112 link_len = strlen(link_str); 113 114 if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN) 115 return -ENAMETOOLONG; 116 117 rc = symlink_hash(link_len, link_str, md5_hash); 118 if (rc) { 119 cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc); 120 return rc; 121 } 122 123 scnprintf(buf, buf_len, 124 CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT, 125 link_len, 126 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); 127 128 ofs = CIFS_MF_SYMLINK_LINK_OFFSET; 129 memcpy(buf + ofs, link_str, link_len); 130 131 ofs += link_len; 132 if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) { 133 buf[ofs] = '\n'; 134 ofs++; 135 } 136 137 while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) { 138 buf[ofs] = ' '; 139 ofs++; 140 } 141 142 return 0; 143 } 144 145 bool 146 couldbe_mf_symlink(const struct cifs_fattr *fattr) 147 { 148 if (!S_ISREG(fattr->cf_mode)) 149 /* it's not a symlink */ 150 return false; 151 152 if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE) 153 /* it's not a symlink */ 154 return false; 155 156 return true; 157 } 158 159 static int 160 create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon, 161 struct cifs_sb_info *cifs_sb, const char *fromName, 162 const char *toName) 163 { 164 int rc; 165 u8 *buf; 166 unsigned int bytes_written = 0; 167 168 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); 169 if (!buf) 170 return -ENOMEM; 171 172 rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName); 173 if (rc) 174 goto out; 175 176 if (tcon->ses->server->ops->create_mf_symlink) 177 rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon, 178 cifs_sb, fromName, buf, &bytes_written); 179 else 180 rc = -EOPNOTSUPP; 181 182 if (rc) 183 goto out; 184 185 if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE) 186 rc = -EIO; 187 out: 188 kfree(buf); 189 return rc; 190 } 191 192 int 193 check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, 194 struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, 195 const unsigned char *path) 196 { 197 int rc; 198 u8 *buf = NULL; 199 unsigned int link_len = 0; 200 unsigned int bytes_read = 0; 201 char *symlink = NULL; 202 203 if (!couldbe_mf_symlink(fattr)) 204 /* it's not a symlink */ 205 return 0; 206 207 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); 208 if (!buf) 209 return -ENOMEM; 210 211 if (tcon->ses->server->ops->query_mf_symlink) 212 rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon, 213 cifs_sb, path, buf, &bytes_read); 214 else 215 rc = -ENOSYS; 216 217 if (rc) 218 goto out; 219 220 if (bytes_read == 0) /* not a symlink */ 221 goto out; 222 223 rc = parse_mf_symlink(buf, bytes_read, &link_len, &symlink); 224 if (rc == -EINVAL) { 225 /* it's not a symlink */ 226 rc = 0; 227 goto out; 228 } 229 230 if (rc != 0) 231 goto out; 232 233 /* it is a symlink */ 234 fattr->cf_eof = link_len; 235 fattr->cf_mode &= ~S_IFMT; 236 fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; 237 fattr->cf_dtype = DT_LNK; 238 fattr->cf_symlink_target = symlink; 239 out: 240 kfree(buf); 241 return rc; 242 } 243 244 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 245 /* 246 * SMB 1.0 Protocol specific functions 247 */ 248 249 int 250 cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, 251 struct cifs_sb_info *cifs_sb, const unsigned char *path, 252 char *pbuf, unsigned int *pbytes_read) 253 { 254 int rc; 255 int oplock = 0; 256 struct cifs_fid fid; 257 struct cifs_open_parms oparms; 258 struct cifs_io_parms io_parms = {0}; 259 int buf_type = CIFS_NO_BUFFER; 260 FILE_ALL_INFO file_info; 261 262 oparms = (struct cifs_open_parms) { 263 .tcon = tcon, 264 .cifs_sb = cifs_sb, 265 .desired_access = GENERIC_READ, 266 .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 267 .disposition = FILE_OPEN, 268 .path = path, 269 .fid = &fid, 270 }; 271 272 rc = CIFS_open(xid, &oparms, &oplock, &file_info); 273 if (rc) 274 return rc; 275 276 if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { 277 rc = -ENOENT; 278 /* it's not a symlink */ 279 goto out; 280 } 281 282 io_parms.netfid = fid.netfid; 283 io_parms.pid = current->tgid; 284 io_parms.tcon = tcon; 285 io_parms.offset = 0; 286 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 287 288 rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type); 289 out: 290 CIFSSMBClose(xid, tcon, fid.netfid); 291 return rc; 292 } 293 294 int 295 cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, 296 struct cifs_sb_info *cifs_sb, const unsigned char *path, 297 char *pbuf, unsigned int *pbytes_written) 298 { 299 int rc; 300 int oplock = 0; 301 struct cifs_fid fid; 302 struct cifs_open_parms oparms; 303 struct cifs_io_parms io_parms = {0}; 304 305 oparms = (struct cifs_open_parms) { 306 .tcon = tcon, 307 .cifs_sb = cifs_sb, 308 .desired_access = GENERIC_WRITE, 309 .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 310 .disposition = FILE_CREATE, 311 .path = path, 312 .fid = &fid, 313 }; 314 315 rc = CIFS_open(xid, &oparms, &oplock, NULL); 316 if (rc) 317 return rc; 318 319 io_parms.netfid = fid.netfid; 320 io_parms.pid = current->tgid; 321 io_parms.tcon = tcon; 322 io_parms.offset = 0; 323 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 324 325 rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf); 326 CIFSSMBClose(xid, tcon, fid.netfid); 327 return rc; 328 } 329 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 330 331 /* 332 * SMB 2.1/SMB3 Protocol specific functions 333 */ 334 int 335 smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, 336 struct cifs_sb_info *cifs_sb, const unsigned char *path, 337 char *pbuf, unsigned int *pbytes_read) 338 { 339 int rc; 340 struct cifs_fid fid; 341 struct cifs_open_parms oparms; 342 struct cifs_io_parms io_parms = {0}; 343 int buf_type = CIFS_NO_BUFFER; 344 __le16 *utf16_path; 345 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 346 struct smb2_file_all_info *pfile_info = NULL; 347 348 oparms = (struct cifs_open_parms) { 349 .tcon = tcon, 350 .cifs_sb = cifs_sb, 351 .path = path, 352 .desired_access = GENERIC_READ, 353 .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 354 .disposition = FILE_OPEN, 355 .fid = &fid, 356 }; 357 358 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); 359 if (utf16_path == NULL) 360 return -ENOMEM; 361 362 pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2, 363 GFP_KERNEL); 364 365 if (pfile_info == NULL) { 366 kfree(utf16_path); 367 return -ENOMEM; 368 } 369 370 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL, 371 NULL, NULL); 372 if (rc) 373 goto qmf_out_open_fail; 374 375 if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { 376 /* it's not a symlink */ 377 rc = -ENOENT; /* Is there a better rc to return? */ 378 goto qmf_out; 379 } 380 381 io_parms.netfid = fid.netfid; 382 io_parms.pid = current->tgid; 383 io_parms.tcon = tcon; 384 io_parms.offset = 0; 385 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 386 io_parms.persistent_fid = fid.persistent_fid; 387 io_parms.volatile_fid = fid.volatile_fid; 388 rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type); 389 qmf_out: 390 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); 391 qmf_out_open_fail: 392 kfree(utf16_path); 393 kfree(pfile_info); 394 return rc; 395 } 396 397 int 398 smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, 399 struct cifs_sb_info *cifs_sb, const unsigned char *path, 400 char *pbuf, unsigned int *pbytes_written) 401 { 402 int rc; 403 struct cifs_fid fid; 404 struct cifs_open_parms oparms; 405 struct cifs_io_parms io_parms = {0}; 406 __le16 *utf16_path; 407 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 408 struct kvec iov[2]; 409 410 cifs_dbg(FYI, "%s: path: %s\n", __func__, path); 411 412 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); 413 if (!utf16_path) 414 return -ENOMEM; 415 416 oparms = (struct cifs_open_parms) { 417 .tcon = tcon, 418 .cifs_sb = cifs_sb, 419 .path = path, 420 .desired_access = GENERIC_WRITE, 421 .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 422 .disposition = FILE_CREATE, 423 .fid = &fid, 424 .mode = 0644, 425 }; 426 427 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, 428 NULL, NULL); 429 if (rc) { 430 kfree(utf16_path); 431 return rc; 432 } 433 434 io_parms.netfid = fid.netfid; 435 io_parms.pid = current->tgid; 436 io_parms.tcon = tcon; 437 io_parms.offset = 0; 438 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 439 io_parms.persistent_fid = fid.persistent_fid; 440 io_parms.volatile_fid = fid.volatile_fid; 441 442 /* iov[0] is reserved for smb header */ 443 iov[1].iov_base = pbuf; 444 iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE; 445 446 rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1); 447 448 /* Make sure we wrote all of the symlink data */ 449 if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE)) 450 rc = -EIO; 451 452 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); 453 454 kfree(utf16_path); 455 return rc; 456 } 457 458 /* 459 * M-F Symlink Functions - End 460 */ 461 462 int 463 cifs_hardlink(struct dentry *old_file, struct inode *inode, 464 struct dentry *direntry) 465 { 466 int rc = -EACCES; 467 unsigned int xid; 468 const char *from_name, *to_name; 469 void *page1, *page2; 470 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 471 struct tcon_link *tlink; 472 struct cifs_tcon *tcon; 473 struct TCP_Server_Info *server; 474 struct cifsInodeInfo *cifsInode; 475 476 if (unlikely(cifs_forced_shutdown(cifs_sb))) 477 return -EIO; 478 479 tlink = cifs_sb_tlink(cifs_sb); 480 if (IS_ERR(tlink)) 481 return PTR_ERR(tlink); 482 tcon = tlink_tcon(tlink); 483 484 xid = get_xid(); 485 page1 = alloc_dentry_path(); 486 page2 = alloc_dentry_path(); 487 488 from_name = build_path_from_dentry(old_file, page1); 489 if (IS_ERR(from_name)) { 490 rc = PTR_ERR(from_name); 491 goto cifs_hl_exit; 492 } 493 to_name = build_path_from_dentry(direntry, page2); 494 if (IS_ERR(to_name)) { 495 rc = PTR_ERR(to_name); 496 goto cifs_hl_exit; 497 } 498 499 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 500 if (tcon->unix_ext) 501 rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name, 502 cifs_sb->local_nls, 503 cifs_remap(cifs_sb)); 504 else { 505 #else 506 { 507 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 508 server = tcon->ses->server; 509 if (!server->ops->create_hardlink) { 510 rc = -ENOSYS; 511 goto cifs_hl_exit; 512 } 513 rc = server->ops->create_hardlink(xid, tcon, old_file, 514 from_name, to_name, cifs_sb); 515 if ((rc == -EIO) || (rc == -EINVAL)) 516 rc = -EOPNOTSUPP; 517 } 518 519 d_drop(direntry); /* force new lookup from server of target */ 520 521 /* 522 * if source file is cached (oplocked) revalidate will not go to server 523 * until the file is closed or oplock broken so update nlinks locally 524 */ 525 if (d_really_is_positive(old_file)) { 526 cifsInode = CIFS_I(d_inode(old_file)); 527 if (rc == 0) { 528 spin_lock(&d_inode(old_file)->i_lock); 529 inc_nlink(d_inode(old_file)); 530 spin_unlock(&d_inode(old_file)->i_lock); 531 532 /* 533 * parent dir timestamps will update from srv within a 534 * second, would it really be worth it to set the parent 535 * dir cifs inode time to zero to force revalidate 536 * (faster) for it too? 537 */ 538 } 539 /* 540 * if not oplocked will force revalidate to get info on source 541 * file from srv. Note Samba server prior to 4.2 has bug - 542 * not updating src file ctime on hardlinks but Windows servers 543 * handle it properly 544 */ 545 cifsInode->time = 0; 546 547 /* 548 * Will update parent dir timestamps from srv within a second. 549 * Would it really be worth it to set the parent dir (cifs 550 * inode) time field to zero to force revalidate on parent 551 * directory faster ie 552 * 553 * CIFS_I(inode)->time = 0; 554 */ 555 } 556 557 cifs_hl_exit: 558 free_dentry_path(page1); 559 free_dentry_path(page2); 560 free_xid(xid); 561 cifs_put_tlink(tlink); 562 return rc; 563 } 564 565 int 566 cifs_symlink(struct mnt_idmap *idmap, struct inode *inode, 567 struct dentry *direntry, const char *symname) 568 { 569 int rc = -EOPNOTSUPP; 570 unsigned int xid; 571 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 572 struct TCP_Server_Info *server; 573 struct tcon_link *tlink; 574 struct cifs_tcon *pTcon; 575 const char *full_path; 576 void *page; 577 struct inode *newinode = NULL; 578 579 if (unlikely(cifs_forced_shutdown(cifs_sb))) 580 return -EIO; 581 582 page = alloc_dentry_path(); 583 if (!page) 584 return -ENOMEM; 585 586 xid = get_xid(); 587 588 tlink = cifs_sb_tlink(cifs_sb); 589 if (IS_ERR(tlink)) { 590 rc = PTR_ERR(tlink); 591 /* BB could be clearer if skipped put_tlink on error here, but harmless */ 592 goto symlink_exit; 593 } 594 pTcon = tlink_tcon(tlink); 595 server = cifs_pick_channel(pTcon->ses); 596 597 full_path = build_path_from_dentry(direntry, page); 598 if (IS_ERR(full_path)) { 599 rc = PTR_ERR(full_path); 600 goto symlink_exit; 601 } 602 603 cifs_dbg(FYI, "Full path: %s\n", full_path); 604 cifs_dbg(FYI, "symname is %s\n", symname); 605 606 /* BB what if DFS and this volume is on different share? BB */ 607 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 608 rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); 609 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 610 } else if (pTcon->unix_ext) { 611 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, 612 cifs_sb->local_nls, 613 cifs_remap(cifs_sb)); 614 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 615 } else if (server->ops->create_reparse_symlink) { 616 rc = server->ops->create_reparse_symlink(xid, inode, direntry, 617 pTcon, full_path, 618 symname); 619 goto symlink_exit; 620 } 621 622 if (rc == 0) { 623 if (pTcon->posix_extensions) { 624 rc = smb311_posix_get_inode_info(&newinode, full_path, 625 NULL, inode->i_sb, xid); 626 } else if (pTcon->unix_ext) { 627 rc = cifs_get_inode_info_unix(&newinode, full_path, 628 inode->i_sb, xid); 629 } else { 630 rc = cifs_get_inode_info(&newinode, full_path, NULL, 631 inode->i_sb, xid, NULL); 632 } 633 634 if (rc != 0) { 635 cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n", 636 rc); 637 } else { 638 d_instantiate(direntry, newinode); 639 } 640 } 641 symlink_exit: 642 free_dentry_path(page); 643 cifs_put_tlink(tlink); 644 free_xid(xid); 645 return rc; 646 } 647
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.