at v3.10 622 lines 15 kB view raw
1/* 2 * fs/cifs/link.c 3 * 4 * Copyright (C) International Business Machines Corp., 2002,2008 5 * Author(s): Steve French (sfrench@us.ibm.com) 6 * 7 * This library is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU Lesser General Public License as published 9 * by the Free Software Foundation; either version 2.1 of the License, or 10 * (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 15 * the GNU Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with this library; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21#include <linux/fs.h> 22#include <linux/stat.h> 23#include <linux/slab.h> 24#include <linux/namei.h> 25#include "cifsfs.h" 26#include "cifspdu.h" 27#include "cifsglob.h" 28#include "cifsproto.h" 29#include "cifs_debug.h" 30#include "cifs_fs_sb.h" 31 32#define CIFS_MF_SYMLINK_LEN_OFFSET (4+1) 33#define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1)) 34#define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1)) 35#define CIFS_MF_SYMLINK_LINK_MAXLEN (1024) 36#define CIFS_MF_SYMLINK_FILE_SIZE \ 37 (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN) 38 39#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n" 40#define CIFS_MF_SYMLINK_MD5_FORMAT \ 41 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n" 42#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \ 43 md5_hash[0], md5_hash[1], md5_hash[2], md5_hash[3], \ 44 md5_hash[4], md5_hash[5], md5_hash[6], md5_hash[7], \ 45 md5_hash[8], md5_hash[9], md5_hash[10], md5_hash[11],\ 46 md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15] 47 48static int 49symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) 50{ 51 int rc; 52 unsigned int size; 53 struct crypto_shash *md5; 54 struct sdesc *sdescmd5; 55 56 md5 = crypto_alloc_shash("md5", 0, 0); 57 if (IS_ERR(md5)) { 58 rc = PTR_ERR(md5); 59 cifs_dbg(VFS, "%s: Crypto md5 allocation error %d\n", 60 __func__, rc); 61 return rc; 62 } 63 size = sizeof(struct shash_desc) + crypto_shash_descsize(md5); 64 sdescmd5 = kmalloc(size, GFP_KERNEL); 65 if (!sdescmd5) { 66 rc = -ENOMEM; 67 goto symlink_hash_err; 68 } 69 sdescmd5->shash.tfm = md5; 70 sdescmd5->shash.flags = 0x0; 71 72 rc = crypto_shash_init(&sdescmd5->shash); 73 if (rc) { 74 cifs_dbg(VFS, "%s: Could not init md5 shash\n", __func__); 75 goto symlink_hash_err; 76 } 77 rc = crypto_shash_update(&sdescmd5->shash, link_str, link_len); 78 if (rc) { 79 cifs_dbg(VFS, "%s: Could not update with link_str\n", __func__); 80 goto symlink_hash_err; 81 } 82 rc = crypto_shash_final(&sdescmd5->shash, md5_hash); 83 if (rc) 84 cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); 85 86symlink_hash_err: 87 crypto_free_shash(md5); 88 kfree(sdescmd5); 89 90 return rc; 91} 92 93static int 94CIFSParseMFSymlink(const u8 *buf, 95 unsigned int buf_len, 96 unsigned int *_link_len, 97 char **_link_str) 98{ 99 int rc; 100 unsigned int link_len; 101 const char *md5_str1; 102 const char *link_str; 103 u8 md5_hash[16]; 104 char md5_str2[34]; 105 106 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE) 107 return -EINVAL; 108 109 md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET]; 110 link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET]; 111 112 rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len); 113 if (rc != 1) 114 return -EINVAL; 115 116 rc = symlink_hash(link_len, link_str, md5_hash); 117 if (rc) { 118 cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc); 119 return rc; 120 } 121 122 snprintf(md5_str2, sizeof(md5_str2), 123 CIFS_MF_SYMLINK_MD5_FORMAT, 124 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); 125 126 if (strncmp(md5_str1, md5_str2, 17) != 0) 127 return -EINVAL; 128 129 if (_link_str) { 130 *_link_str = kstrndup(link_str, link_len, GFP_KERNEL); 131 if (!*_link_str) 132 return -ENOMEM; 133 } 134 135 *_link_len = link_len; 136 return 0; 137} 138 139static int 140CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str) 141{ 142 int rc; 143 unsigned int link_len; 144 unsigned int ofs; 145 u8 md5_hash[16]; 146 147 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE) 148 return -EINVAL; 149 150 link_len = strlen(link_str); 151 152 if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN) 153 return -ENAMETOOLONG; 154 155 rc = symlink_hash(link_len, link_str, md5_hash); 156 if (rc) { 157 cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc); 158 return rc; 159 } 160 161 snprintf(buf, buf_len, 162 CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT, 163 link_len, 164 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); 165 166 ofs = CIFS_MF_SYMLINK_LINK_OFFSET; 167 memcpy(buf + ofs, link_str, link_len); 168 169 ofs += link_len; 170 if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) { 171 buf[ofs] = '\n'; 172 ofs++; 173 } 174 175 while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) { 176 buf[ofs] = ' '; 177 ofs++; 178 } 179 180 return 0; 181} 182 183static int 184CIFSCreateMFSymLink(const unsigned int xid, struct cifs_tcon *tcon, 185 const char *fromName, const char *toName, 186 struct cifs_sb_info *cifs_sb) 187{ 188 int rc; 189 int oplock = 0; 190 int remap; 191 int create_options = CREATE_NOT_DIR; 192 __u16 netfid = 0; 193 u8 *buf; 194 unsigned int bytes_written = 0; 195 struct cifs_io_parms io_parms; 196 struct nls_table *nls_codepage; 197 198 nls_codepage = cifs_sb->local_nls; 199 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; 200 201 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); 202 if (!buf) 203 return -ENOMEM; 204 205 rc = CIFSFormatMFSymlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName); 206 if (rc != 0) { 207 kfree(buf); 208 return rc; 209 } 210 211 if (backup_cred(cifs_sb)) 212 create_options |= CREATE_OPEN_BACKUP_INTENT; 213 214 rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE, 215 create_options, &netfid, &oplock, NULL, 216 nls_codepage, remap); 217 if (rc != 0) { 218 kfree(buf); 219 return rc; 220 } 221 222 io_parms.netfid = netfid; 223 io_parms.pid = current->tgid; 224 io_parms.tcon = tcon; 225 io_parms.offset = 0; 226 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 227 228 rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, buf, NULL, 0); 229 CIFSSMBClose(xid, tcon, netfid); 230 kfree(buf); 231 if (rc != 0) 232 return rc; 233 234 if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE) 235 return -EIO; 236 237 return 0; 238} 239 240static int 241CIFSQueryMFSymLink(const unsigned int xid, struct cifs_tcon *tcon, 242 const unsigned char *searchName, char **symlinkinfo, 243 const struct nls_table *nls_codepage, int remap) 244{ 245 int rc; 246 int oplock = 0; 247 __u16 netfid = 0; 248 u8 *buf; 249 char *pbuf; 250 unsigned int bytes_read = 0; 251 int buf_type = CIFS_NO_BUFFER; 252 unsigned int link_len = 0; 253 struct cifs_io_parms io_parms; 254 FILE_ALL_INFO file_info; 255 256 rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ, 257 CREATE_NOT_DIR, &netfid, &oplock, &file_info, 258 nls_codepage, remap); 259 if (rc != 0) 260 return rc; 261 262 if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { 263 CIFSSMBClose(xid, tcon, netfid); 264 /* it's not a symlink */ 265 return -EINVAL; 266 } 267 268 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); 269 if (!buf) 270 return -ENOMEM; 271 pbuf = buf; 272 io_parms.netfid = netfid; 273 io_parms.pid = current->tgid; 274 io_parms.tcon = tcon; 275 io_parms.offset = 0; 276 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 277 278 rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); 279 CIFSSMBClose(xid, tcon, netfid); 280 if (rc != 0) { 281 kfree(buf); 282 return rc; 283 } 284 285 rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, symlinkinfo); 286 kfree(buf); 287 if (rc != 0) 288 return rc; 289 290 return 0; 291} 292 293bool 294CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr) 295{ 296 if (!(fattr->cf_mode & S_IFREG)) 297 /* it's not a symlink */ 298 return false; 299 300 if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE) 301 /* it's not a symlink */ 302 return false; 303 304 return true; 305} 306 307int 308CIFSCheckMFSymlink(struct cifs_fattr *fattr, 309 const unsigned char *path, 310 struct cifs_sb_info *cifs_sb, unsigned int xid) 311{ 312 int rc; 313 int oplock = 0; 314 __u16 netfid = 0; 315 struct tcon_link *tlink; 316 struct cifs_tcon *pTcon; 317 struct cifs_io_parms io_parms; 318 u8 *buf; 319 char *pbuf; 320 unsigned int bytes_read = 0; 321 int buf_type = CIFS_NO_BUFFER; 322 unsigned int link_len = 0; 323 FILE_ALL_INFO file_info; 324 325 if (!CIFSCouldBeMFSymlink(fattr)) 326 /* it's not a symlink */ 327 return 0; 328 329 tlink = cifs_sb_tlink(cifs_sb); 330 if (IS_ERR(tlink)) 331 return PTR_ERR(tlink); 332 pTcon = tlink_tcon(tlink); 333 334 rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, 335 CREATE_NOT_DIR, &netfid, &oplock, &file_info, 336 cifs_sb->local_nls, 337 cifs_sb->mnt_cifs_flags & 338 CIFS_MOUNT_MAP_SPECIAL_CHR); 339 if (rc != 0) 340 goto out; 341 342 if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { 343 CIFSSMBClose(xid, pTcon, netfid); 344 /* it's not a symlink */ 345 goto out; 346 } 347 348 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); 349 if (!buf) { 350 rc = -ENOMEM; 351 goto out; 352 } 353 pbuf = buf; 354 io_parms.netfid = netfid; 355 io_parms.pid = current->tgid; 356 io_parms.tcon = pTcon; 357 io_parms.offset = 0; 358 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 359 360 rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); 361 CIFSSMBClose(xid, pTcon, netfid); 362 if (rc != 0) { 363 kfree(buf); 364 goto out; 365 } 366 367 rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL); 368 kfree(buf); 369 if (rc == -EINVAL) { 370 /* it's not a symlink */ 371 rc = 0; 372 goto out; 373 } 374 375 if (rc != 0) 376 goto out; 377 378 /* it is a symlink */ 379 fattr->cf_eof = link_len; 380 fattr->cf_mode &= ~S_IFMT; 381 fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; 382 fattr->cf_dtype = DT_LNK; 383out: 384 cifs_put_tlink(tlink); 385 return rc; 386} 387 388int 389cifs_hardlink(struct dentry *old_file, struct inode *inode, 390 struct dentry *direntry) 391{ 392 int rc = -EACCES; 393 unsigned int xid; 394 char *from_name = NULL; 395 char *to_name = NULL; 396 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 397 struct tcon_link *tlink; 398 struct cifs_tcon *tcon; 399 struct TCP_Server_Info *server; 400 struct cifsInodeInfo *cifsInode; 401 402 tlink = cifs_sb_tlink(cifs_sb); 403 if (IS_ERR(tlink)) 404 return PTR_ERR(tlink); 405 tcon = tlink_tcon(tlink); 406 407 xid = get_xid(); 408 409 from_name = build_path_from_dentry(old_file); 410 to_name = build_path_from_dentry(direntry); 411 if ((from_name == NULL) || (to_name == NULL)) { 412 rc = -ENOMEM; 413 goto cifs_hl_exit; 414 } 415 416 if (tcon->unix_ext) 417 rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name, 418 cifs_sb->local_nls, 419 cifs_sb->mnt_cifs_flags & 420 CIFS_MOUNT_MAP_SPECIAL_CHR); 421 else { 422 server = tcon->ses->server; 423 if (!server->ops->create_hardlink) 424 return -ENOSYS; 425 rc = server->ops->create_hardlink(xid, tcon, from_name, to_name, 426 cifs_sb); 427 if ((rc == -EIO) || (rc == -EINVAL)) 428 rc = -EOPNOTSUPP; 429 } 430 431 d_drop(direntry); /* force new lookup from server of target */ 432 433 /* 434 * if source file is cached (oplocked) revalidate will not go to server 435 * until the file is closed or oplock broken so update nlinks locally 436 */ 437 if (old_file->d_inode) { 438 cifsInode = CIFS_I(old_file->d_inode); 439 if (rc == 0) { 440 spin_lock(&old_file->d_inode->i_lock); 441 inc_nlink(old_file->d_inode); 442 spin_unlock(&old_file->d_inode->i_lock); 443 /* 444 * BB should we make this contingent on superblock flag 445 * NOATIME? 446 */ 447 /* old_file->d_inode->i_ctime = CURRENT_TIME; */ 448 /* 449 * parent dir timestamps will update from srv within a 450 * second, would it really be worth it to set the parent 451 * dir cifs inode time to zero to force revalidate 452 * (faster) for it too? 453 */ 454 } 455 /* 456 * if not oplocked will force revalidate to get info on source 457 * file from srv 458 */ 459 cifsInode->time = 0; 460 461 /* 462 * Will update parent dir timestamps from srv within a second. 463 * Would it really be worth it to set the parent dir (cifs 464 * inode) time field to zero to force revalidate on parent 465 * directory faster ie 466 * 467 * CIFS_I(inode)->time = 0; 468 */ 469 } 470 471cifs_hl_exit: 472 kfree(from_name); 473 kfree(to_name); 474 free_xid(xid); 475 cifs_put_tlink(tlink); 476 return rc; 477} 478 479void * 480cifs_follow_link(struct dentry *direntry, struct nameidata *nd) 481{ 482 struct inode *inode = direntry->d_inode; 483 int rc = -ENOMEM; 484 unsigned int xid; 485 char *full_path = NULL; 486 char *target_path = NULL; 487 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 488 struct tcon_link *tlink = NULL; 489 struct cifs_tcon *tcon; 490 491 xid = get_xid(); 492 493 tlink = cifs_sb_tlink(cifs_sb); 494 if (IS_ERR(tlink)) { 495 rc = PTR_ERR(tlink); 496 tlink = NULL; 497 goto out; 498 } 499 tcon = tlink_tcon(tlink); 500 501 /* 502 * For now, we just handle symlinks with unix extensions enabled. 503 * Eventually we should handle NTFS reparse points, and MacOS 504 * symlink support. For instance... 505 * 506 * rc = CIFSSMBQueryReparseLinkInfo(...) 507 * 508 * For now, just return -EACCES when the server doesn't support posix 509 * extensions. Note that we still allow querying symlinks when posix 510 * extensions are manually disabled. We could disable these as well 511 * but there doesn't seem to be any harm in allowing the client to 512 * read them. 513 */ 514 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && 515 !cap_unix(tcon->ses)) { 516 rc = -EACCES; 517 goto out; 518 } 519 520 full_path = build_path_from_dentry(direntry); 521 if (!full_path) 522 goto out; 523 524 cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode); 525 526 rc = -EACCES; 527 /* 528 * First try Minshall+French Symlinks, if configured 529 * and fallback to UNIX Extensions Symlinks. 530 */ 531 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) 532 rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path, 533 cifs_sb->local_nls, 534 cifs_sb->mnt_cifs_flags & 535 CIFS_MOUNT_MAP_SPECIAL_CHR); 536 537 if ((rc != 0) && cap_unix(tcon->ses)) 538 rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, 539 cifs_sb->local_nls); 540 541 kfree(full_path); 542out: 543 if (rc != 0) { 544 kfree(target_path); 545 target_path = ERR_PTR(rc); 546 } 547 548 free_xid(xid); 549 if (tlink) 550 cifs_put_tlink(tlink); 551 nd_set_link(nd, target_path); 552 return NULL; 553} 554 555int 556cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) 557{ 558 int rc = -EOPNOTSUPP; 559 unsigned int xid; 560 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 561 struct tcon_link *tlink; 562 struct cifs_tcon *pTcon; 563 char *full_path = NULL; 564 struct inode *newinode = NULL; 565 566 xid = get_xid(); 567 568 tlink = cifs_sb_tlink(cifs_sb); 569 if (IS_ERR(tlink)) { 570 rc = PTR_ERR(tlink); 571 goto symlink_exit; 572 } 573 pTcon = tlink_tcon(tlink); 574 575 full_path = build_path_from_dentry(direntry); 576 if (full_path == NULL) { 577 rc = -ENOMEM; 578 goto symlink_exit; 579 } 580 581 cifs_dbg(FYI, "Full path: %s\n", full_path); 582 cifs_dbg(FYI, "symname is %s\n", symname); 583 584 /* BB what if DFS and this volume is on different share? BB */ 585 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) 586 rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname, 587 cifs_sb); 588 else if (pTcon->unix_ext) 589 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, 590 cifs_sb->local_nls); 591 /* else 592 rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName, 593 cifs_sb_target->local_nls); */ 594 595 if (rc == 0) { 596 if (pTcon->unix_ext) 597 rc = cifs_get_inode_info_unix(&newinode, full_path, 598 inode->i_sb, xid); 599 else 600 rc = cifs_get_inode_info(&newinode, full_path, NULL, 601 inode->i_sb, xid, NULL); 602 603 if (rc != 0) { 604 cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n", 605 rc); 606 } else { 607 d_instantiate(direntry, newinode); 608 } 609 } 610symlink_exit: 611 kfree(full_path); 612 cifs_put_tlink(tlink); 613 free_xid(xid); 614 return rc; 615} 616 617void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie) 618{ 619 char *p = nd_get_link(nd); 620 if (!IS_ERR(p)) 621 kfree(p); 622}