at v3.12 630 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 308open_query_close_cifs_symlink(const unsigned char *path, char *pbuf, 309 unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb, 310 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 int buf_type = CIFS_NO_BUFFER; 319 FILE_ALL_INFO file_info; 320 321 tlink = cifs_sb_tlink(cifs_sb); 322 if (IS_ERR(tlink)) 323 return PTR_ERR(tlink); 324 ptcon = tlink_tcon(tlink); 325 326 rc = CIFSSMBOpen(xid, ptcon, path, FILE_OPEN, GENERIC_READ, 327 CREATE_NOT_DIR, &netfid, &oplock, &file_info, 328 cifs_sb->local_nls, 329 cifs_sb->mnt_cifs_flags & 330 CIFS_MOUNT_MAP_SPECIAL_CHR); 331 if (rc != 0) { 332 cifs_put_tlink(tlink); 333 return rc; 334 } 335 336 if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { 337 CIFSSMBClose(xid, ptcon, netfid); 338 cifs_put_tlink(tlink); 339 /* it's not a symlink */ 340 return rc; 341 } 342 343 io_parms.netfid = netfid; 344 io_parms.pid = current->tgid; 345 io_parms.tcon = ptcon; 346 io_parms.offset = 0; 347 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 348 349 rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type); 350 CIFSSMBClose(xid, ptcon, netfid); 351 cifs_put_tlink(tlink); 352 return rc; 353} 354 355 356int 357CIFSCheckMFSymlink(struct cifs_fattr *fattr, 358 const unsigned char *path, 359 struct cifs_sb_info *cifs_sb, unsigned int xid) 360{ 361 int rc = 0; 362 u8 *buf = NULL; 363 unsigned int link_len = 0; 364 unsigned int bytes_read = 0; 365 struct cifs_tcon *ptcon; 366 367 if (!CIFSCouldBeMFSymlink(fattr)) 368 /* it's not a symlink */ 369 return 0; 370 371 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); 372 if (!buf) { 373 rc = -ENOMEM; 374 goto out; 375 } 376 377 ptcon = tlink_tcon(cifs_sb_tlink(cifs_sb)); 378 if ((ptcon->ses) && (ptcon->ses->server->ops->query_mf_symlink)) 379 rc = ptcon->ses->server->ops->query_mf_symlink(path, buf, 380 &bytes_read, cifs_sb, xid); 381 else 382 goto out; 383 384 if (rc != 0) 385 goto out; 386 387 if (bytes_read == 0) /* not a symlink */ 388 goto out; 389 390 rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL); 391 if (rc == -EINVAL) { 392 /* it's not a symlink */ 393 rc = 0; 394 goto out; 395 } 396 397 if (rc != 0) 398 goto out; 399 400 /* it is a symlink */ 401 fattr->cf_eof = link_len; 402 fattr->cf_mode &= ~S_IFMT; 403 fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; 404 fattr->cf_dtype = DT_LNK; 405out: 406 kfree(buf); 407 return rc; 408} 409 410int 411cifs_hardlink(struct dentry *old_file, struct inode *inode, 412 struct dentry *direntry) 413{ 414 int rc = -EACCES; 415 unsigned int xid; 416 char *from_name = NULL; 417 char *to_name = NULL; 418 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 419 struct tcon_link *tlink; 420 struct cifs_tcon *tcon; 421 struct TCP_Server_Info *server; 422 struct cifsInodeInfo *cifsInode; 423 424 tlink = cifs_sb_tlink(cifs_sb); 425 if (IS_ERR(tlink)) 426 return PTR_ERR(tlink); 427 tcon = tlink_tcon(tlink); 428 429 xid = get_xid(); 430 431 from_name = build_path_from_dentry(old_file); 432 to_name = build_path_from_dentry(direntry); 433 if ((from_name == NULL) || (to_name == NULL)) { 434 rc = -ENOMEM; 435 goto cifs_hl_exit; 436 } 437 438 if (tcon->unix_ext) 439 rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name, 440 cifs_sb->local_nls, 441 cifs_sb->mnt_cifs_flags & 442 CIFS_MOUNT_MAP_SPECIAL_CHR); 443 else { 444 server = tcon->ses->server; 445 if (!server->ops->create_hardlink) 446 return -ENOSYS; 447 rc = server->ops->create_hardlink(xid, tcon, from_name, to_name, 448 cifs_sb); 449 if ((rc == -EIO) || (rc == -EINVAL)) 450 rc = -EOPNOTSUPP; 451 } 452 453 d_drop(direntry); /* force new lookup from server of target */ 454 455 /* 456 * if source file is cached (oplocked) revalidate will not go to server 457 * until the file is closed or oplock broken so update nlinks locally 458 */ 459 if (old_file->d_inode) { 460 cifsInode = CIFS_I(old_file->d_inode); 461 if (rc == 0) { 462 spin_lock(&old_file->d_inode->i_lock); 463 inc_nlink(old_file->d_inode); 464 spin_unlock(&old_file->d_inode->i_lock); 465 /* 466 * BB should we make this contingent on superblock flag 467 * NOATIME? 468 */ 469 /* old_file->d_inode->i_ctime = CURRENT_TIME; */ 470 /* 471 * parent dir timestamps will update from srv within a 472 * second, would it really be worth it to set the parent 473 * dir cifs inode time to zero to force revalidate 474 * (faster) for it too? 475 */ 476 } 477 /* 478 * if not oplocked will force revalidate to get info on source 479 * file from srv 480 */ 481 cifsInode->time = 0; 482 483 /* 484 * Will update parent dir timestamps from srv within a second. 485 * Would it really be worth it to set the parent dir (cifs 486 * inode) time field to zero to force revalidate on parent 487 * directory faster ie 488 * 489 * CIFS_I(inode)->time = 0; 490 */ 491 } 492 493cifs_hl_exit: 494 kfree(from_name); 495 kfree(to_name); 496 free_xid(xid); 497 cifs_put_tlink(tlink); 498 return rc; 499} 500 501void * 502cifs_follow_link(struct dentry *direntry, struct nameidata *nd) 503{ 504 struct inode *inode = direntry->d_inode; 505 int rc = -ENOMEM; 506 unsigned int xid; 507 char *full_path = NULL; 508 char *target_path = NULL; 509 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 510 struct tcon_link *tlink = NULL; 511 struct cifs_tcon *tcon; 512 struct TCP_Server_Info *server; 513 514 xid = get_xid(); 515 516 tlink = cifs_sb_tlink(cifs_sb); 517 if (IS_ERR(tlink)) { 518 rc = PTR_ERR(tlink); 519 tlink = NULL; 520 goto out; 521 } 522 tcon = tlink_tcon(tlink); 523 server = tcon->ses->server; 524 525 full_path = build_path_from_dentry(direntry); 526 if (!full_path) 527 goto out; 528 529 cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode); 530 531 rc = -EACCES; 532 /* 533 * First try Minshall+French Symlinks, if configured 534 * and fallback to UNIX Extensions Symlinks. 535 */ 536 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) 537 rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path, 538 cifs_sb->local_nls, 539 cifs_sb->mnt_cifs_flags & 540 CIFS_MOUNT_MAP_SPECIAL_CHR); 541 542 if ((rc != 0) && cap_unix(tcon->ses)) 543 rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, 544 cifs_sb->local_nls); 545 else if (rc != 0 && server->ops->query_symlink) 546 rc = server->ops->query_symlink(xid, tcon, full_path, 547 &target_path, cifs_sb); 548 549 kfree(full_path); 550out: 551 if (rc != 0) { 552 kfree(target_path); 553 target_path = ERR_PTR(rc); 554 } 555 556 free_xid(xid); 557 if (tlink) 558 cifs_put_tlink(tlink); 559 nd_set_link(nd, target_path); 560 return NULL; 561} 562 563int 564cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) 565{ 566 int rc = -EOPNOTSUPP; 567 unsigned int xid; 568 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 569 struct tcon_link *tlink; 570 struct cifs_tcon *pTcon; 571 char *full_path = NULL; 572 struct inode *newinode = NULL; 573 574 xid = get_xid(); 575 576 tlink = cifs_sb_tlink(cifs_sb); 577 if (IS_ERR(tlink)) { 578 rc = PTR_ERR(tlink); 579 goto symlink_exit; 580 } 581 pTcon = tlink_tcon(tlink); 582 583 full_path = build_path_from_dentry(direntry); 584 if (full_path == NULL) { 585 rc = -ENOMEM; 586 goto symlink_exit; 587 } 588 589 cifs_dbg(FYI, "Full path: %s\n", full_path); 590 cifs_dbg(FYI, "symname is %s\n", symname); 591 592 /* BB what if DFS and this volume is on different share? BB */ 593 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) 594 rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname, 595 cifs_sb); 596 else if (pTcon->unix_ext) 597 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, 598 cifs_sb->local_nls); 599 /* else 600 rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName, 601 cifs_sb_target->local_nls); */ 602 603 if (rc == 0) { 604 if (pTcon->unix_ext) 605 rc = cifs_get_inode_info_unix(&newinode, full_path, 606 inode->i_sb, xid); 607 else 608 rc = cifs_get_inode_info(&newinode, full_path, NULL, 609 inode->i_sb, xid, NULL); 610 611 if (rc != 0) { 612 cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n", 613 rc); 614 } else { 615 d_instantiate(direntry, newinode); 616 } 617 } 618symlink_exit: 619 kfree(full_path); 620 cifs_put_tlink(tlink); 621 free_xid(xid); 622 return rc; 623} 624 625void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie) 626{ 627 char *p = nd_get_link(nd); 628 if (!IS_ERR(p)) 629 kfree(p); 630}