• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  ioctl.c
4  *
5  *  Copyright (C) 1995, 1996 by Volker Lendecke
6  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7  *  Modified 1998, 1999 Wolfram Pienkoss for NLS
8  *
9  */
10 
11 #include <linux/capability.h>
12 #include <linux/compat.h>
13 #include <linux/errno.h>
14 #include <linux/fs.h>
15 #include <linux/ioctl.h>
16 #include <linux/time.h>
17 #include <linux/mm.h>
18 #include <linux/mount.h>
19 #include <linux/slab.h>
20 #include <linux/highuid.h>
21 #include <linux/vmalloc.h>
22 #include <linux/sched.h>
23 #include <linux/cred.h>
24 
25 #include <linux/uaccess.h>
26 
27 #include "ncp_fs.h"
28 
29 /* maximum limit for ncp_objectname_ioctl */
30 #define NCP_OBJECT_NAME_MAX_LEN	4096
31 /* maximum limit for ncp_privatedata_ioctl */
32 #define NCP_PRIVATE_DATA_MAX_LEN 8192
33 /* maximum negotiable packet size */
34 #define NCP_PACKET_SIZE_INTERNAL 65536
35 
36 static int
ncp_get_fs_info(struct ncp_server * server,struct inode * inode,struct ncp_fs_info __user * arg)37 ncp_get_fs_info(struct ncp_server * server, struct inode *inode,
38 		struct ncp_fs_info __user *arg)
39 {
40 	struct ncp_fs_info info;
41 
42 	if (copy_from_user(&info, arg, sizeof(info)))
43 		return -EFAULT;
44 
45 	if (info.version != NCP_GET_FS_INFO_VERSION) {
46 		ncp_dbg(1, "info.version invalid: %d\n", info.version);
47 		return -EINVAL;
48 	}
49 	/* TODO: info.addr = server->m.serv_addr; */
50 	SET_UID(info.mounted_uid, from_kuid_munged(current_user_ns(), server->m.mounted_uid));
51 	info.connection		= server->connection;
52 	info.buffer_size	= server->buffer_size;
53 	info.volume_number	= NCP_FINFO(inode)->volNumber;
54 	info.directory_id	= NCP_FINFO(inode)->DosDirNum;
55 
56 	if (copy_to_user(arg, &info, sizeof(info)))
57 		return -EFAULT;
58 	return 0;
59 }
60 
61 static int
ncp_get_fs_info_v2(struct ncp_server * server,struct inode * inode,struct ncp_fs_info_v2 __user * arg)62 ncp_get_fs_info_v2(struct ncp_server * server, struct inode *inode,
63 		   struct ncp_fs_info_v2 __user * arg)
64 {
65 	struct ncp_fs_info_v2 info2;
66 
67 	if (copy_from_user(&info2, arg, sizeof(info2)))
68 		return -EFAULT;
69 
70 	if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
71 		ncp_dbg(1, "info.version invalid: %d\n", info2.version);
72 		return -EINVAL;
73 	}
74 	info2.mounted_uid   = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
75 	info2.connection    = server->connection;
76 	info2.buffer_size   = server->buffer_size;
77 	info2.volume_number = NCP_FINFO(inode)->volNumber;
78 	info2.directory_id  = NCP_FINFO(inode)->DosDirNum;
79 	info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
80 
81 	if (copy_to_user(arg, &info2, sizeof(info2)))
82 		return -EFAULT;
83 	return 0;
84 }
85 
86 #ifdef CONFIG_COMPAT
87 struct compat_ncp_objectname_ioctl
88 {
89 	s32		auth_type;
90 	u32		object_name_len;
91 	compat_caddr_t	object_name;	/* a userspace data, in most cases user name */
92 };
93 
94 struct compat_ncp_fs_info_v2 {
95 	s32 version;
96 	u32 mounted_uid;
97 	u32 connection;
98 	u32 buffer_size;
99 
100 	u32 volume_number;
101 	u32 directory_id;
102 
103 	u32 dummy1;
104 	u32 dummy2;
105 	u32 dummy3;
106 };
107 
108 struct compat_ncp_ioctl_request {
109 	u32 function;
110 	u32 size;
111 	compat_caddr_t data;
112 };
113 
114 struct compat_ncp_privatedata_ioctl
115 {
116 	u32		len;
117 	compat_caddr_t	data;		/* ~1000 for NDS */
118 };
119 
120 #define NCP_IOC_GET_FS_INFO_V2_32	_IOWR('n', 4, struct compat_ncp_fs_info_v2)
121 #define NCP_IOC_NCPREQUEST_32		_IOR('n', 1, struct compat_ncp_ioctl_request)
122 #define NCP_IOC_GETOBJECTNAME_32	_IOWR('n', 9, struct compat_ncp_objectname_ioctl)
123 #define NCP_IOC_SETOBJECTNAME_32	_IOR('n', 9, struct compat_ncp_objectname_ioctl)
124 #define NCP_IOC_GETPRIVATEDATA_32	_IOWR('n', 10, struct compat_ncp_privatedata_ioctl)
125 #define NCP_IOC_SETPRIVATEDATA_32	_IOR('n', 10, struct compat_ncp_privatedata_ioctl)
126 
127 static int
ncp_get_compat_fs_info_v2(struct ncp_server * server,struct inode * inode,struct compat_ncp_fs_info_v2 __user * arg)128 ncp_get_compat_fs_info_v2(struct ncp_server * server, struct inode *inode,
129 		   struct compat_ncp_fs_info_v2 __user * arg)
130 {
131 	struct compat_ncp_fs_info_v2 info2;
132 
133 	if (copy_from_user(&info2, arg, sizeof(info2)))
134 		return -EFAULT;
135 
136 	if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
137 		ncp_dbg(1, "info.version invalid: %d\n", info2.version);
138 		return -EINVAL;
139 	}
140 	info2.mounted_uid   = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
141 	info2.connection    = server->connection;
142 	info2.buffer_size   = server->buffer_size;
143 	info2.volume_number = NCP_FINFO(inode)->volNumber;
144 	info2.directory_id  = NCP_FINFO(inode)->DosDirNum;
145 	info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
146 
147 	if (copy_to_user(arg, &info2, sizeof(info2)))
148 		return -EFAULT;
149 	return 0;
150 }
151 #endif
152 
153 #define NCP_IOC_GETMOUNTUID16		_IOW('n', 2, u16)
154 #define NCP_IOC_GETMOUNTUID32		_IOW('n', 2, u32)
155 #define NCP_IOC_GETMOUNTUID64		_IOW('n', 2, u64)
156 
157 #ifdef CONFIG_NCPFS_NLS
158 /* Here we are select the iocharset and the codepage for NLS.
159  * Thanks Petr Vandrovec for idea and many hints.
160  */
161 static int
ncp_set_charsets(struct ncp_server * server,struct ncp_nls_ioctl __user * arg)162 ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
163 {
164 	struct ncp_nls_ioctl user;
165 	struct nls_table *codepage;
166 	struct nls_table *iocharset;
167 	struct nls_table *oldset_io;
168 	struct nls_table *oldset_cp;
169 	int utf8;
170 	int err;
171 
172 	if (copy_from_user(&user, arg, sizeof(user)))
173 		return -EFAULT;
174 
175 	codepage = NULL;
176 	user.codepage[NCP_IOCSNAME_LEN] = 0;
177 	if (!user.codepage[0] || !strcmp(user.codepage, "default"))
178 		codepage = load_nls_default();
179 	else {
180 		codepage = load_nls(user.codepage);
181 		if (!codepage) {
182 			return -EBADRQC;
183 		}
184 	}
185 
186 	iocharset = NULL;
187 	user.iocharset[NCP_IOCSNAME_LEN] = 0;
188 	if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) {
189 		iocharset = load_nls_default();
190 		utf8 = 0;
191 	} else if (!strcmp(user.iocharset, "utf8")) {
192 		iocharset = load_nls_default();
193 		utf8 = 1;
194 	} else {
195 		iocharset = load_nls(user.iocharset);
196 		if (!iocharset) {
197 			unload_nls(codepage);
198 			return -EBADRQC;
199 		}
200 		utf8 = 0;
201 	}
202 
203 	mutex_lock(&server->root_setup_lock);
204 	if (server->root_setuped) {
205 		oldset_cp = codepage;
206 		oldset_io = iocharset;
207 		err = -EBUSY;
208 	} else {
209 		if (utf8)
210 			NCP_SET_FLAG(server, NCP_FLAG_UTF8);
211 		else
212 			NCP_CLR_FLAG(server, NCP_FLAG_UTF8);
213 		oldset_cp = server->nls_vol;
214 		server->nls_vol = codepage;
215 		oldset_io = server->nls_io;
216 		server->nls_io = iocharset;
217 		err = 0;
218 	}
219 	mutex_unlock(&server->root_setup_lock);
220 	unload_nls(oldset_cp);
221 	unload_nls(oldset_io);
222 
223 	return err;
224 }
225 
226 static int
ncp_get_charsets(struct ncp_server * server,struct ncp_nls_ioctl __user * arg)227 ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
228 {
229 	struct ncp_nls_ioctl user;
230 	int len;
231 
232 	memset(&user, 0, sizeof(user));
233 	mutex_lock(&server->root_setup_lock);
234 	if (server->nls_vol && server->nls_vol->charset) {
235 		len = strlen(server->nls_vol->charset);
236 		if (len > NCP_IOCSNAME_LEN)
237 			len = NCP_IOCSNAME_LEN;
238 		strncpy(user.codepage, server->nls_vol->charset, len);
239 		user.codepage[len] = 0;
240 	}
241 
242 	if (NCP_IS_FLAG(server, NCP_FLAG_UTF8))
243 		strcpy(user.iocharset, "utf8");
244 	else if (server->nls_io && server->nls_io->charset) {
245 		len = strlen(server->nls_io->charset);
246 		if (len > NCP_IOCSNAME_LEN)
247 			len = NCP_IOCSNAME_LEN;
248 		strncpy(user.iocharset,	server->nls_io->charset, len);
249 		user.iocharset[len] = 0;
250 	}
251 	mutex_unlock(&server->root_setup_lock);
252 
253 	if (copy_to_user(arg, &user, sizeof(user)))
254 		return -EFAULT;
255 	return 0;
256 }
257 #endif /* CONFIG_NCPFS_NLS */
258 
__ncp_ioctl(struct inode * inode,unsigned int cmd,unsigned long arg)259 static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg)
260 {
261 	struct ncp_server *server = NCP_SERVER(inode);
262 	int result;
263 	struct ncp_ioctl_request request;
264 	char* bouncebuffer;
265 	void __user *argp = (void __user *)arg;
266 
267 	switch (cmd) {
268 #ifdef CONFIG_COMPAT
269 	case NCP_IOC_NCPREQUEST_32:
270 #endif
271 	case NCP_IOC_NCPREQUEST:
272 #ifdef CONFIG_COMPAT
273 		if (cmd == NCP_IOC_NCPREQUEST_32) {
274 			struct compat_ncp_ioctl_request request32;
275 			if (copy_from_user(&request32, argp, sizeof(request32)))
276 				return -EFAULT;
277 			request.function = request32.function;
278 			request.size = request32.size;
279 			request.data = compat_ptr(request32.data);
280 		} else
281 #endif
282 		if (copy_from_user(&request, argp, sizeof(request)))
283 			return -EFAULT;
284 
285 		if ((request.function > 255)
286 		    || (request.size >
287 		  NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) {
288 			return -EINVAL;
289 		}
290 		bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL);
291 		if (!bouncebuffer)
292 			return -ENOMEM;
293 		if (copy_from_user(bouncebuffer, request.data, request.size)) {
294 			vfree(bouncebuffer);
295 			return -EFAULT;
296 		}
297 		ncp_lock_server(server);
298 
299 		/* FIXME: We hack around in the server's structures
300 		   here to be able to use ncp_request */
301 
302 		server->has_subfunction = 0;
303 		server->current_size = request.size;
304 		memcpy(server->packet, bouncebuffer, request.size);
305 
306 		result = ncp_request2(server, request.function,
307 			bouncebuffer, NCP_PACKET_SIZE_INTERNAL);
308 		if (result < 0)
309 			result = -EIO;
310 		else
311 			result = server->reply_size;
312 		ncp_unlock_server(server);
313 		ncp_dbg(1, "copy %d bytes\n", result);
314 		if (result >= 0)
315 			if (copy_to_user(request.data, bouncebuffer, result))
316 				result = -EFAULT;
317 		vfree(bouncebuffer);
318 		return result;
319 
320 	case NCP_IOC_CONN_LOGGED_IN:
321 
322 		if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE))
323 			return -EINVAL;
324 		mutex_lock(&server->root_setup_lock);
325 		if (server->root_setuped)
326 			result = -EBUSY;
327 		else {
328 			result = ncp_conn_logged_in(inode->i_sb);
329 			if (result == 0)
330 				server->root_setuped = 1;
331 		}
332 		mutex_unlock(&server->root_setup_lock);
333 		return result;
334 
335 	case NCP_IOC_GET_FS_INFO:
336 		return ncp_get_fs_info(server, inode, argp);
337 
338 	case NCP_IOC_GET_FS_INFO_V2:
339 		return ncp_get_fs_info_v2(server, inode, argp);
340 
341 #ifdef CONFIG_COMPAT
342 	case NCP_IOC_GET_FS_INFO_V2_32:
343 		return ncp_get_compat_fs_info_v2(server, inode, argp);
344 #endif
345 	/* we have too many combinations of CONFIG_COMPAT,
346 	 * CONFIG_64BIT and CONFIG_UID16, so just handle
347 	 * any of the possible ioctls */
348 	case NCP_IOC_GETMOUNTUID16:
349 		{
350 			u16 uid;
351 
352 			SET_UID(uid, from_kuid_munged(current_user_ns(), server->m.mounted_uid));
353 			if (put_user(uid, (u16 __user *)argp))
354 				return -EFAULT;
355 			return 0;
356 		}
357 	case NCP_IOC_GETMOUNTUID32:
358 	{
359 		uid_t uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
360 		if (put_user(uid, (u32 __user *)argp))
361 			return -EFAULT;
362 		return 0;
363 	}
364 	case NCP_IOC_GETMOUNTUID64:
365 	{
366 		uid_t uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
367 		if (put_user(uid, (u64 __user *)argp))
368 			return -EFAULT;
369 		return 0;
370 	}
371 	case NCP_IOC_GETROOT:
372 		{
373 			struct ncp_setroot_ioctl sr;
374 
375 			result = -EACCES;
376 			mutex_lock(&server->root_setup_lock);
377 			if (server->m.mounted_vol[0]) {
378 				struct dentry* dentry = inode->i_sb->s_root;
379 
380 				if (dentry) {
381 					struct inode* s_inode = d_inode(dentry);
382 
383 					if (s_inode) {
384 						sr.volNumber = NCP_FINFO(s_inode)->volNumber;
385 						sr.dirEntNum = NCP_FINFO(s_inode)->dirEntNum;
386 						sr.namespace = server->name_space[sr.volNumber];
387 						result = 0;
388 					} else
389 						ncp_dbg(1, "d_inode(s_root)==NULL\n");
390 				} else
391 					ncp_dbg(1, "s_root==NULL\n");
392 			} else {
393 				sr.volNumber = -1;
394 				sr.namespace = 0;
395 				sr.dirEntNum = 0;
396 				result = 0;
397 			}
398 			mutex_unlock(&server->root_setup_lock);
399 			if (!result && copy_to_user(argp, &sr, sizeof(sr)))
400 				result = -EFAULT;
401 			return result;
402 		}
403 
404 	case NCP_IOC_SETROOT:
405 		{
406 			struct ncp_setroot_ioctl sr;
407 			__u32 vnum;
408 			__le32 de;
409 			__le32 dosde;
410 			struct dentry* dentry;
411 
412 			if (copy_from_user(&sr, argp, sizeof(sr)))
413 				return -EFAULT;
414 			mutex_lock(&server->root_setup_lock);
415 			if (server->root_setuped)
416 				result = -EBUSY;
417 			else {
418 				if (sr.volNumber < 0) {
419 					server->m.mounted_vol[0] = 0;
420 					vnum = NCP_NUMBER_OF_VOLUMES;
421 					de = 0;
422 					dosde = 0;
423 					result = 0;
424 				} else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) {
425 					result = -EINVAL;
426 				} else if (ncp_mount_subdir(server, sr.volNumber,
427 							sr.namespace, sr.dirEntNum,
428 							&vnum, &de, &dosde)) {
429 					result = -ENOENT;
430 				} else
431 					result = 0;
432 
433 				if (result == 0) {
434 					dentry = inode->i_sb->s_root;
435 					if (dentry) {
436 						struct inode* s_inode = d_inode(dentry);
437 
438 						if (s_inode) {
439 							NCP_FINFO(s_inode)->volNumber = vnum;
440 							NCP_FINFO(s_inode)->dirEntNum = de;
441 							NCP_FINFO(s_inode)->DosDirNum = dosde;
442 							server->root_setuped = 1;
443 						} else {
444 							ncp_dbg(1, "d_inode(s_root)==NULL\n");
445 							result = -EIO;
446 						}
447 					} else {
448 						ncp_dbg(1, "s_root==NULL\n");
449 						result = -EIO;
450 					}
451 				}
452 			}
453 			mutex_unlock(&server->root_setup_lock);
454 
455 			return result;
456 		}
457 
458 #ifdef CONFIG_NCPFS_PACKET_SIGNING
459 	case NCP_IOC_SIGN_INIT:
460 		{
461 			struct ncp_sign_init sign;
462 
463 			if (argp)
464 				if (copy_from_user(&sign, argp, sizeof(sign)))
465 					return -EFAULT;
466 			ncp_lock_server(server);
467 			mutex_lock(&server->rcv.creq_mutex);
468 			if (argp) {
469 				if (server->sign_wanted) {
470 					memcpy(server->sign_root,sign.sign_root,8);
471 					memcpy(server->sign_last,sign.sign_last,16);
472 					server->sign_active = 1;
473 				}
474 				/* ignore when signatures not wanted */
475 			} else {
476 				server->sign_active = 0;
477 			}
478 			mutex_unlock(&server->rcv.creq_mutex);
479 			ncp_unlock_server(server);
480 			return 0;
481 		}
482 
483         case NCP_IOC_SIGN_WANTED:
484 		{
485 			int state;
486 
487 			ncp_lock_server(server);
488 			state = server->sign_wanted;
489 			ncp_unlock_server(server);
490 			if (put_user(state, (int __user *)argp))
491 				return -EFAULT;
492 			return 0;
493 		}
494 
495 	case NCP_IOC_SET_SIGN_WANTED:
496 		{
497 			int newstate;
498 
499 			/* get only low 8 bits... */
500 			if (get_user(newstate, (unsigned char __user *)argp))
501 				return -EFAULT;
502 			result = 0;
503 			ncp_lock_server(server);
504 			if (server->sign_active) {
505 				/* cannot turn signatures OFF when active */
506 				if (!newstate)
507 					result = -EINVAL;
508 			} else {
509 				server->sign_wanted = newstate != 0;
510 			}
511 			ncp_unlock_server(server);
512 			return result;
513 		}
514 
515 #endif /* CONFIG_NCPFS_PACKET_SIGNING */
516 
517 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
518 	case NCP_IOC_LOCKUNLOCK:
519 		{
520 			struct ncp_lock_ioctl	 rqdata;
521 
522 			if (copy_from_user(&rqdata, argp, sizeof(rqdata)))
523 				return -EFAULT;
524 			if (rqdata.origin != 0)
525 				return -EINVAL;
526 			/* check for cmd */
527 			switch (rqdata.cmd) {
528 				case NCP_LOCK_EX:
529 				case NCP_LOCK_SH:
530 						if (rqdata.timeout < 0)
531 							return -EINVAL;
532 						if (rqdata.timeout == 0)
533 							rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT;
534 						else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT)
535 							rqdata.timeout = NCP_LOCK_MAX_TIMEOUT;
536 						break;
537 				case NCP_LOCK_LOG:
538 						rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT;	/* has no effect */
539 				case NCP_LOCK_CLEAR:
540 						break;
541 				default:
542 						return -EINVAL;
543 			}
544 			/* locking needs both read and write access */
545 			if ((result = ncp_make_open(inode, O_RDWR)) != 0)
546 			{
547 				return result;
548 			}
549 			result = -EISDIR;
550 			if (!S_ISREG(inode->i_mode))
551 				goto outrel;
552 			if (rqdata.cmd == NCP_LOCK_CLEAR)
553 			{
554 				result = ncp_ClearPhysicalRecord(NCP_SERVER(inode),
555 							NCP_FINFO(inode)->file_handle,
556 							rqdata.offset,
557 							rqdata.length);
558 				if (result > 0) result = 0;	/* no such lock */
559 			}
560 			else
561 			{
562 				int lockcmd;
563 
564 				switch (rqdata.cmd)
565 				{
566 					case NCP_LOCK_EX:  lockcmd=1; break;
567 					case NCP_LOCK_SH:  lockcmd=3; break;
568 					default:	   lockcmd=0; break;
569 				}
570 				result = ncp_LogPhysicalRecord(NCP_SERVER(inode),
571 							NCP_FINFO(inode)->file_handle,
572 							lockcmd,
573 							rqdata.offset,
574 							rqdata.length,
575 							rqdata.timeout);
576 				if (result > 0) result = -EAGAIN;
577 			}
578 outrel:
579 			ncp_inode_close(inode);
580 			return result;
581 		}
582 #endif	/* CONFIG_NCPFS_IOCTL_LOCKING */
583 
584 #ifdef CONFIG_COMPAT
585 	case NCP_IOC_GETOBJECTNAME_32:
586 		{
587 			struct compat_ncp_objectname_ioctl user;
588 			size_t outl;
589 
590 			if (copy_from_user(&user, argp, sizeof(user)))
591 				return -EFAULT;
592 			down_read(&server->auth_rwsem);
593 			user.auth_type = server->auth.auth_type;
594 			outl = user.object_name_len;
595 			user.object_name_len = server->auth.object_name_len;
596 			if (outl > user.object_name_len)
597 				outl = user.object_name_len;
598 			result = 0;
599 			if (outl) {
600 				if (copy_to_user(compat_ptr(user.object_name),
601 						 server->auth.object_name,
602 						 outl))
603 					result = -EFAULT;
604 			}
605 			up_read(&server->auth_rwsem);
606 			if (!result && copy_to_user(argp, &user, sizeof(user)))
607 				result = -EFAULT;
608 			return result;
609 		}
610 #endif
611 
612 	case NCP_IOC_GETOBJECTNAME:
613 		{
614 			struct ncp_objectname_ioctl user;
615 			size_t outl;
616 
617 			if (copy_from_user(&user, argp, sizeof(user)))
618 				return -EFAULT;
619 			down_read(&server->auth_rwsem);
620 			user.auth_type = server->auth.auth_type;
621 			outl = user.object_name_len;
622 			user.object_name_len = server->auth.object_name_len;
623 			if (outl > user.object_name_len)
624 				outl = user.object_name_len;
625 			result = 0;
626 			if (outl) {
627 				if (copy_to_user(user.object_name,
628 						 server->auth.object_name,
629 						 outl))
630 					result = -EFAULT;
631 			}
632 			up_read(&server->auth_rwsem);
633 			if (!result && copy_to_user(argp, &user, sizeof(user)))
634 				result = -EFAULT;
635 			return result;
636 		}
637 
638 #ifdef CONFIG_COMPAT
639 	case NCP_IOC_SETOBJECTNAME_32:
640 #endif
641 	case NCP_IOC_SETOBJECTNAME:
642 		{
643 			struct ncp_objectname_ioctl user;
644 			void* newname;
645 			void* oldname;
646 			size_t oldnamelen;
647 			void* oldprivate;
648 			size_t oldprivatelen;
649 
650 #ifdef CONFIG_COMPAT
651 			if (cmd == NCP_IOC_SETOBJECTNAME_32) {
652 				struct compat_ncp_objectname_ioctl user32;
653 				if (copy_from_user(&user32, argp, sizeof(user32)))
654 					return -EFAULT;
655 				user.auth_type = user32.auth_type;
656 				user.object_name_len = user32.object_name_len;
657 				user.object_name = compat_ptr(user32.object_name);
658 			} else
659 #endif
660 			if (copy_from_user(&user, argp, sizeof(user)))
661 				return -EFAULT;
662 
663 			if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN)
664 				return -ENOMEM;
665 			if (user.object_name_len) {
666 				newname = memdup_user(user.object_name,
667 						      user.object_name_len);
668 				if (IS_ERR(newname))
669 					return PTR_ERR(newname);
670 			} else {
671 				newname = NULL;
672 			}
673 			down_write(&server->auth_rwsem);
674 			oldname = server->auth.object_name;
675 			oldnamelen = server->auth.object_name_len;
676 			oldprivate = server->priv.data;
677 			oldprivatelen = server->priv.len;
678 			server->auth.auth_type = user.auth_type;
679 			server->auth.object_name_len = user.object_name_len;
680 			server->auth.object_name = newname;
681 			server->priv.len = 0;
682 			server->priv.data = NULL;
683 			up_write(&server->auth_rwsem);
684 			kfree(oldprivate);
685 			kfree(oldname);
686 			return 0;
687 		}
688 
689 #ifdef CONFIG_COMPAT
690 	case NCP_IOC_GETPRIVATEDATA_32:
691 #endif
692 	case NCP_IOC_GETPRIVATEDATA:
693 		{
694 			struct ncp_privatedata_ioctl user;
695 			size_t outl;
696 
697 #ifdef CONFIG_COMPAT
698 			if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
699 				struct compat_ncp_privatedata_ioctl user32;
700 				if (copy_from_user(&user32, argp, sizeof(user32)))
701 					return -EFAULT;
702 				user.len = user32.len;
703 				user.data = compat_ptr(user32.data);
704 			} else
705 #endif
706 			if (copy_from_user(&user, argp, sizeof(user)))
707 				return -EFAULT;
708 
709 			down_read(&server->auth_rwsem);
710 			outl = user.len;
711 			user.len = server->priv.len;
712 			if (outl > user.len) outl = user.len;
713 			result = 0;
714 			if (outl) {
715 				if (copy_to_user(user.data,
716 						 server->priv.data,
717 						 outl))
718 					result = -EFAULT;
719 			}
720 			up_read(&server->auth_rwsem);
721 			if (result)
722 				return result;
723 #ifdef CONFIG_COMPAT
724 			if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
725 				struct compat_ncp_privatedata_ioctl user32;
726 				user32.len = user.len;
727 				user32.data = (unsigned long) user.data;
728 				if (copy_to_user(argp, &user32, sizeof(user32)))
729 					return -EFAULT;
730 			} else
731 #endif
732 			if (copy_to_user(argp, &user, sizeof(user)))
733 				return -EFAULT;
734 
735 			return 0;
736 		}
737 
738 #ifdef CONFIG_COMPAT
739 	case NCP_IOC_SETPRIVATEDATA_32:
740 #endif
741 	case NCP_IOC_SETPRIVATEDATA:
742 		{
743 			struct ncp_privatedata_ioctl user;
744 			void* new;
745 			void* old;
746 			size_t oldlen;
747 
748 #ifdef CONFIG_COMPAT
749 			if (cmd == NCP_IOC_SETPRIVATEDATA_32) {
750 				struct compat_ncp_privatedata_ioctl user32;
751 				if (copy_from_user(&user32, argp, sizeof(user32)))
752 					return -EFAULT;
753 				user.len = user32.len;
754 				user.data = compat_ptr(user32.data);
755 			} else
756 #endif
757 			if (copy_from_user(&user, argp, sizeof(user)))
758 				return -EFAULT;
759 
760 			if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
761 				return -ENOMEM;
762 			if (user.len) {
763 				new = memdup_user(user.data, user.len);
764 				if (IS_ERR(new))
765 					return PTR_ERR(new);
766 			} else {
767 				new = NULL;
768 			}
769 			down_write(&server->auth_rwsem);
770 			old = server->priv.data;
771 			oldlen = server->priv.len;
772 			server->priv.len = user.len;
773 			server->priv.data = new;
774 			up_write(&server->auth_rwsem);
775 			kfree(old);
776 			return 0;
777 		}
778 
779 #ifdef CONFIG_NCPFS_NLS
780 	case NCP_IOC_SETCHARSETS:
781 		return ncp_set_charsets(server, argp);
782 
783 	case NCP_IOC_GETCHARSETS:
784 		return ncp_get_charsets(server, argp);
785 
786 #endif /* CONFIG_NCPFS_NLS */
787 
788 	case NCP_IOC_SETDENTRYTTL:
789 		{
790 			u_int32_t user;
791 
792 			if (copy_from_user(&user, argp, sizeof(user)))
793 				return -EFAULT;
794 			/* 20 secs at most... */
795 			if (user > 20000)
796 				return -EINVAL;
797 			user = (user * HZ) / 1000;
798 			atomic_set(&server->dentry_ttl, user);
799 			return 0;
800 		}
801 
802 	case NCP_IOC_GETDENTRYTTL:
803 		{
804 			u_int32_t user = (atomic_read(&server->dentry_ttl) * 1000) / HZ;
805 			if (copy_to_user(argp, &user, sizeof(user)))
806 				return -EFAULT;
807 			return 0;
808 		}
809 
810 	}
811 	return -EINVAL;
812 }
813 
ncp_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)814 long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
815 {
816 	struct inode *inode = file_inode(filp);
817 	struct ncp_server *server = NCP_SERVER(inode);
818 	kuid_t uid = current_uid();
819 	int need_drop_write = 0;
820 	long ret;
821 
822 	switch (cmd) {
823 	case NCP_IOC_SETCHARSETS:
824 	case NCP_IOC_CONN_LOGGED_IN:
825 	case NCP_IOC_SETROOT:
826 		if (!capable(CAP_SYS_ADMIN)) {
827 			ret = -EPERM;
828 			goto out;
829 		}
830 		break;
831 	}
832 	if (!uid_eq(server->m.mounted_uid, uid)) {
833 		switch (cmd) {
834 		/*
835 		 * Only mount owner can issue these ioctls.  Information
836 		 * necessary to authenticate to other NDS servers are
837 		 * stored here.
838 		 */
839 		case NCP_IOC_GETOBJECTNAME:
840 		case NCP_IOC_SETOBJECTNAME:
841 		case NCP_IOC_GETPRIVATEDATA:
842 		case NCP_IOC_SETPRIVATEDATA:
843 #ifdef CONFIG_COMPAT
844 		case NCP_IOC_GETOBJECTNAME_32:
845 		case NCP_IOC_SETOBJECTNAME_32:
846 		case NCP_IOC_GETPRIVATEDATA_32:
847 		case NCP_IOC_SETPRIVATEDATA_32:
848 #endif
849 			ret = -EACCES;
850 			goto out;
851 		/*
852 		 * These require write access on the inode if user id
853 		 * does not match.  Note that they do not write to the
854 		 * file...  But old code did mnt_want_write, so I keep
855 		 * it as is.  Of course not for mountpoint owner, as
856 		 * that breaks read-only mounts altogether as ncpmount
857 		 * needs working NCP_IOC_NCPREQUEST and
858 		 * NCP_IOC_GET_FS_INFO.  Some of these codes (setdentryttl,
859 		 * signinit, setsignwanted) should be probably restricted
860 		 * to owner only, or even more to CAP_SYS_ADMIN).
861 		 */
862 		case NCP_IOC_GET_FS_INFO:
863 		case NCP_IOC_GET_FS_INFO_V2:
864 		case NCP_IOC_NCPREQUEST:
865 		case NCP_IOC_SETDENTRYTTL:
866 		case NCP_IOC_SIGN_INIT:
867 		case NCP_IOC_LOCKUNLOCK:
868 		case NCP_IOC_SET_SIGN_WANTED:
869 #ifdef CONFIG_COMPAT
870 		case NCP_IOC_GET_FS_INFO_V2_32:
871 		case NCP_IOC_NCPREQUEST_32:
872 #endif
873 			ret = mnt_want_write_file(filp);
874 			if (ret)
875 				goto out;
876 			need_drop_write = 1;
877 			ret = inode_permission(inode, MAY_WRITE);
878 			if (ret)
879 				goto outDropWrite;
880 			break;
881 		/*
882 		 * Read access required.
883 		 */
884 		case NCP_IOC_GETMOUNTUID16:
885 		case NCP_IOC_GETMOUNTUID32:
886 		case NCP_IOC_GETMOUNTUID64:
887 		case NCP_IOC_GETROOT:
888 		case NCP_IOC_SIGN_WANTED:
889 			ret = inode_permission(inode, MAY_READ);
890 			if (ret)
891 				goto out;
892 			break;
893 		/*
894 		 * Anybody can read these.
895 		 */
896 		case NCP_IOC_GETCHARSETS:
897 		case NCP_IOC_GETDENTRYTTL:
898 		default:
899 		/* Three codes below are protected by CAP_SYS_ADMIN above. */
900 		case NCP_IOC_SETCHARSETS:
901 		case NCP_IOC_CONN_LOGGED_IN:
902 		case NCP_IOC_SETROOT:
903 			break;
904 		}
905 	}
906 	ret = __ncp_ioctl(inode, cmd, arg);
907 outDropWrite:
908 	if (need_drop_write)
909 		mnt_drop_write_file(filp);
910 out:
911 	return ret;
912 }
913 
914 #ifdef CONFIG_COMPAT
ncp_compat_ioctl(struct file * file,unsigned int cmd,unsigned long arg)915 long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
916 {
917 	long ret;
918 
919 	arg = (unsigned long) compat_ptr(arg);
920 	ret = ncp_ioctl(file, cmd, arg);
921 	return ret;
922 }
923 #endif
924