diff options
Diffstat (limited to 'fs/ncpfs/ioctl.c')
-rw-r--r-- | fs/ncpfs/ioctl.c | 239 |
1 files changed, 210 insertions, 29 deletions
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 42039fe0653c..a89ac84a8241 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c | |||
@@ -7,19 +7,21 @@ | |||
7 | * | 7 | * |
8 | */ | 8 | */ |
9 | 9 | ||
10 | |||
11 | #include <asm/uaccess.h> | ||
12 | #include <linux/capability.h> | 10 | #include <linux/capability.h> |
11 | #include <linux/compat.h> | ||
13 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
14 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
15 | #include <linux/ioctl.h> | 14 | #include <linux/ioctl.h> |
16 | #include <linux/time.h> | 15 | #include <linux/time.h> |
17 | #include <linux/mm.h> | 16 | #include <linux/mm.h> |
18 | #include <linux/highuid.h> | 17 | #include <linux/highuid.h> |
18 | #include <linux/smp_lock.h> | ||
19 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
20 | 20 | ||
21 | #include <linux/ncp_fs.h> | 21 | #include <linux/ncp_fs.h> |
22 | 22 | ||
23 | #include <asm/uaccess.h> | ||
24 | |||
23 | #include "ncplib_kernel.h" | 25 | #include "ncplib_kernel.h" |
24 | 26 | ||
25 | /* maximum limit for ncp_objectname_ioctl */ | 27 | /* maximum limit for ncp_objectname_ioctl */ |
@@ -89,6 +91,82 @@ ncp_get_fs_info_v2(struct ncp_server * server, struct file *file, | |||
89 | return 0; | 91 | return 0; |
90 | } | 92 | } |
91 | 93 | ||
94 | #ifdef CONFIG_COMPAT | ||
95 | struct compat_ncp_objectname_ioctl | ||
96 | { | ||
97 | s32 auth_type; | ||
98 | u32 object_name_len; | ||
99 | compat_caddr_t object_name; /* an userspace data, in most cases user name */ | ||
100 | }; | ||
101 | |||
102 | struct compat_ncp_fs_info_v2 { | ||
103 | s32 version; | ||
104 | u32 mounted_uid; | ||
105 | u32 connection; | ||
106 | u32 buffer_size; | ||
107 | |||
108 | u32 volume_number; | ||
109 | u32 directory_id; | ||
110 | |||
111 | u32 dummy1; | ||
112 | u32 dummy2; | ||
113 | u32 dummy3; | ||
114 | }; | ||
115 | |||
116 | struct compat_ncp_ioctl_request { | ||
117 | u32 function; | ||
118 | u32 size; | ||
119 | compat_caddr_t data; | ||
120 | }; | ||
121 | |||
122 | struct compat_ncp_privatedata_ioctl | ||
123 | { | ||
124 | u32 len; | ||
125 | compat_caddr_t data; /* ~1000 for NDS */ | ||
126 | }; | ||
127 | |||
128 | #define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct compat_ncp_fs_info_v2) | ||
129 | #define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct compat_ncp_ioctl_request) | ||
130 | #define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct compat_ncp_objectname_ioctl) | ||
131 | #define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct compat_ncp_objectname_ioctl) | ||
132 | #define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct compat_ncp_privatedata_ioctl) | ||
133 | #define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl) | ||
134 | |||
135 | static int | ||
136 | ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file, | ||
137 | struct compat_ncp_fs_info_v2 __user * arg) | ||
138 | { | ||
139 | struct inode *inode = file->f_dentry->d_inode; | ||
140 | struct compat_ncp_fs_info_v2 info2; | ||
141 | |||
142 | if ((file_permission(file, MAY_WRITE) != 0) | ||
143 | && (current->uid != server->m.mounted_uid)) { | ||
144 | return -EACCES; | ||
145 | } | ||
146 | if (copy_from_user(&info2, arg, sizeof(info2))) | ||
147 | return -EFAULT; | ||
148 | |||
149 | if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { | ||
150 | DPRINTK("info.version invalid: %d\n", info2.version); | ||
151 | return -EINVAL; | ||
152 | } | ||
153 | info2.mounted_uid = server->m.mounted_uid; | ||
154 | info2.connection = server->connection; | ||
155 | info2.buffer_size = server->buffer_size; | ||
156 | info2.volume_number = NCP_FINFO(inode)->volNumber; | ||
157 | info2.directory_id = NCP_FINFO(inode)->DosDirNum; | ||
158 | info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; | ||
159 | |||
160 | if (copy_to_user(arg, &info2, sizeof(info2))) | ||
161 | return -EFAULT; | ||
162 | return 0; | ||
163 | } | ||
164 | #endif | ||
165 | |||
166 | #define NCP_IOC_GETMOUNTUID16 _IOW('n', 2, u16) | ||
167 | #define NCP_IOC_GETMOUNTUID32 _IOW('n', 2, u32) | ||
168 | #define NCP_IOC_GETMOUNTUID64 _IOW('n', 2, u64) | ||
169 | |||
92 | #ifdef CONFIG_NCPFS_NLS | 170 | #ifdef CONFIG_NCPFS_NLS |
93 | /* Here we are select the iocharset and the codepage for NLS. | 171 | /* Here we are select the iocharset and the codepage for NLS. |
94 | * Thanks Petr Vandrovec for idea and many hints. | 172 | * Thanks Petr Vandrovec for idea and many hints. |
@@ -192,12 +270,24 @@ int ncp_ioctl(struct inode *inode, struct file *filp, | |||
192 | void __user *argp = (void __user *)arg; | 270 | void __user *argp = (void __user *)arg; |
193 | 271 | ||
194 | switch (cmd) { | 272 | switch (cmd) { |
273 | #ifdef CONFIG_COMPAT | ||
274 | case NCP_IOC_NCPREQUEST_32: | ||
275 | #endif | ||
195 | case NCP_IOC_NCPREQUEST: | 276 | case NCP_IOC_NCPREQUEST: |
196 | |||
197 | if ((file_permission(filp, MAY_WRITE) != 0) | 277 | if ((file_permission(filp, MAY_WRITE) != 0) |
198 | && (current->uid != server->m.mounted_uid)) { | 278 | && (current->uid != server->m.mounted_uid)) { |
199 | return -EACCES; | 279 | return -EACCES; |
200 | } | 280 | } |
281 | #ifdef CONFIG_COMPAT | ||
282 | if (cmd == NCP_IOC_NCPREQUEST_32) { | ||
283 | struct compat_ncp_ioctl_request request32; | ||
284 | if (copy_from_user(&request32, argp, sizeof(request32))) | ||
285 | return -EFAULT; | ||
286 | request.function = request32.function; | ||
287 | request.size = request32.size; | ||
288 | request.data = compat_ptr(request32.data); | ||
289 | } else | ||
290 | #endif | ||
201 | if (copy_from_user(&request, argp, sizeof(request))) | 291 | if (copy_from_user(&request, argp, sizeof(request))) |
202 | return -EFAULT; | 292 | return -EFAULT; |
203 | 293 | ||
@@ -254,19 +344,35 @@ int ncp_ioctl(struct inode *inode, struct file *filp, | |||
254 | case NCP_IOC_GET_FS_INFO_V2: | 344 | case NCP_IOC_GET_FS_INFO_V2: |
255 | return ncp_get_fs_info_v2(server, filp, argp); | 345 | return ncp_get_fs_info_v2(server, filp, argp); |
256 | 346 | ||
257 | case NCP_IOC_GETMOUNTUID2: | 347 | #ifdef CONFIG_COMPAT |
258 | { | 348 | case NCP_IOC_GET_FS_INFO_V2_32: |
259 | unsigned long tmp = server->m.mounted_uid; | 349 | return ncp_get_compat_fs_info_v2(server, filp, argp); |
260 | 350 | #endif | |
261 | if ((file_permission(filp, MAY_READ) != 0) | 351 | /* we have too many combinations of CONFIG_COMPAT, |
262 | && (current->uid != server->m.mounted_uid)) | 352 | * CONFIG_64BIT and CONFIG_UID16, so just handle |
263 | { | 353 | * any of the possible ioctls */ |
264 | return -EACCES; | 354 | case NCP_IOC_GETMOUNTUID16: |
265 | } | 355 | case NCP_IOC_GETMOUNTUID32: |
266 | if (put_user(tmp, (unsigned long __user *)argp)) | 356 | case NCP_IOC_GETMOUNTUID64: |
357 | if ((file_permission(filp, MAY_READ) != 0) | ||
358 | && (current->uid != server->m.mounted_uid)) { | ||
359 | return -EACCES; | ||
360 | } | ||
361 | if (cmd == NCP_IOC_GETMOUNTUID16) { | ||
362 | u16 uid; | ||
363 | SET_UID(uid, server->m.mounted_uid); | ||
364 | if (put_user(uid, (u16 __user *)argp)) | ||
365 | return -EFAULT; | ||
366 | } else if (cmd == NCP_IOC_GETMOUNTUID32) { | ||
367 | if (put_user(server->m.mounted_uid, | ||
368 | (u32 __user *)argp)) | ||
369 | return -EFAULT; | ||
370 | } else { | ||
371 | if (put_user(server->m.mounted_uid, | ||
372 | (u64 __user *)argp)) | ||
267 | return -EFAULT; | 373 | return -EFAULT; |
268 | return 0; | ||
269 | } | 374 | } |
375 | return 0; | ||
270 | 376 | ||
271 | case NCP_IOC_GETROOT: | 377 | case NCP_IOC_GETROOT: |
272 | { | 378 | { |
@@ -476,6 +582,32 @@ outrel: | |||
476 | } | 582 | } |
477 | #endif /* CONFIG_NCPFS_IOCTL_LOCKING */ | 583 | #endif /* CONFIG_NCPFS_IOCTL_LOCKING */ |
478 | 584 | ||
585 | #ifdef CONFIG_COMPAT | ||
586 | case NCP_IOC_GETOBJECTNAME_32: | ||
587 | if (current->uid != server->m.mounted_uid) { | ||
588 | return -EACCES; | ||
589 | } | ||
590 | { | ||
591 | struct compat_ncp_objectname_ioctl user; | ||
592 | size_t outl; | ||
593 | |||
594 | if (copy_from_user(&user, argp, sizeof(user))) | ||
595 | return -EFAULT; | ||
596 | user.auth_type = server->auth.auth_type; | ||
597 | outl = user.object_name_len; | ||
598 | user.object_name_len = server->auth.object_name_len; | ||
599 | if (outl > user.object_name_len) | ||
600 | outl = user.object_name_len; | ||
601 | if (outl) { | ||
602 | if (copy_to_user(compat_ptr(user.object_name), | ||
603 | server->auth.object_name, | ||
604 | outl)) return -EFAULT; | ||
605 | } | ||
606 | if (copy_to_user(argp, &user, sizeof(user))) | ||
607 | return -EFAULT; | ||
608 | return 0; | ||
609 | } | ||
610 | #endif | ||
479 | case NCP_IOC_GETOBJECTNAME: | 611 | case NCP_IOC_GETOBJECTNAME: |
480 | if (current->uid != server->m.mounted_uid) { | 612 | if (current->uid != server->m.mounted_uid) { |
481 | return -EACCES; | 613 | return -EACCES; |
@@ -500,6 +632,9 @@ outrel: | |||
500 | return -EFAULT; | 632 | return -EFAULT; |
501 | return 0; | 633 | return 0; |
502 | } | 634 | } |
635 | #ifdef CONFIG_COMPAT | ||
636 | case NCP_IOC_SETOBJECTNAME_32: | ||
637 | #endif | ||
503 | case NCP_IOC_SETOBJECTNAME: | 638 | case NCP_IOC_SETOBJECTNAME: |
504 | if (current->uid != server->m.mounted_uid) { | 639 | if (current->uid != server->m.mounted_uid) { |
505 | return -EACCES; | 640 | return -EACCES; |
@@ -512,8 +647,19 @@ outrel: | |||
512 | void* oldprivate; | 647 | void* oldprivate; |
513 | size_t oldprivatelen; | 648 | size_t oldprivatelen; |
514 | 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 | ||
515 | if (copy_from_user(&user, argp, sizeof(user))) | 660 | if (copy_from_user(&user, argp, sizeof(user))) |
516 | return -EFAULT; | 661 | return -EFAULT; |
662 | |||
517 | if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN) | 663 | if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN) |
518 | return -ENOMEM; | 664 | return -ENOMEM; |
519 | if (user.object_name_len) { | 665 | if (user.object_name_len) { |
@@ -544,6 +690,9 @@ outrel: | |||
544 | kfree(oldname); | 690 | kfree(oldname); |
545 | return 0; | 691 | return 0; |
546 | } | 692 | } |
693 | #ifdef CONFIG_COMPAT | ||
694 | case NCP_IOC_GETPRIVATEDATA_32: | ||
695 | #endif | ||
547 | case NCP_IOC_GETPRIVATEDATA: | 696 | case NCP_IOC_GETPRIVATEDATA: |
548 | if (current->uid != server->m.mounted_uid) { | 697 | if (current->uid != server->m.mounted_uid) { |
549 | return -EACCES; | 698 | return -EACCES; |
@@ -552,8 +701,18 @@ outrel: | |||
552 | struct ncp_privatedata_ioctl user; | 701 | struct ncp_privatedata_ioctl user; |
553 | size_t outl; | 702 | size_t outl; |
554 | 703 | ||
704 | #ifdef CONFIG_COMPAT | ||
705 | if (cmd == NCP_IOC_GETPRIVATEDATA_32) { | ||
706 | struct compat_ncp_privatedata_ioctl user32; | ||
707 | if (copy_from_user(&user32, argp, sizeof(user32))) | ||
708 | return -EFAULT; | ||
709 | user.len = user32.len; | ||
710 | user.data = compat_ptr(user32.data); | ||
711 | } else | ||
712 | #endif | ||
555 | if (copy_from_user(&user, argp, sizeof(user))) | 713 | if (copy_from_user(&user, argp, sizeof(user))) |
556 | return -EFAULT; | 714 | return -EFAULT; |
715 | |||
557 | outl = user.len; | 716 | outl = user.len; |
558 | user.len = server->priv.len; | 717 | user.len = server->priv.len; |
559 | if (outl > user.len) outl = user.len; | 718 | if (outl > user.len) outl = user.len; |
@@ -562,10 +721,23 @@ outrel: | |||
562 | server->priv.data, | 721 | server->priv.data, |
563 | outl)) return -EFAULT; | 722 | outl)) return -EFAULT; |
564 | } | 723 | } |
724 | #ifdef CONFIG_COMPAT | ||
725 | if (cmd == NCP_IOC_GETPRIVATEDATA_32) { | ||
726 | struct compat_ncp_privatedata_ioctl user32; | ||
727 | user32.len = user.len; | ||
728 | user32.data = (unsigned long) user.data; | ||
729 | if (copy_to_user(&user32, argp, sizeof(user32))) | ||
730 | return -EFAULT; | ||
731 | } else | ||
732 | #endif | ||
565 | if (copy_to_user(argp, &user, sizeof(user))) | 733 | if (copy_to_user(argp, &user, sizeof(user))) |
566 | return -EFAULT; | 734 | return -EFAULT; |
735 | |||
567 | return 0; | 736 | return 0; |
568 | } | 737 | } |
738 | #ifdef CONFIG_COMPAT | ||
739 | case NCP_IOC_SETPRIVATEDATA_32: | ||
740 | #endif | ||
569 | case NCP_IOC_SETPRIVATEDATA: | 741 | case NCP_IOC_SETPRIVATEDATA: |
570 | if (current->uid != server->m.mounted_uid) { | 742 | if (current->uid != server->m.mounted_uid) { |
571 | return -EACCES; | 743 | return -EACCES; |
@@ -576,8 +748,18 @@ outrel: | |||
576 | void* old; | 748 | void* old; |
577 | size_t oldlen; | 749 | size_t oldlen; |
578 | 750 | ||
751 | #ifdef CONFIG_COMPAT | ||
752 | if (cmd == NCP_IOC_SETPRIVATEDATA_32) { | ||
753 | struct compat_ncp_privatedata_ioctl user32; | ||
754 | if (copy_from_user(&user32, argp, sizeof(user32))) | ||
755 | return -EFAULT; | ||
756 | user.len = user32.len; | ||
757 | user.data = compat_ptr(user32.data); | ||
758 | } else | ||
759 | #endif | ||
579 | if (copy_from_user(&user, argp, sizeof(user))) | 760 | if (copy_from_user(&user, argp, sizeof(user))) |
580 | return -EFAULT; | 761 | return -EFAULT; |
762 | |||
581 | if (user.len > NCP_PRIVATE_DATA_MAX_LEN) | 763 | if (user.len > NCP_PRIVATE_DATA_MAX_LEN) |
582 | return -ENOMEM; | 764 | return -ENOMEM; |
583 | if (user.len) { | 765 | if (user.len) { |
@@ -636,20 +818,19 @@ outrel: | |||
636 | } | 818 | } |
637 | 819 | ||
638 | } | 820 | } |
639 | /* #ifdef CONFIG_UID16 */ | ||
640 | /* NCP_IOC_GETMOUNTUID may be same as NCP_IOC_GETMOUNTUID2, | ||
641 | so we have this out of switch */ | ||
642 | if (cmd == NCP_IOC_GETMOUNTUID) { | ||
643 | __kernel_uid_t uid = 0; | ||
644 | if ((file_permission(filp, MAY_READ) != 0) | ||
645 | && (current->uid != server->m.mounted_uid)) { | ||
646 | return -EACCES; | ||
647 | } | ||
648 | SET_UID(uid, server->m.mounted_uid); | ||
649 | if (put_user(uid, (__kernel_uid_t __user *)argp)) | ||
650 | return -EFAULT; | ||
651 | return 0; | ||
652 | } | ||
653 | /* #endif */ | ||
654 | return -EINVAL; | 821 | return -EINVAL; |
655 | } | 822 | } |
823 | |||
824 | #ifdef CONFIG_COMPAT | ||
825 | long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
826 | { | ||
827 | struct inode *inode = file->f_dentry->d_inode; | ||
828 | int ret; | ||
829 | |||
830 | lock_kernel(); | ||
831 | arg = (unsigned long) compat_ptr(arg); | ||
832 | ret = ncp_ioctl(inode, file, cmd, arg); | ||
833 | unlock_kernel(); | ||
834 | return ret; | ||
835 | } | ||
836 | #endif | ||