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