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