0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/fs.h>
0012 #include <linux/file.h>
0013 #include <linux/mount.h>
0014 #include <linux/mm.h>
0015 #include <linux/pagemap.h>
0016 #include "cifspdu.h"
0017 #include "cifsglob.h"
0018 #include "cifsproto.h"
0019 #include "cifs_debug.h"
0020 #include "cifsfs.h"
0021 #include "cifs_ioctl.h"
0022 #include "smb2proto.h"
0023 #include "smb2glob.h"
0024 #include <linux/btrfs.h>
0025
0026 static long cifs_ioctl_query_info(unsigned int xid, struct file *filep,
0027 unsigned long p)
0028 {
0029 struct inode *inode = file_inode(filep);
0030 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
0031 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
0032 struct dentry *dentry = filep->f_path.dentry;
0033 const unsigned char *path;
0034 void *page = alloc_dentry_path();
0035 __le16 *utf16_path = NULL, root_path;
0036 int rc = 0;
0037
0038 path = build_path_from_dentry(dentry, page);
0039 if (IS_ERR(path)) {
0040 free_dentry_path(page);
0041 return PTR_ERR(path);
0042 }
0043
0044 cifs_dbg(FYI, "%s %s\n", __func__, path);
0045
0046 if (!path[0]) {
0047 root_path = 0;
0048 utf16_path = &root_path;
0049 } else {
0050 utf16_path = cifs_convert_path_to_utf16(path + 1, cifs_sb);
0051 if (!utf16_path) {
0052 rc = -ENOMEM;
0053 goto ici_exit;
0054 }
0055 }
0056
0057 if (tcon->ses->server->ops->ioctl_query_info)
0058 rc = tcon->ses->server->ops->ioctl_query_info(
0059 xid, tcon, cifs_sb, utf16_path,
0060 filep->private_data ? 0 : 1, p);
0061 else
0062 rc = -EOPNOTSUPP;
0063
0064 ici_exit:
0065 if (utf16_path != &root_path)
0066 kfree(utf16_path);
0067 free_dentry_path(page);
0068 return rc;
0069 }
0070
0071 static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file,
0072 unsigned long srcfd)
0073 {
0074 int rc;
0075 struct fd src_file;
0076 struct inode *src_inode;
0077
0078 cifs_dbg(FYI, "ioctl copychunk range\n");
0079
0080 if (!(dst_file->f_mode & FMODE_WRITE)) {
0081 cifs_dbg(FYI, "file target not open for write\n");
0082 return -EINVAL;
0083 }
0084
0085
0086 rc = mnt_want_write_file(dst_file);
0087 if (rc) {
0088 cifs_dbg(FYI, "mnt_want_write failed with rc %d\n", rc);
0089 return rc;
0090 }
0091
0092 src_file = fdget(srcfd);
0093 if (!src_file.file) {
0094 rc = -EBADF;
0095 goto out_drop_write;
0096 }
0097
0098 if (src_file.file->f_op->unlocked_ioctl != cifs_ioctl) {
0099 rc = -EBADF;
0100 cifs_dbg(VFS, "src file seems to be from a different filesystem type\n");
0101 goto out_fput;
0102 }
0103
0104 src_inode = file_inode(src_file.file);
0105 rc = -EINVAL;
0106 if (S_ISDIR(src_inode->i_mode))
0107 goto out_fput;
0108
0109 rc = cifs_file_copychunk_range(xid, src_file.file, 0, dst_file, 0,
0110 src_inode->i_size, 0);
0111 if (rc > 0)
0112 rc = 0;
0113 out_fput:
0114 fdput(src_file);
0115 out_drop_write:
0116 mnt_drop_write_file(dst_file);
0117 return rc;
0118 }
0119
0120 static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon,
0121 void __user *arg)
0122 {
0123 int rc = 0;
0124 struct smb_mnt_fs_info *fsinf;
0125
0126 fsinf = kzalloc(sizeof(struct smb_mnt_fs_info), GFP_KERNEL);
0127 if (fsinf == NULL)
0128 return -ENOMEM;
0129
0130 fsinf->version = 1;
0131 fsinf->protocol_id = tcon->ses->server->vals->protocol_id;
0132 fsinf->device_characteristics =
0133 le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics);
0134 fsinf->device_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
0135 fsinf->fs_attributes = le32_to_cpu(tcon->fsAttrInfo.Attributes);
0136 fsinf->max_path_component =
0137 le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength);
0138 fsinf->vol_serial_number = tcon->vol_serial_number;
0139 fsinf->vol_create_time = le64_to_cpu(tcon->vol_create_time);
0140 fsinf->share_flags = tcon->share_flags;
0141 fsinf->share_caps = le32_to_cpu(tcon->capabilities);
0142 fsinf->sector_flags = tcon->ss_flags;
0143 fsinf->optimal_sector_size = tcon->perf_sector_size;
0144 fsinf->max_bytes_chunk = tcon->max_bytes_chunk;
0145 fsinf->maximal_access = tcon->maximal_access;
0146 fsinf->cifs_posix_caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
0147
0148 if (copy_to_user(arg, fsinf, sizeof(struct smb_mnt_fs_info)))
0149 rc = -EFAULT;
0150
0151 kfree(fsinf);
0152 return rc;
0153 }
0154
0155 static int cifs_shutdown(struct super_block *sb, unsigned long arg)
0156 {
0157 struct cifs_sb_info *sbi = CIFS_SB(sb);
0158 __u32 flags;
0159
0160 if (!capable(CAP_SYS_ADMIN))
0161 return -EPERM;
0162
0163 if (get_user(flags, (__u32 __user *)arg))
0164 return -EFAULT;
0165
0166 if (flags > CIFS_GOING_FLAGS_NOLOGFLUSH)
0167 return -EINVAL;
0168
0169 if (cifs_forced_shutdown(sbi))
0170 return 0;
0171
0172 cifs_dbg(VFS, "shut down requested (%d)", flags);
0173
0174
0175
0176
0177
0178
0179
0180 switch (flags) {
0181
0182
0183
0184
0185
0186
0187 case CIFS_GOING_FLAGS_DEFAULT:
0188 cifs_dbg(FYI, "shutdown with default flag not supported\n");
0189 return -EINVAL;
0190
0191
0192
0193
0194
0195 case CIFS_GOING_FLAGS_LOGFLUSH:
0196 case CIFS_GOING_FLAGS_NOLOGFLUSH:
0197 sbi->mnt_cifs_flags |= CIFS_MOUNT_SHUTDOWN;
0198 return 0;
0199 default:
0200 return -EINVAL;
0201 }
0202 return 0;
0203 }
0204
0205 static int cifs_dump_full_key(struct cifs_tcon *tcon, struct smb3_full_key_debug_info __user *in)
0206 {
0207 struct smb3_full_key_debug_info out;
0208 struct cifs_ses *ses;
0209 int rc = 0;
0210 bool found = false;
0211 u8 __user *end;
0212
0213 if (!smb3_encryption_required(tcon)) {
0214 rc = -EOPNOTSUPP;
0215 goto out;
0216 }
0217
0218
0219 if (copy_from_user(&out, in, sizeof(out))) {
0220 rc = -EINVAL;
0221 goto out;
0222 }
0223
0224 if (!out.session_id) {
0225
0226 ses = tcon->ses;
0227 } else {
0228
0229 struct cifs_ses *ses_it = NULL;
0230 struct TCP_Server_Info *server_it = NULL;
0231
0232 spin_lock(&cifs_tcp_ses_lock);
0233 list_for_each_entry(server_it, &cifs_tcp_ses_list, tcp_ses_list) {
0234 list_for_each_entry(ses_it, &server_it->smb_ses_list, smb_ses_list) {
0235 if (ses_it->Suid == out.session_id) {
0236 ses = ses_it;
0237
0238
0239
0240
0241
0242 ses->ses_count++;
0243 found = true;
0244 goto search_end;
0245 }
0246 }
0247 }
0248 search_end:
0249 spin_unlock(&cifs_tcp_ses_lock);
0250 if (!found) {
0251 rc = -ENOENT;
0252 goto out;
0253 }
0254 }
0255
0256 switch (ses->server->cipher_type) {
0257 case SMB2_ENCRYPTION_AES128_CCM:
0258 case SMB2_ENCRYPTION_AES128_GCM:
0259 out.session_key_length = CIFS_SESS_KEY_SIZE;
0260 out.server_in_key_length = out.server_out_key_length = SMB3_GCM128_CRYPTKEY_SIZE;
0261 break;
0262 case SMB2_ENCRYPTION_AES256_CCM:
0263 case SMB2_ENCRYPTION_AES256_GCM:
0264 out.session_key_length = CIFS_SESS_KEY_SIZE;
0265 out.server_in_key_length = out.server_out_key_length = SMB3_GCM256_CRYPTKEY_SIZE;
0266 break;
0267 default:
0268 rc = -EOPNOTSUPP;
0269 goto out;
0270 }
0271
0272
0273 if (out.in_size < sizeof(out) + out.session_key_length + out.server_in_key_length
0274 + out.server_out_key_length) {
0275 rc = -ENOBUFS;
0276 goto out;
0277 }
0278
0279 out.session_id = ses->Suid;
0280 out.cipher_type = le16_to_cpu(ses->server->cipher_type);
0281
0282
0283 if (copy_to_user(in, &out, sizeof(out))) {
0284 rc = -EINVAL;
0285 goto out;
0286 }
0287
0288
0289 end = in->data;
0290 if (copy_to_user(end, ses->auth_key.response, out.session_key_length)) {
0291 rc = -EINVAL;
0292 goto out;
0293 }
0294 end += out.session_key_length;
0295
0296 if (copy_to_user(end, ses->smb3encryptionkey, out.server_in_key_length)) {
0297 rc = -EINVAL;
0298 goto out;
0299 }
0300 end += out.server_in_key_length;
0301
0302 if (copy_to_user(end, ses->smb3decryptionkey, out.server_out_key_length)) {
0303 rc = -EINVAL;
0304 goto out;
0305 }
0306
0307 out:
0308 if (found)
0309 cifs_put_smb_ses(ses);
0310 return rc;
0311 }
0312
0313 long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
0314 {
0315 struct inode *inode = file_inode(filep);
0316 struct smb3_key_debug_info pkey_inf;
0317 int rc = -ENOTTY;
0318 unsigned int xid;
0319 struct cifsFileInfo *pSMBFile = filep->private_data;
0320 struct cifs_tcon *tcon;
0321 struct tcon_link *tlink;
0322 struct cifs_sb_info *cifs_sb;
0323 __u64 ExtAttrBits = 0;
0324 __u64 caps;
0325
0326 xid = get_xid();
0327
0328 cifs_dbg(FYI, "cifs ioctl 0x%x\n", command);
0329 switch (command) {
0330 case FS_IOC_GETFLAGS:
0331 if (pSMBFile == NULL)
0332 break;
0333 tcon = tlink_tcon(pSMBFile->tlink);
0334 caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
0335 #ifdef CONFIG_CIFS_POSIX
0336 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
0337 if (CIFS_UNIX_EXTATTR_CAP & caps) {
0338 __u64 ExtAttrMask = 0;
0339 rc = CIFSGetExtAttr(xid, tcon,
0340 pSMBFile->fid.netfid,
0341 &ExtAttrBits, &ExtAttrMask);
0342 if (rc == 0)
0343 rc = put_user(ExtAttrBits &
0344 FS_FL_USER_VISIBLE,
0345 (int __user *)arg);
0346 if (rc != EOPNOTSUPP)
0347 break;
0348 }
0349 #endif
0350 #endif
0351 rc = 0;
0352 if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED) {
0353
0354 ExtAttrBits = FS_COMPR_FL;
0355 rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE,
0356 (int __user *)arg);
0357 }
0358 break;
0359 case FS_IOC_SETFLAGS:
0360 if (pSMBFile == NULL)
0361 break;
0362 tcon = tlink_tcon(pSMBFile->tlink);
0363
0364
0365 if (get_user(ExtAttrBits, (int __user *)arg)) {
0366 rc = -EFAULT;
0367 break;
0368 }
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381 if ((ExtAttrBits & FS_COMPR_FL) == 0)
0382 break;
0383
0384
0385 if (tcon->ses->server->ops->set_compression) {
0386 rc = tcon->ses->server->ops->set_compression(
0387 xid, tcon, pSMBFile);
0388 cifs_dbg(FYI, "set compress flag rc %d\n", rc);
0389 }
0390 break;
0391 case CIFS_IOC_COPYCHUNK_FILE:
0392 rc = cifs_ioctl_copychunk(xid, filep, arg);
0393 break;
0394 case CIFS_QUERY_INFO:
0395 rc = cifs_ioctl_query_info(xid, filep, arg);
0396 break;
0397 case CIFS_IOC_SET_INTEGRITY:
0398 if (pSMBFile == NULL)
0399 break;
0400 tcon = tlink_tcon(pSMBFile->tlink);
0401 if (tcon->ses->server->ops->set_integrity)
0402 rc = tcon->ses->server->ops->set_integrity(xid,
0403 tcon, pSMBFile);
0404 else
0405 rc = -EOPNOTSUPP;
0406 break;
0407 case CIFS_IOC_GET_MNT_INFO:
0408 if (pSMBFile == NULL)
0409 break;
0410 tcon = tlink_tcon(pSMBFile->tlink);
0411 rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg);
0412 break;
0413 case CIFS_ENUMERATE_SNAPSHOTS:
0414 if (pSMBFile == NULL)
0415 break;
0416 if (arg == 0) {
0417 rc = -EINVAL;
0418 goto cifs_ioc_exit;
0419 }
0420 tcon = tlink_tcon(pSMBFile->tlink);
0421 if (tcon->ses->server->ops->enum_snapshots)
0422 rc = tcon->ses->server->ops->enum_snapshots(xid, tcon,
0423 pSMBFile, (void __user *)arg);
0424 else
0425 rc = -EOPNOTSUPP;
0426 break;
0427 case CIFS_DUMP_KEY:
0428
0429
0430
0431
0432 if (pSMBFile == NULL)
0433 break;
0434 if (!capable(CAP_SYS_ADMIN)) {
0435 rc = -EACCES;
0436 break;
0437 }
0438
0439 tcon = tlink_tcon(pSMBFile->tlink);
0440 if (!smb3_encryption_required(tcon)) {
0441 rc = -EOPNOTSUPP;
0442 break;
0443 }
0444 pkey_inf.cipher_type =
0445 le16_to_cpu(tcon->ses->server->cipher_type);
0446 pkey_inf.Suid = tcon->ses->Suid;
0447 memcpy(pkey_inf.auth_key, tcon->ses->auth_key.response,
0448 16 );
0449 memcpy(pkey_inf.smb3decryptionkey,
0450 tcon->ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE);
0451 memcpy(pkey_inf.smb3encryptionkey,
0452 tcon->ses->smb3encryptionkey, SMB3_SIGN_KEY_SIZE);
0453 if (copy_to_user((void __user *)arg, &pkey_inf,
0454 sizeof(struct smb3_key_debug_info)))
0455 rc = -EFAULT;
0456 else
0457 rc = 0;
0458 break;
0459 case CIFS_DUMP_FULL_KEY:
0460
0461
0462
0463 if (pSMBFile == NULL)
0464 break;
0465 if (!capable(CAP_SYS_ADMIN)) {
0466 rc = -EACCES;
0467 break;
0468 }
0469 tcon = tlink_tcon(pSMBFile->tlink);
0470 rc = cifs_dump_full_key(tcon, (void __user *)arg);
0471 break;
0472 case CIFS_IOC_NOTIFY:
0473 if (!S_ISDIR(inode->i_mode)) {
0474
0475 rc = -EOPNOTSUPP;
0476 break;
0477 }
0478 cifs_sb = CIFS_SB(inode->i_sb);
0479 tlink = cifs_sb_tlink(cifs_sb);
0480 if (IS_ERR(tlink)) {
0481 rc = PTR_ERR(tlink);
0482 break;
0483 }
0484 tcon = tlink_tcon(tlink);
0485 if (tcon && tcon->ses->server->ops->notify) {
0486 rc = tcon->ses->server->ops->notify(xid,
0487 filep, (void __user *)arg);
0488 cifs_dbg(FYI, "ioctl notify rc %d\n", rc);
0489 } else
0490 rc = -EOPNOTSUPP;
0491 cifs_put_tlink(tlink);
0492 break;
0493 case CIFS_IOC_SHUTDOWN:
0494 rc = cifs_shutdown(inode->i_sb, arg);
0495 break;
0496 default:
0497 cifs_dbg(FYI, "unsupported ioctl\n");
0498 break;
0499 }
0500 cifs_ioc_exit:
0501 free_xid(xid);
0502 return rc;
0503 }