1*38c8a9a5SSteve French // SPDX-License-Identifier: LGPL-2.1 2*38c8a9a5SSteve French /* 3*38c8a9a5SSteve French * 4*38c8a9a5SSteve French * vfs operations that deal with io control 5*38c8a9a5SSteve French * 6*38c8a9a5SSteve French * Copyright (C) International Business Machines Corp., 2005,2013 7*38c8a9a5SSteve French * Author(s): Steve French (sfrench@us.ibm.com) 8*38c8a9a5SSteve French * 9*38c8a9a5SSteve French */ 10*38c8a9a5SSteve French 11*38c8a9a5SSteve French #include <linux/fs.h> 12*38c8a9a5SSteve French #include <linux/file.h> 13*38c8a9a5SSteve French #include <linux/mount.h> 14*38c8a9a5SSteve French #include <linux/mm.h> 15*38c8a9a5SSteve French #include <linux/pagemap.h> 16*38c8a9a5SSteve French #include "cifspdu.h" 17*38c8a9a5SSteve French #include "cifsglob.h" 18*38c8a9a5SSteve French #include "cifsproto.h" 19*38c8a9a5SSteve French #include "cifs_debug.h" 20*38c8a9a5SSteve French #include "cifsfs.h" 21*38c8a9a5SSteve French #include "cifs_ioctl.h" 22*38c8a9a5SSteve French #include "smb2proto.h" 23*38c8a9a5SSteve French #include "smb2glob.h" 24*38c8a9a5SSteve French #include <linux/btrfs.h> 25*38c8a9a5SSteve French 26*38c8a9a5SSteve French static long cifs_ioctl_query_info(unsigned int xid, struct file *filep, 27*38c8a9a5SSteve French unsigned long p) 28*38c8a9a5SSteve French { 29*38c8a9a5SSteve French struct inode *inode = file_inode(filep); 30*38c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 31*38c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 32*38c8a9a5SSteve French struct dentry *dentry = filep->f_path.dentry; 33*38c8a9a5SSteve French const unsigned char *path; 34*38c8a9a5SSteve French void *page = alloc_dentry_path(); 35*38c8a9a5SSteve French __le16 *utf16_path = NULL, root_path; 36*38c8a9a5SSteve French int rc = 0; 37*38c8a9a5SSteve French 38*38c8a9a5SSteve French path = build_path_from_dentry(dentry, page); 39*38c8a9a5SSteve French if (IS_ERR(path)) { 40*38c8a9a5SSteve French free_dentry_path(page); 41*38c8a9a5SSteve French return PTR_ERR(path); 42*38c8a9a5SSteve French } 43*38c8a9a5SSteve French 44*38c8a9a5SSteve French cifs_dbg(FYI, "%s %s\n", __func__, path); 45*38c8a9a5SSteve French 46*38c8a9a5SSteve French if (!path[0]) { 47*38c8a9a5SSteve French root_path = 0; 48*38c8a9a5SSteve French utf16_path = &root_path; 49*38c8a9a5SSteve French } else { 50*38c8a9a5SSteve French utf16_path = cifs_convert_path_to_utf16(path + 1, cifs_sb); 51*38c8a9a5SSteve French if (!utf16_path) { 52*38c8a9a5SSteve French rc = -ENOMEM; 53*38c8a9a5SSteve French goto ici_exit; 54*38c8a9a5SSteve French } 55*38c8a9a5SSteve French } 56*38c8a9a5SSteve French 57*38c8a9a5SSteve French if (tcon->ses->server->ops->ioctl_query_info) 58*38c8a9a5SSteve French rc = tcon->ses->server->ops->ioctl_query_info( 59*38c8a9a5SSteve French xid, tcon, cifs_sb, utf16_path, 60*38c8a9a5SSteve French filep->private_data ? 0 : 1, p); 61*38c8a9a5SSteve French else 62*38c8a9a5SSteve French rc = -EOPNOTSUPP; 63*38c8a9a5SSteve French 64*38c8a9a5SSteve French ici_exit: 65*38c8a9a5SSteve French if (utf16_path != &root_path) 66*38c8a9a5SSteve French kfree(utf16_path); 67*38c8a9a5SSteve French free_dentry_path(page); 68*38c8a9a5SSteve French return rc; 69*38c8a9a5SSteve French } 70*38c8a9a5SSteve French 71*38c8a9a5SSteve French static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file, 72*38c8a9a5SSteve French unsigned long srcfd) 73*38c8a9a5SSteve French { 74*38c8a9a5SSteve French int rc; 75*38c8a9a5SSteve French struct fd src_file; 76*38c8a9a5SSteve French struct inode *src_inode; 77*38c8a9a5SSteve French 78*38c8a9a5SSteve French cifs_dbg(FYI, "ioctl copychunk range\n"); 79*38c8a9a5SSteve French /* the destination must be opened for writing */ 80*38c8a9a5SSteve French if (!(dst_file->f_mode & FMODE_WRITE)) { 81*38c8a9a5SSteve French cifs_dbg(FYI, "file target not open for write\n"); 82*38c8a9a5SSteve French return -EINVAL; 83*38c8a9a5SSteve French } 84*38c8a9a5SSteve French 85*38c8a9a5SSteve French /* check if target volume is readonly and take reference */ 86*38c8a9a5SSteve French rc = mnt_want_write_file(dst_file); 87*38c8a9a5SSteve French if (rc) { 88*38c8a9a5SSteve French cifs_dbg(FYI, "mnt_want_write failed with rc %d\n", rc); 89*38c8a9a5SSteve French return rc; 90*38c8a9a5SSteve French } 91*38c8a9a5SSteve French 92*38c8a9a5SSteve French src_file = fdget(srcfd); 93*38c8a9a5SSteve French if (!src_file.file) { 94*38c8a9a5SSteve French rc = -EBADF; 95*38c8a9a5SSteve French goto out_drop_write; 96*38c8a9a5SSteve French } 97*38c8a9a5SSteve French 98*38c8a9a5SSteve French if (src_file.file->f_op->unlocked_ioctl != cifs_ioctl) { 99*38c8a9a5SSteve French rc = -EBADF; 100*38c8a9a5SSteve French cifs_dbg(VFS, "src file seems to be from a different filesystem type\n"); 101*38c8a9a5SSteve French goto out_fput; 102*38c8a9a5SSteve French } 103*38c8a9a5SSteve French 104*38c8a9a5SSteve French src_inode = file_inode(src_file.file); 105*38c8a9a5SSteve French rc = -EINVAL; 106*38c8a9a5SSteve French if (S_ISDIR(src_inode->i_mode)) 107*38c8a9a5SSteve French goto out_fput; 108*38c8a9a5SSteve French 109*38c8a9a5SSteve French rc = cifs_file_copychunk_range(xid, src_file.file, 0, dst_file, 0, 110*38c8a9a5SSteve French src_inode->i_size, 0); 111*38c8a9a5SSteve French if (rc > 0) 112*38c8a9a5SSteve French rc = 0; 113*38c8a9a5SSteve French out_fput: 114*38c8a9a5SSteve French fdput(src_file); 115*38c8a9a5SSteve French out_drop_write: 116*38c8a9a5SSteve French mnt_drop_write_file(dst_file); 117*38c8a9a5SSteve French return rc; 118*38c8a9a5SSteve French } 119*38c8a9a5SSteve French 120*38c8a9a5SSteve French static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon, 121*38c8a9a5SSteve French void __user *arg) 122*38c8a9a5SSteve French { 123*38c8a9a5SSteve French int rc = 0; 124*38c8a9a5SSteve French struct smb_mnt_fs_info *fsinf; 125*38c8a9a5SSteve French 126*38c8a9a5SSteve French fsinf = kzalloc(sizeof(struct smb_mnt_fs_info), GFP_KERNEL); 127*38c8a9a5SSteve French if (fsinf == NULL) 128*38c8a9a5SSteve French return -ENOMEM; 129*38c8a9a5SSteve French 130*38c8a9a5SSteve French fsinf->version = 1; 131*38c8a9a5SSteve French fsinf->protocol_id = tcon->ses->server->vals->protocol_id; 132*38c8a9a5SSteve French fsinf->device_characteristics = 133*38c8a9a5SSteve French le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics); 134*38c8a9a5SSteve French fsinf->device_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); 135*38c8a9a5SSteve French fsinf->fs_attributes = le32_to_cpu(tcon->fsAttrInfo.Attributes); 136*38c8a9a5SSteve French fsinf->max_path_component = 137*38c8a9a5SSteve French le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength); 138*38c8a9a5SSteve French fsinf->vol_serial_number = tcon->vol_serial_number; 139*38c8a9a5SSteve French fsinf->vol_create_time = le64_to_cpu(tcon->vol_create_time); 140*38c8a9a5SSteve French fsinf->share_flags = tcon->share_flags; 141*38c8a9a5SSteve French fsinf->share_caps = le32_to_cpu(tcon->capabilities); 142*38c8a9a5SSteve French fsinf->sector_flags = tcon->ss_flags; 143*38c8a9a5SSteve French fsinf->optimal_sector_size = tcon->perf_sector_size; 144*38c8a9a5SSteve French fsinf->max_bytes_chunk = tcon->max_bytes_chunk; 145*38c8a9a5SSteve French fsinf->maximal_access = tcon->maximal_access; 146*38c8a9a5SSteve French fsinf->cifs_posix_caps = le64_to_cpu(tcon->fsUnixInfo.Capability); 147*38c8a9a5SSteve French 148*38c8a9a5SSteve French if (copy_to_user(arg, fsinf, sizeof(struct smb_mnt_fs_info))) 149*38c8a9a5SSteve French rc = -EFAULT; 150*38c8a9a5SSteve French 151*38c8a9a5SSteve French kfree(fsinf); 152*38c8a9a5SSteve French return rc; 153*38c8a9a5SSteve French } 154*38c8a9a5SSteve French 155*38c8a9a5SSteve French static int cifs_shutdown(struct super_block *sb, unsigned long arg) 156*38c8a9a5SSteve French { 157*38c8a9a5SSteve French struct cifs_sb_info *sbi = CIFS_SB(sb); 158*38c8a9a5SSteve French __u32 flags; 159*38c8a9a5SSteve French 160*38c8a9a5SSteve French if (!capable(CAP_SYS_ADMIN)) 161*38c8a9a5SSteve French return -EPERM; 162*38c8a9a5SSteve French 163*38c8a9a5SSteve French if (get_user(flags, (__u32 __user *)arg)) 164*38c8a9a5SSteve French return -EFAULT; 165*38c8a9a5SSteve French 166*38c8a9a5SSteve French if (flags > CIFS_GOING_FLAGS_NOLOGFLUSH) 167*38c8a9a5SSteve French return -EINVAL; 168*38c8a9a5SSteve French 169*38c8a9a5SSteve French if (cifs_forced_shutdown(sbi)) 170*38c8a9a5SSteve French return 0; 171*38c8a9a5SSteve French 172*38c8a9a5SSteve French cifs_dbg(VFS, "shut down requested (%d)", flags); 173*38c8a9a5SSteve French /* trace_cifs_shutdown(sb, flags);*/ 174*38c8a9a5SSteve French 175*38c8a9a5SSteve French /* 176*38c8a9a5SSteve French * see: 177*38c8a9a5SSteve French * https://man7.org/linux/man-pages/man2/ioctl_xfs_goingdown.2.html 178*38c8a9a5SSteve French * for more information and description of original intent of the flags 179*38c8a9a5SSteve French */ 180*38c8a9a5SSteve French switch (flags) { 181*38c8a9a5SSteve French /* 182*38c8a9a5SSteve French * We could add support later for default flag which requires: 183*38c8a9a5SSteve French * "Flush all dirty data and metadata to disk" 184*38c8a9a5SSteve French * would need to call syncfs or equivalent to flush page cache for 185*38c8a9a5SSteve French * the mount and then issue fsync to server (if nostrictsync not set) 186*38c8a9a5SSteve French */ 187*38c8a9a5SSteve French case CIFS_GOING_FLAGS_DEFAULT: 188*38c8a9a5SSteve French cifs_dbg(FYI, "shutdown with default flag not supported\n"); 189*38c8a9a5SSteve French return -EINVAL; 190*38c8a9a5SSteve French /* 191*38c8a9a5SSteve French * FLAGS_LOGFLUSH is easy since it asks to write out metadata (not 192*38c8a9a5SSteve French * data) but metadata writes are not cached on the client, so can treat 193*38c8a9a5SSteve French * it similarly to NOLOGFLUSH 194*38c8a9a5SSteve French */ 195*38c8a9a5SSteve French case CIFS_GOING_FLAGS_LOGFLUSH: 196*38c8a9a5SSteve French case CIFS_GOING_FLAGS_NOLOGFLUSH: 197*38c8a9a5SSteve French sbi->mnt_cifs_flags |= CIFS_MOUNT_SHUTDOWN; 198*38c8a9a5SSteve French return 0; 199*38c8a9a5SSteve French default: 200*38c8a9a5SSteve French return -EINVAL; 201*38c8a9a5SSteve French } 202*38c8a9a5SSteve French return 0; 203*38c8a9a5SSteve French } 204*38c8a9a5SSteve French 205*38c8a9a5SSteve French static int cifs_dump_full_key(struct cifs_tcon *tcon, struct smb3_full_key_debug_info __user *in) 206*38c8a9a5SSteve French { 207*38c8a9a5SSteve French struct smb3_full_key_debug_info out; 208*38c8a9a5SSteve French struct cifs_ses *ses; 209*38c8a9a5SSteve French int rc = 0; 210*38c8a9a5SSteve French bool found = false; 211*38c8a9a5SSteve French u8 __user *end; 212*38c8a9a5SSteve French 213*38c8a9a5SSteve French if (!smb3_encryption_required(tcon)) { 214*38c8a9a5SSteve French rc = -EOPNOTSUPP; 215*38c8a9a5SSteve French goto out; 216*38c8a9a5SSteve French } 217*38c8a9a5SSteve French 218*38c8a9a5SSteve French /* copy user input into our output buffer */ 219*38c8a9a5SSteve French if (copy_from_user(&out, in, sizeof(out))) { 220*38c8a9a5SSteve French rc = -EINVAL; 221*38c8a9a5SSteve French goto out; 222*38c8a9a5SSteve French } 223*38c8a9a5SSteve French 224*38c8a9a5SSteve French if (!out.session_id) { 225*38c8a9a5SSteve French /* if ses id is 0, use current user session */ 226*38c8a9a5SSteve French ses = tcon->ses; 227*38c8a9a5SSteve French } else { 228*38c8a9a5SSteve French /* otherwise if a session id is given, look for it in all our sessions */ 229*38c8a9a5SSteve French struct cifs_ses *ses_it = NULL; 230*38c8a9a5SSteve French struct TCP_Server_Info *server_it = NULL; 231*38c8a9a5SSteve French 232*38c8a9a5SSteve French spin_lock(&cifs_tcp_ses_lock); 233*38c8a9a5SSteve French list_for_each_entry(server_it, &cifs_tcp_ses_list, tcp_ses_list) { 234*38c8a9a5SSteve French list_for_each_entry(ses_it, &server_it->smb_ses_list, smb_ses_list) { 235*38c8a9a5SSteve French if (ses_it->Suid == out.session_id) { 236*38c8a9a5SSteve French ses = ses_it; 237*38c8a9a5SSteve French /* 238*38c8a9a5SSteve French * since we are using the session outside the crit 239*38c8a9a5SSteve French * section, we need to make sure it won't be released 240*38c8a9a5SSteve French * so increment its refcount 241*38c8a9a5SSteve French */ 242*38c8a9a5SSteve French cifs_smb_ses_inc_refcount(ses); 243*38c8a9a5SSteve French found = true; 244*38c8a9a5SSteve French goto search_end; 245*38c8a9a5SSteve French } 246*38c8a9a5SSteve French } 247*38c8a9a5SSteve French } 248*38c8a9a5SSteve French search_end: 249*38c8a9a5SSteve French spin_unlock(&cifs_tcp_ses_lock); 250*38c8a9a5SSteve French if (!found) { 251*38c8a9a5SSteve French rc = -ENOENT; 252*38c8a9a5SSteve French goto out; 253*38c8a9a5SSteve French } 254*38c8a9a5SSteve French } 255*38c8a9a5SSteve French 256*38c8a9a5SSteve French switch (ses->server->cipher_type) { 257*38c8a9a5SSteve French case SMB2_ENCRYPTION_AES128_CCM: 258*38c8a9a5SSteve French case SMB2_ENCRYPTION_AES128_GCM: 259*38c8a9a5SSteve French out.session_key_length = CIFS_SESS_KEY_SIZE; 260*38c8a9a5SSteve French out.server_in_key_length = out.server_out_key_length = SMB3_GCM128_CRYPTKEY_SIZE; 261*38c8a9a5SSteve French break; 262*38c8a9a5SSteve French case SMB2_ENCRYPTION_AES256_CCM: 263*38c8a9a5SSteve French case SMB2_ENCRYPTION_AES256_GCM: 264*38c8a9a5SSteve French out.session_key_length = CIFS_SESS_KEY_SIZE; 265*38c8a9a5SSteve French out.server_in_key_length = out.server_out_key_length = SMB3_GCM256_CRYPTKEY_SIZE; 266*38c8a9a5SSteve French break; 267*38c8a9a5SSteve French default: 268*38c8a9a5SSteve French rc = -EOPNOTSUPP; 269*38c8a9a5SSteve French goto out; 270*38c8a9a5SSteve French } 271*38c8a9a5SSteve French 272*38c8a9a5SSteve French /* check if user buffer is big enough to store all the keys */ 273*38c8a9a5SSteve French if (out.in_size < sizeof(out) + out.session_key_length + out.server_in_key_length 274*38c8a9a5SSteve French + out.server_out_key_length) { 275*38c8a9a5SSteve French rc = -ENOBUFS; 276*38c8a9a5SSteve French goto out; 277*38c8a9a5SSteve French } 278*38c8a9a5SSteve French 279*38c8a9a5SSteve French out.session_id = ses->Suid; 280*38c8a9a5SSteve French out.cipher_type = le16_to_cpu(ses->server->cipher_type); 281*38c8a9a5SSteve French 282*38c8a9a5SSteve French /* overwrite user input with our output */ 283*38c8a9a5SSteve French if (copy_to_user(in, &out, sizeof(out))) { 284*38c8a9a5SSteve French rc = -EINVAL; 285*38c8a9a5SSteve French goto out; 286*38c8a9a5SSteve French } 287*38c8a9a5SSteve French 288*38c8a9a5SSteve French /* append all the keys at the end of the user buffer */ 289*38c8a9a5SSteve French end = in->data; 290*38c8a9a5SSteve French if (copy_to_user(end, ses->auth_key.response, out.session_key_length)) { 291*38c8a9a5SSteve French rc = -EINVAL; 292*38c8a9a5SSteve French goto out; 293*38c8a9a5SSteve French } 294*38c8a9a5SSteve French end += out.session_key_length; 295*38c8a9a5SSteve French 296*38c8a9a5SSteve French if (copy_to_user(end, ses->smb3encryptionkey, out.server_in_key_length)) { 297*38c8a9a5SSteve French rc = -EINVAL; 298*38c8a9a5SSteve French goto out; 299*38c8a9a5SSteve French } 300*38c8a9a5SSteve French end += out.server_in_key_length; 301*38c8a9a5SSteve French 302*38c8a9a5SSteve French if (copy_to_user(end, ses->smb3decryptionkey, out.server_out_key_length)) { 303*38c8a9a5SSteve French rc = -EINVAL; 304*38c8a9a5SSteve French goto out; 305*38c8a9a5SSteve French } 306*38c8a9a5SSteve French 307*38c8a9a5SSteve French out: 308*38c8a9a5SSteve French if (found) 309*38c8a9a5SSteve French cifs_put_smb_ses(ses); 310*38c8a9a5SSteve French return rc; 311*38c8a9a5SSteve French } 312*38c8a9a5SSteve French 313*38c8a9a5SSteve French long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) 314*38c8a9a5SSteve French { 315*38c8a9a5SSteve French struct inode *inode = file_inode(filep); 316*38c8a9a5SSteve French struct smb3_key_debug_info pkey_inf; 317*38c8a9a5SSteve French int rc = -ENOTTY; /* strange error - but the precedent */ 318*38c8a9a5SSteve French unsigned int xid; 319*38c8a9a5SSteve French struct cifsFileInfo *pSMBFile = filep->private_data; 320*38c8a9a5SSteve French struct cifs_tcon *tcon; 321*38c8a9a5SSteve French struct tcon_link *tlink; 322*38c8a9a5SSteve French struct cifs_sb_info *cifs_sb; 323*38c8a9a5SSteve French __u64 ExtAttrBits = 0; 324*38c8a9a5SSteve French __u64 caps; 325*38c8a9a5SSteve French 326*38c8a9a5SSteve French xid = get_xid(); 327*38c8a9a5SSteve French 328*38c8a9a5SSteve French cifs_dbg(FYI, "cifs ioctl 0x%x\n", command); 329*38c8a9a5SSteve French switch (command) { 330*38c8a9a5SSteve French case FS_IOC_GETFLAGS: 331*38c8a9a5SSteve French if (pSMBFile == NULL) 332*38c8a9a5SSteve French break; 333*38c8a9a5SSteve French tcon = tlink_tcon(pSMBFile->tlink); 334*38c8a9a5SSteve French caps = le64_to_cpu(tcon->fsUnixInfo.Capability); 335*38c8a9a5SSteve French #ifdef CONFIG_CIFS_POSIX 336*38c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 337*38c8a9a5SSteve French if (CIFS_UNIX_EXTATTR_CAP & caps) { 338*38c8a9a5SSteve French __u64 ExtAttrMask = 0; 339*38c8a9a5SSteve French rc = CIFSGetExtAttr(xid, tcon, 340*38c8a9a5SSteve French pSMBFile->fid.netfid, 341*38c8a9a5SSteve French &ExtAttrBits, &ExtAttrMask); 342*38c8a9a5SSteve French if (rc == 0) 343*38c8a9a5SSteve French rc = put_user(ExtAttrBits & 344*38c8a9a5SSteve French FS_FL_USER_VISIBLE, 345*38c8a9a5SSteve French (int __user *)arg); 346*38c8a9a5SSteve French if (rc != -EOPNOTSUPP) 347*38c8a9a5SSteve French break; 348*38c8a9a5SSteve French } 349*38c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 350*38c8a9a5SSteve French #endif /* CONFIG_CIFS_POSIX */ 351*38c8a9a5SSteve French rc = 0; 352*38c8a9a5SSteve French if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED) { 353*38c8a9a5SSteve French /* add in the compressed bit */ 354*38c8a9a5SSteve French ExtAttrBits = FS_COMPR_FL; 355*38c8a9a5SSteve French rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE, 356*38c8a9a5SSteve French (int __user *)arg); 357*38c8a9a5SSteve French } 358*38c8a9a5SSteve French break; 359*38c8a9a5SSteve French case FS_IOC_SETFLAGS: 360*38c8a9a5SSteve French if (pSMBFile == NULL) 361*38c8a9a5SSteve French break; 362*38c8a9a5SSteve French tcon = tlink_tcon(pSMBFile->tlink); 363*38c8a9a5SSteve French /* caps = le64_to_cpu(tcon->fsUnixInfo.Capability); */ 364*38c8a9a5SSteve French 365*38c8a9a5SSteve French if (get_user(ExtAttrBits, (int __user *)arg)) { 366*38c8a9a5SSteve French rc = -EFAULT; 367*38c8a9a5SSteve French break; 368*38c8a9a5SSteve French } 369*38c8a9a5SSteve French 370*38c8a9a5SSteve French /* 371*38c8a9a5SSteve French * if (CIFS_UNIX_EXTATTR_CAP & caps) 372*38c8a9a5SSteve French * rc = CIFSSetExtAttr(xid, tcon, 373*38c8a9a5SSteve French * pSMBFile->fid.netfid, 374*38c8a9a5SSteve French * extAttrBits, 375*38c8a9a5SSteve French * &ExtAttrMask); 376*38c8a9a5SSteve French * if (rc != -EOPNOTSUPP) 377*38c8a9a5SSteve French * break; 378*38c8a9a5SSteve French */ 379*38c8a9a5SSteve French 380*38c8a9a5SSteve French /* Currently only flag we can set is compressed flag */ 381*38c8a9a5SSteve French if ((ExtAttrBits & FS_COMPR_FL) == 0) 382*38c8a9a5SSteve French break; 383*38c8a9a5SSteve French 384*38c8a9a5SSteve French /* Try to set compress flag */ 385*38c8a9a5SSteve French if (tcon->ses->server->ops->set_compression) { 386*38c8a9a5SSteve French rc = tcon->ses->server->ops->set_compression( 387*38c8a9a5SSteve French xid, tcon, pSMBFile); 388*38c8a9a5SSteve French cifs_dbg(FYI, "set compress flag rc %d\n", rc); 389*38c8a9a5SSteve French } 390*38c8a9a5SSteve French break; 391*38c8a9a5SSteve French case CIFS_IOC_COPYCHUNK_FILE: 392*38c8a9a5SSteve French rc = cifs_ioctl_copychunk(xid, filep, arg); 393*38c8a9a5SSteve French break; 394*38c8a9a5SSteve French case CIFS_QUERY_INFO: 395*38c8a9a5SSteve French rc = cifs_ioctl_query_info(xid, filep, arg); 396*38c8a9a5SSteve French break; 397*38c8a9a5SSteve French case CIFS_IOC_SET_INTEGRITY: 398*38c8a9a5SSteve French if (pSMBFile == NULL) 399*38c8a9a5SSteve French break; 400*38c8a9a5SSteve French tcon = tlink_tcon(pSMBFile->tlink); 401*38c8a9a5SSteve French if (tcon->ses->server->ops->set_integrity) 402*38c8a9a5SSteve French rc = tcon->ses->server->ops->set_integrity(xid, 403*38c8a9a5SSteve French tcon, pSMBFile); 404*38c8a9a5SSteve French else 405*38c8a9a5SSteve French rc = -EOPNOTSUPP; 406*38c8a9a5SSteve French break; 407*38c8a9a5SSteve French case CIFS_IOC_GET_MNT_INFO: 408*38c8a9a5SSteve French if (pSMBFile == NULL) 409*38c8a9a5SSteve French break; 410*38c8a9a5SSteve French tcon = tlink_tcon(pSMBFile->tlink); 411*38c8a9a5SSteve French rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg); 412*38c8a9a5SSteve French break; 413*38c8a9a5SSteve French case CIFS_ENUMERATE_SNAPSHOTS: 414*38c8a9a5SSteve French if (pSMBFile == NULL) 415*38c8a9a5SSteve French break; 416*38c8a9a5SSteve French if (arg == 0) { 417*38c8a9a5SSteve French rc = -EINVAL; 418*38c8a9a5SSteve French goto cifs_ioc_exit; 419*38c8a9a5SSteve French } 420*38c8a9a5SSteve French tcon = tlink_tcon(pSMBFile->tlink); 421*38c8a9a5SSteve French if (tcon->ses->server->ops->enum_snapshots) 422*38c8a9a5SSteve French rc = tcon->ses->server->ops->enum_snapshots(xid, tcon, 423*38c8a9a5SSteve French pSMBFile, (void __user *)arg); 424*38c8a9a5SSteve French else 425*38c8a9a5SSteve French rc = -EOPNOTSUPP; 426*38c8a9a5SSteve French break; 427*38c8a9a5SSteve French case CIFS_DUMP_KEY: 428*38c8a9a5SSteve French /* 429*38c8a9a5SSteve French * Dump encryption keys. This is an old ioctl that only 430*38c8a9a5SSteve French * handles AES-128-{CCM,GCM}. 431*38c8a9a5SSteve French */ 432*38c8a9a5SSteve French if (pSMBFile == NULL) 433*38c8a9a5SSteve French break; 434*38c8a9a5SSteve French if (!capable(CAP_SYS_ADMIN)) { 435*38c8a9a5SSteve French rc = -EACCES; 436*38c8a9a5SSteve French break; 437*38c8a9a5SSteve French } 438*38c8a9a5SSteve French 439*38c8a9a5SSteve French tcon = tlink_tcon(pSMBFile->tlink); 440*38c8a9a5SSteve French if (!smb3_encryption_required(tcon)) { 441*38c8a9a5SSteve French rc = -EOPNOTSUPP; 442*38c8a9a5SSteve French break; 443*38c8a9a5SSteve French } 444*38c8a9a5SSteve French pkey_inf.cipher_type = 445*38c8a9a5SSteve French le16_to_cpu(tcon->ses->server->cipher_type); 446*38c8a9a5SSteve French pkey_inf.Suid = tcon->ses->Suid; 447*38c8a9a5SSteve French memcpy(pkey_inf.auth_key, tcon->ses->auth_key.response, 448*38c8a9a5SSteve French 16 /* SMB2_NTLMV2_SESSKEY_SIZE */); 449*38c8a9a5SSteve French memcpy(pkey_inf.smb3decryptionkey, 450*38c8a9a5SSteve French tcon->ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE); 451*38c8a9a5SSteve French memcpy(pkey_inf.smb3encryptionkey, 452*38c8a9a5SSteve French tcon->ses->smb3encryptionkey, SMB3_SIGN_KEY_SIZE); 453*38c8a9a5SSteve French if (copy_to_user((void __user *)arg, &pkey_inf, 454*38c8a9a5SSteve French sizeof(struct smb3_key_debug_info))) 455*38c8a9a5SSteve French rc = -EFAULT; 456*38c8a9a5SSteve French else 457*38c8a9a5SSteve French rc = 0; 458*38c8a9a5SSteve French break; 459*38c8a9a5SSteve French case CIFS_DUMP_FULL_KEY: 460*38c8a9a5SSteve French /* 461*38c8a9a5SSteve French * Dump encryption keys (handles any key sizes) 462*38c8a9a5SSteve French */ 463*38c8a9a5SSteve French if (pSMBFile == NULL) 464*38c8a9a5SSteve French break; 465*38c8a9a5SSteve French if (!capable(CAP_SYS_ADMIN)) { 466*38c8a9a5SSteve French rc = -EACCES; 467*38c8a9a5SSteve French break; 468*38c8a9a5SSteve French } 469*38c8a9a5SSteve French tcon = tlink_tcon(pSMBFile->tlink); 470*38c8a9a5SSteve French rc = cifs_dump_full_key(tcon, (void __user *)arg); 471*38c8a9a5SSteve French break; 472*38c8a9a5SSteve French case CIFS_IOC_NOTIFY: 473*38c8a9a5SSteve French if (!S_ISDIR(inode->i_mode)) { 474*38c8a9a5SSteve French /* Notify can only be done on directories */ 475*38c8a9a5SSteve French rc = -EOPNOTSUPP; 476*38c8a9a5SSteve French break; 477*38c8a9a5SSteve French } 478*38c8a9a5SSteve French cifs_sb = CIFS_SB(inode->i_sb); 479*38c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 480*38c8a9a5SSteve French if (IS_ERR(tlink)) { 481*38c8a9a5SSteve French rc = PTR_ERR(tlink); 482*38c8a9a5SSteve French break; 483*38c8a9a5SSteve French } 484*38c8a9a5SSteve French tcon = tlink_tcon(tlink); 485*38c8a9a5SSteve French if (tcon && tcon->ses->server->ops->notify) { 486*38c8a9a5SSteve French rc = tcon->ses->server->ops->notify(xid, 487*38c8a9a5SSteve French filep, (void __user *)arg, 488*38c8a9a5SSteve French false /* no ret data */); 489*38c8a9a5SSteve French cifs_dbg(FYI, "ioctl notify rc %d\n", rc); 490*38c8a9a5SSteve French } else 491*38c8a9a5SSteve French rc = -EOPNOTSUPP; 492*38c8a9a5SSteve French cifs_put_tlink(tlink); 493*38c8a9a5SSteve French break; 494*38c8a9a5SSteve French case CIFS_IOC_NOTIFY_INFO: 495*38c8a9a5SSteve French if (!S_ISDIR(inode->i_mode)) { 496*38c8a9a5SSteve French /* Notify can only be done on directories */ 497*38c8a9a5SSteve French rc = -EOPNOTSUPP; 498*38c8a9a5SSteve French break; 499*38c8a9a5SSteve French } 500*38c8a9a5SSteve French cifs_sb = CIFS_SB(inode->i_sb); 501*38c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 502*38c8a9a5SSteve French if (IS_ERR(tlink)) { 503*38c8a9a5SSteve French rc = PTR_ERR(tlink); 504*38c8a9a5SSteve French break; 505*38c8a9a5SSteve French } 506*38c8a9a5SSteve French tcon = tlink_tcon(tlink); 507*38c8a9a5SSteve French if (tcon && tcon->ses->server->ops->notify) { 508*38c8a9a5SSteve French rc = tcon->ses->server->ops->notify(xid, 509*38c8a9a5SSteve French filep, (void __user *)arg, 510*38c8a9a5SSteve French true /* return details */); 511*38c8a9a5SSteve French cifs_dbg(FYI, "ioctl notify info rc %d\n", rc); 512*38c8a9a5SSteve French } else 513*38c8a9a5SSteve French rc = -EOPNOTSUPP; 514*38c8a9a5SSteve French cifs_put_tlink(tlink); 515*38c8a9a5SSteve French break; 516*38c8a9a5SSteve French case CIFS_IOC_SHUTDOWN: 517*38c8a9a5SSteve French rc = cifs_shutdown(inode->i_sb, arg); 518*38c8a9a5SSteve French break; 519*38c8a9a5SSteve French default: 520*38c8a9a5SSteve French cifs_dbg(FYI, "unsupported ioctl\n"); 521*38c8a9a5SSteve French break; 522*38c8a9a5SSteve French } 523*38c8a9a5SSteve French cifs_ioc_exit: 524*38c8a9a5SSteve French free_xid(xid); 525*38c8a9a5SSteve French return rc; 526*38c8a9a5SSteve French } 527