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