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