1 // SPDX-License-Identifier: LGPL-2.1 2 /* 3 * 4 * vfs operations that deal with io control 5 * 6 * Copyright (C) International Business Machines Corp., 2005,2013 7 * Author(s): Steve French (sfrench@us.ibm.com) 8 * 9 */ 10 11 #include <linux/fs.h> 12 #include <linux/file.h> 13 #include <linux/mount.h> 14 #include <linux/mm.h> 15 #include <linux/pagemap.h> 16 #include "cifsglob.h" 17 #include "cifsproto.h" 18 #include "cifs_debug.h" 19 #include "cifsfs.h" 20 #include "cifs_ioctl.h" 21 #include "smb2proto.h" 22 #include "smb2glob.h" 23 #include <linux/btrfs.h> 24 25 static long cifs_ioctl_query_info(unsigned int xid, struct file *filep, 26 unsigned long p) 27 { 28 struct inode *inode = file_inode(filep); 29 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 30 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 31 struct dentry *dentry = filep->f_path.dentry; 32 const unsigned char *path; 33 void *page = alloc_dentry_path(); 34 __le16 *utf16_path = NULL, root_path; 35 int rc = 0; 36 37 path = build_path_from_dentry(dentry, page); 38 if (IS_ERR(path)) { 39 free_dentry_path(page); 40 return PTR_ERR(path); 41 } 42 43 cifs_dbg(FYI, "%s %s\n", __func__, path); 44 45 if (!path[0]) { 46 root_path = 0; 47 utf16_path = &root_path; 48 } else { 49 utf16_path = cifs_convert_path_to_utf16(path + 1, cifs_sb); 50 if (!utf16_path) { 51 rc = -ENOMEM; 52 goto ici_exit; 53 } 54 } 55 56 if (tcon->ses->server->ops->ioctl_query_info) 57 rc = tcon->ses->server->ops->ioctl_query_info( 58 xid, tcon, cifs_sb, utf16_path, 59 filep->private_data ? 0 : 1, p); 60 else 61 rc = -EOPNOTSUPP; 62 63 ici_exit: 64 if (utf16_path != &root_path) 65 kfree(utf16_path); 66 free_dentry_path(page); 67 return rc; 68 } 69 70 static int cifs_set_compression_by_path(unsigned int xid, struct file *filep, 71 struct cifs_tcon *tcon, 72 __u16 compression_state) 73 { 74 struct inode *inode = file_inode(filep); 75 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 76 struct TCP_Server_Info *server = tcon->ses->server; 77 struct cifs_open_parms oparms; 78 struct cifs_open_info_data data = {}; 79 struct cifsFileInfo *tmp_cfile = NULL; 80 struct cifs_fid fid = {}; 81 const char *full_path; 82 __u32 oplock = 0; 83 u64 uniqueid; 84 void *page; 85 int rc; 86 87 if (!server->ops->open || !server->ops->close || 88 !server->ops->query_file_info) 89 return -EOPNOTSUPP; 90 91 if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM) || 92 cifs_sb->mnt_cifs_serverino_autodisabled) 93 return -EOPNOTSUPP; 94 95 if (d_unhashed(filep->f_path.dentry)) 96 return -ESTALE; 97 98 page = alloc_dentry_path(); 99 full_path = build_path_from_dentry(filep->f_path.dentry, page); 100 if (IS_ERR(full_path)) { 101 free_dentry_path(page); 102 return PTR_ERR(full_path); 103 } 104 105 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA | 106 FILE_READ_ATTRIBUTES, 107 FILE_OPEN, 0, ACL_NO_MODE); 108 oparms.fid = &fid; 109 110 rc = server->ops->open(xid, &oparms, &oplock, NULL); 111 if (rc) 112 goto out; 113 114 tmp_cfile = kzalloc_obj(*tmp_cfile); 115 if (!tmp_cfile) { 116 rc = -ENOMEM; 117 goto close; 118 } 119 120 tmp_cfile->fid = fid; 121 rc = server->ops->query_file_info(xid, tcon, tmp_cfile, &data); 122 if (rc) 123 goto close; 124 125 uniqueid = le64_to_cpu(data.fi.IndexNumber); 126 if (uniqueid != CIFS_I(inode)->uniqueid) { 127 rc = -ESTALE; 128 goto close; 129 } 130 131 rc = server->ops->set_compression(xid, tcon, tmp_cfile, 132 compression_state); 133 134 close: 135 server->ops->close(xid, tcon, &fid); 136 if (tmp_cfile) 137 kfree(tmp_cfile); 138 cifs_free_open_info(&data); 139 out: 140 free_dentry_path(page); 141 return rc; 142 } 143 144 static int cifs_ioctl_set_compression(unsigned int xid, struct file *filep, 145 struct cifs_tcon *tcon, 146 struct cifsFileInfo *cfile, 147 __u16 compression_state) 148 { 149 struct cifsFileInfo *wfile; 150 struct cifs_tcon *wtcon; 151 struct inode *inode = file_inode(filep); 152 int rc; 153 154 if (!tcon->ses->server->ops->set_compression) 155 return -EOPNOTSUPP; 156 157 if (cfile && (cfile->fid.access & FILE_WRITE_DATA)) { 158 rc = tcon->ses->server->ops->set_compression(xid, tcon, cfile, 159 compression_state); 160 if (rc != -EACCES) 161 return rc; 162 } 163 164 rc = cifs_get_writable_file(CIFS_I(inode), FIND_FSUID_ONLY, &wfile); 165 if (!rc) { 166 wtcon = tlink_tcon(wfile->tlink); 167 rc = wtcon->ses->server->ops->set_compression(xid, wtcon, wfile, 168 compression_state); 169 cifsFileInfo_put(wfile); 170 if (rc != -EACCES) 171 return rc; 172 } else if (rc != -EBADF) { 173 return rc; 174 } 175 176 return cifs_set_compression_by_path(xid, filep, tcon, 177 compression_state); 178 } 179 180 static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file, 181 unsigned long srcfd) 182 { 183 int rc; 184 struct inode *src_inode; 185 186 cifs_dbg(FYI, "ioctl copychunk range\n"); 187 /* the destination must be opened for writing */ 188 if (!(dst_file->f_mode & FMODE_WRITE)) { 189 cifs_dbg(FYI, "file target not open for write\n"); 190 return -EINVAL; 191 } 192 193 /* check if target volume is readonly and take reference */ 194 rc = mnt_want_write_file(dst_file); 195 if (rc) { 196 cifs_dbg(FYI, "mnt_want_write failed with rc %d\n", rc); 197 return rc; 198 } 199 200 CLASS(fd, src_file)(srcfd); 201 if (fd_empty(src_file)) { 202 rc = -EBADF; 203 goto out_drop_write; 204 } 205 206 if (fd_file(src_file)->f_op->unlocked_ioctl != cifs_ioctl) { 207 rc = -EBADF; 208 cifs_dbg(VFS, "src file seems to be from a different filesystem type\n"); 209 goto out_drop_write; 210 } 211 212 src_inode = file_inode(fd_file(src_file)); 213 rc = -EINVAL; 214 if (S_ISDIR(src_inode->i_mode)) 215 goto out_drop_write; 216 217 rc = cifs_file_copychunk_range(xid, fd_file(src_file), 0, dst_file, 0, 218 src_inode->i_size, 0); 219 if (rc > 0) 220 rc = 0; 221 out_drop_write: 222 mnt_drop_write_file(dst_file); 223 return rc; 224 } 225 226 static long smb_mnt_get_tcon_info(struct cifs_tcon *tcon, void __user *arg) 227 { 228 int rc = 0; 229 struct smb_mnt_tcon_info tcon_inf; 230 231 tcon_inf.tid = tcon->tid; 232 tcon_inf.session_id = tcon->ses->Suid; 233 234 if (copy_to_user(arg, &tcon_inf, sizeof(struct smb_mnt_tcon_info))) 235 rc = -EFAULT; 236 237 return rc; 238 } 239 240 static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon, 241 void __user *arg) 242 { 243 int rc = 0; 244 struct smb_mnt_fs_info *fsinf; 245 246 fsinf = kzalloc_obj(struct smb_mnt_fs_info); 247 if (fsinf == NULL) 248 return -ENOMEM; 249 250 fsinf->version = 1; 251 fsinf->protocol_id = tcon->ses->server->vals->protocol_id; 252 fsinf->tcon_flags = tcon->Flags; 253 fsinf->device_characteristics = 254 le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics); 255 fsinf->device_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); 256 fsinf->fs_attributes = le32_to_cpu(tcon->fsAttrInfo.Attributes); 257 fsinf->max_path_component = 258 le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength); 259 fsinf->vol_serial_number = tcon->vol_serial_number; 260 fsinf->vol_create_time = le64_to_cpu(tcon->vol_create_time); 261 fsinf->share_flags = tcon->share_flags; 262 fsinf->share_caps = le32_to_cpu(tcon->capabilities); 263 fsinf->sector_flags = tcon->ss_flags; 264 fsinf->optimal_sector_size = tcon->perf_sector_size; 265 fsinf->max_bytes_chunk = tcon->max_bytes_chunk; 266 fsinf->maximal_access = tcon->maximal_access; 267 fsinf->cifs_posix_caps = le64_to_cpu(tcon->fsUnixInfo.Capability); 268 269 if (copy_to_user(arg, fsinf, sizeof(struct smb_mnt_fs_info))) 270 rc = -EFAULT; 271 272 kfree(fsinf); 273 return rc; 274 } 275 276 static int cifs_shutdown(struct super_block *sb, unsigned long arg) 277 { 278 struct cifs_sb_info *sbi = CIFS_SB(sb); 279 struct tcon_link *tlink; 280 struct cifs_tcon *tcon; 281 __u32 flags; 282 int rc; 283 284 if (!capable(CAP_SYS_ADMIN)) 285 return -EPERM; 286 287 if (get_user(flags, (__u32 __user *)arg)) 288 return -EFAULT; 289 290 tlink = cifs_sb_tlink(sbi); 291 if (IS_ERR(tlink)) 292 return PTR_ERR(tlink); 293 tcon = tlink_tcon(tlink); 294 295 trace_smb3_shutdown_enter(flags, tcon->tid); 296 if (flags > CIFS_GOING_FLAGS_NOLOGFLUSH) { 297 rc = -EINVAL; 298 goto shutdown_out_err; 299 } 300 301 if (cifs_forced_shutdown(sbi)) 302 goto shutdown_good; 303 304 cifs_dbg(VFS, "shut down requested (%d)", flags); 305 306 /* 307 * see: 308 * https://man7.org/linux/man-pages/man2/ioctl_xfs_goingdown.2.html 309 * for more information and description of original intent of the flags 310 */ 311 switch (flags) { 312 /* 313 * We could add support later for default flag which requires: 314 * "Flush all dirty data and metadata to disk" 315 * would need to call syncfs or equivalent to flush page cache for 316 * the mount and then issue fsync to server (if nostrictsync not set) 317 */ 318 case CIFS_GOING_FLAGS_DEFAULT: 319 cifs_dbg(FYI, "shutdown with default flag not supported\n"); 320 rc = -EINVAL; 321 goto shutdown_out_err; 322 /* 323 * FLAGS_LOGFLUSH is easy since it asks to write out metadata (not 324 * data) but metadata writes are not cached on the client, so can treat 325 * it similarly to NOLOGFLUSH 326 */ 327 case CIFS_GOING_FLAGS_LOGFLUSH: 328 case CIFS_GOING_FLAGS_NOLOGFLUSH: 329 atomic_or(CIFS_MOUNT_SHUTDOWN, &sbi->mnt_cifs_flags); 330 goto shutdown_good; 331 default: 332 rc = -EINVAL; 333 goto shutdown_out_err; 334 } 335 336 shutdown_good: 337 trace_smb3_shutdown_done(flags, tcon->tid); 338 cifs_put_tlink(tlink); 339 return 0; 340 shutdown_out_err: 341 trace_smb3_shutdown_err(rc, flags, tcon->tid); 342 cifs_put_tlink(tlink); 343 return rc; 344 } 345 346 static int cifs_dump_full_key(struct cifs_tcon *tcon, struct smb3_full_key_debug_info __user *in) 347 { 348 struct smb3_full_key_debug_info out; 349 struct cifs_ses *ses; 350 int rc = 0; 351 bool found = false; 352 u8 __user *end; 353 354 if (!smb3_encryption_required(tcon)) { 355 rc = -EOPNOTSUPP; 356 goto out; 357 } 358 359 /* copy user input into our output buffer */ 360 if (copy_from_user(&out, in, sizeof(out))) { 361 rc = -EINVAL; 362 goto out; 363 } 364 365 if (!out.session_id) { 366 /* if ses id is 0, use current user session */ 367 ses = tcon->ses; 368 } else { 369 /* otherwise if a session id is given, look for it in all our sessions */ 370 struct cifs_ses *ses_it = NULL; 371 struct TCP_Server_Info *server_it = NULL; 372 373 spin_lock(&cifs_tcp_ses_lock); 374 list_for_each_entry(server_it, &cifs_tcp_ses_list, tcp_ses_list) { 375 list_for_each_entry(ses_it, &server_it->smb_ses_list, smb_ses_list) { 376 spin_lock(&ses_it->ses_lock); 377 if (ses_it->ses_status != SES_EXITING && 378 ses_it->Suid == out.session_id) { 379 ses = ses_it; 380 /* 381 * since we are using the session outside the crit 382 * section, we need to make sure it won't be released 383 * so increment its refcount 384 */ 385 cifs_smb_ses_inc_refcount(ses); 386 spin_unlock(&ses_it->ses_lock); 387 found = true; 388 goto search_end; 389 } 390 spin_unlock(&ses_it->ses_lock); 391 } 392 } 393 search_end: 394 spin_unlock(&cifs_tcp_ses_lock); 395 if (!found) { 396 rc = -ENOENT; 397 goto out; 398 } 399 } 400 401 switch (ses->server->cipher_type) { 402 case SMB2_ENCRYPTION_AES128_CCM: 403 case SMB2_ENCRYPTION_AES128_GCM: 404 out.session_key_length = CIFS_SESS_KEY_SIZE; 405 out.server_in_key_length = out.server_out_key_length = SMB3_GCM128_CRYPTKEY_SIZE; 406 break; 407 case SMB2_ENCRYPTION_AES256_CCM: 408 case SMB2_ENCRYPTION_AES256_GCM: 409 out.session_key_length = ses->auth_key.len; 410 out.server_in_key_length = out.server_out_key_length = SMB3_GCM256_CRYPTKEY_SIZE; 411 break; 412 default: 413 rc = -EOPNOTSUPP; 414 goto out; 415 } 416 417 /* check if user buffer is big enough to store all the keys */ 418 if (out.in_size < sizeof(out) + out.session_key_length + out.server_in_key_length 419 + out.server_out_key_length) { 420 rc = -ENOBUFS; 421 goto out; 422 } 423 424 out.session_id = ses->Suid; 425 out.cipher_type = le16_to_cpu(ses->server->cipher_type); 426 427 /* overwrite user input with our output */ 428 if (copy_to_user(in, &out, sizeof(out))) { 429 rc = -EINVAL; 430 goto out; 431 } 432 433 /* append all the keys at the end of the user buffer */ 434 end = in->data; 435 if (copy_to_user(end, ses->auth_key.response, out.session_key_length)) { 436 rc = -EINVAL; 437 goto out; 438 } 439 end += out.session_key_length; 440 441 if (copy_to_user(end, ses->smb3encryptionkey, out.server_in_key_length)) { 442 rc = -EINVAL; 443 goto out; 444 } 445 end += out.server_in_key_length; 446 447 if (copy_to_user(end, ses->smb3decryptionkey, out.server_out_key_length)) { 448 rc = -EINVAL; 449 goto out; 450 } 451 452 out: 453 if (found) 454 cifs_put_smb_ses(ses); 455 return rc; 456 } 457 458 long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) 459 { 460 struct inode *inode = file_inode(filep); 461 struct smb3_key_debug_info pkey_inf; 462 int rc = -ENOTTY; /* strange error - but the precedent */ 463 unsigned int xid; 464 struct cifsFileInfo *pSMBFile = filep->private_data; 465 struct cifs_tcon *tcon; 466 struct tcon_link *tlink; 467 struct cifs_sb_info *cifs_sb; 468 __u64 ExtAttrBits = 0; 469 bool enable_compression; 470 __u16 compression_state; 471 #ifdef CONFIG_CIFS_POSIX 472 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 473 __u64 caps; 474 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 475 #endif /* CONFIG_CIFS_POSIX */ 476 477 xid = get_xid(); 478 479 cifs_dbg(FYI, "cifs ioctl 0x%x\n", command); 480 if (pSMBFile == NULL) 481 trace_smb3_ioctl(xid, 0, command); 482 else 483 trace_smb3_ioctl(xid, pSMBFile->fid.persistent_fid, command); 484 485 switch (command) { 486 case FS_IOC_GETFLAGS: 487 if (pSMBFile == NULL) 488 break; 489 tcon = tlink_tcon(pSMBFile->tlink); 490 #ifdef CONFIG_CIFS_POSIX 491 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 492 caps = le64_to_cpu(tcon->fsUnixInfo.Capability); 493 if (CIFS_UNIX_EXTATTR_CAP & caps) { 494 __u64 ExtAttrMask = 0; 495 rc = CIFSGetExtAttr(xid, tcon, 496 pSMBFile->fid.netfid, 497 &ExtAttrBits, &ExtAttrMask); 498 if (rc == 0) 499 rc = put_user(ExtAttrBits & 500 FS_FL_USER_VISIBLE, 501 (int __user *)arg); 502 if (rc != -EOPNOTSUPP) 503 break; 504 } 505 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 506 #endif /* CONFIG_CIFS_POSIX */ 507 if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_COMPRESSED) 508 ExtAttrBits |= FS_COMPR_FL; 509 510 rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE, 511 (int __user *)arg); 512 break; 513 case FS_IOC_SETFLAGS: 514 if (pSMBFile == NULL) 515 break; 516 tcon = tlink_tcon(pSMBFile->tlink); 517 /* caps = le64_to_cpu(tcon->fsUnixInfo.Capability); */ 518 519 if (get_user(ExtAttrBits, (int __user *)arg)) { 520 rc = -EFAULT; 521 break; 522 } 523 524 /* 525 * if (CIFS_UNIX_EXTATTR_CAP & caps) 526 * rc = CIFSSetExtAttr(xid, tcon, 527 * pSMBFile->fid.netfid, 528 * extAttrBits, 529 * &ExtAttrMask); 530 * if (rc != -EOPNOTSUPP) 531 * break; 532 */ 533 534 /* Currently only flag we can set or clear is compressed. */ 535 if (ExtAttrBits & ~FS_COMPR_FL) { 536 rc = -EOPNOTSUPP; 537 break; 538 } 539 540 enable_compression = ExtAttrBits & FS_COMPR_FL; 541 compression_state = enable_compression ? 542 COMPRESSION_FORMAT_DEFAULT : 543 COMPRESSION_FORMAT_NONE; 544 545 rc = cifs_ioctl_set_compression(xid, filep, tcon, 546 pSMBFile, 547 compression_state); 548 if (rc == 0) { 549 spin_lock(&inode->i_lock); 550 if (enable_compression) 551 CIFS_I(inode)->cifsAttrs |= 552 FILE_ATTRIBUTE_COMPRESSED; 553 else 554 CIFS_I(inode)->cifsAttrs &= 555 ~FILE_ATTRIBUTE_COMPRESSED; 556 spin_unlock(&inode->i_lock); 557 } 558 cifs_dbg(FYI, "set compress flag rc %d\n", rc); 559 break; 560 case CIFS_IOC_COPYCHUNK_FILE: 561 rc = cifs_ioctl_copychunk(xid, filep, arg); 562 break; 563 case CIFS_QUERY_INFO: 564 rc = cifs_ioctl_query_info(xid, filep, arg); 565 break; 566 case CIFS_IOC_SET_INTEGRITY: 567 if (pSMBFile == NULL) 568 break; 569 tcon = tlink_tcon(pSMBFile->tlink); 570 if (tcon->ses->server->ops->set_integrity) 571 rc = tcon->ses->server->ops->set_integrity(xid, 572 tcon, pSMBFile); 573 else 574 rc = -EOPNOTSUPP; 575 break; 576 case CIFS_IOC_GET_MNT_INFO: 577 if (pSMBFile == NULL) 578 break; 579 tcon = tlink_tcon(pSMBFile->tlink); 580 rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg); 581 break; 582 case CIFS_IOC_GET_TCON_INFO: 583 cifs_sb = CIFS_SB(inode->i_sb); 584 tlink = cifs_sb_tlink(cifs_sb); 585 if (IS_ERR(tlink)) { 586 rc = PTR_ERR(tlink); 587 break; 588 } 589 tcon = tlink_tcon(tlink); 590 rc = smb_mnt_get_tcon_info(tcon, (void __user *)arg); 591 cifs_put_tlink(tlink); 592 break; 593 case CIFS_ENUMERATE_SNAPSHOTS: 594 if (pSMBFile == NULL) 595 break; 596 if (arg == 0) { 597 rc = -EINVAL; 598 goto cifs_ioc_exit; 599 } 600 tcon = tlink_tcon(pSMBFile->tlink); 601 if (tcon->ses->server->ops->enum_snapshots) 602 rc = tcon->ses->server->ops->enum_snapshots(xid, tcon, 603 pSMBFile, (void __user *)arg); 604 else 605 rc = -EOPNOTSUPP; 606 break; 607 case CIFS_DUMP_KEY: 608 /* 609 * Dump encryption keys. This is an old ioctl that only 610 * handles AES-128-{CCM,GCM}. 611 */ 612 if (!capable(CAP_SYS_ADMIN)) { 613 rc = -EACCES; 614 break; 615 } 616 617 cifs_sb = CIFS_SB(inode->i_sb); 618 tlink = cifs_sb_tlink(cifs_sb); 619 if (IS_ERR(tlink)) { 620 rc = PTR_ERR(tlink); 621 break; 622 } 623 tcon = tlink_tcon(tlink); 624 if (!smb3_encryption_required(tcon)) { 625 rc = -EOPNOTSUPP; 626 cifs_put_tlink(tlink); 627 break; 628 } 629 pkey_inf.cipher_type = 630 le16_to_cpu(tcon->ses->server->cipher_type); 631 pkey_inf.Suid = tcon->ses->Suid; 632 memcpy(pkey_inf.auth_key, tcon->ses->auth_key.response, 633 SMB2_NTLMV2_SESSKEY_SIZE); 634 memcpy(pkey_inf.smb3decryptionkey, 635 tcon->ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE); 636 memcpy(pkey_inf.smb3encryptionkey, 637 tcon->ses->smb3encryptionkey, SMB3_SIGN_KEY_SIZE); 638 if (copy_to_user((void __user *)arg, &pkey_inf, 639 sizeof(struct smb3_key_debug_info))) 640 rc = -EFAULT; 641 else 642 rc = 0; 643 cifs_put_tlink(tlink); 644 break; 645 case CIFS_DUMP_FULL_KEY: 646 /* 647 * Dump encryption keys (handles any key sizes) 648 */ 649 if (pSMBFile == NULL) 650 break; 651 if (!capable(CAP_SYS_ADMIN)) { 652 rc = -EACCES; 653 break; 654 } 655 cifs_sb = CIFS_SB(inode->i_sb); 656 tlink = cifs_sb_tlink(cifs_sb); 657 if (IS_ERR(tlink)) { 658 rc = PTR_ERR(tlink); 659 break; 660 } 661 662 tcon = tlink_tcon(tlink); 663 rc = cifs_dump_full_key(tcon, (void __user *)arg); 664 cifs_put_tlink(tlink); 665 break; 666 case CIFS_IOC_NOTIFY: 667 if (!S_ISDIR(inode->i_mode)) { 668 /* Notify can only be done on directories */ 669 rc = -EOPNOTSUPP; 670 break; 671 } 672 cifs_sb = CIFS_SB(inode->i_sb); 673 tlink = cifs_sb_tlink(cifs_sb); 674 if (IS_ERR(tlink)) { 675 rc = PTR_ERR(tlink); 676 break; 677 } 678 tcon = tlink_tcon(tlink); 679 if (tcon && tcon->ses->server->ops->notify) { 680 rc = tcon->ses->server->ops->notify(xid, 681 filep, (void __user *)arg, 682 false /* no ret data */); 683 cifs_dbg(FYI, "ioctl notify rc %d\n", rc); 684 } else 685 rc = -EOPNOTSUPP; 686 cifs_put_tlink(tlink); 687 break; 688 case CIFS_IOC_NOTIFY_INFO: 689 if (!S_ISDIR(inode->i_mode)) { 690 /* Notify can only be done on directories */ 691 rc = -EOPNOTSUPP; 692 break; 693 } 694 cifs_sb = CIFS_SB(inode->i_sb); 695 tlink = cifs_sb_tlink(cifs_sb); 696 if (IS_ERR(tlink)) { 697 rc = PTR_ERR(tlink); 698 break; 699 } 700 tcon = tlink_tcon(tlink); 701 if (tcon && tcon->ses->server->ops->notify) { 702 rc = tcon->ses->server->ops->notify(xid, 703 filep, (void __user *)arg, 704 true /* return details */); 705 cifs_dbg(FYI, "ioctl notify info rc %d\n", rc); 706 } else 707 rc = -EOPNOTSUPP; 708 cifs_put_tlink(tlink); 709 break; 710 case CIFS_IOC_SHUTDOWN: 711 rc = cifs_shutdown(inode->i_sb, arg); 712 break; 713 default: 714 cifs_dbg(FYI, "unsupported ioctl\n"); 715 trace_smb3_unsupported_ioctl(xid, 716 pSMBFile ? pSMBFile->fid.persistent_fid : 0, 717 command); 718 break; 719 } 720 cifs_ioc_exit: 721 free_xid(xid); 722 return rc; 723 } 724