summaryrefslogtreecommitdiff
path: root/fs/ncpfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ncpfs')
-rw-r--r--fs/ncpfs/dir.c3
-rw-r--r--fs/ncpfs/file.c3
-rw-r--r--fs/ncpfs/ioctl.c239
3 files changed, 216 insertions, 29 deletions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index b4ee89250e95..458b3b785194 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -53,6 +53,9 @@ const struct file_operations ncp_dir_operations =
.read = generic_read_dir,
.readdir = ncp_readdir,
.ioctl = ncp_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ncp_compat_ioctl,
+#endif
};
struct inode_operations ncp_dir_inode_operations =
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index e6b7c67cf057..df37524b85db 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -289,6 +289,9 @@ const struct file_operations ncp_file_operations =
.read = ncp_file_read,
.write = ncp_file_write,
.ioctl = ncp_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ncp_compat_ioctl,
+#endif
.mmap = ncp_mmap,
.release = ncp_release,
.fsync = ncp_fsync,
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 @@
*
*/
-
-#include <asm/uaccess.h>
#include <linux/capability.h>
+#include <linux/compat.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/highuid.h>
+#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/ncp_fs.h>
+#include <asm/uaccess.h>
+
#include "ncplib_kernel.h"
/* maximum limit for ncp_objectname_ioctl */
@@ -89,6 +91,82 @@ ncp_get_fs_info_v2(struct ncp_server * server, struct file *file,
return 0;
}
+#ifdef CONFIG_COMPAT
+struct compat_ncp_objectname_ioctl
+{
+ s32 auth_type;
+ u32 object_name_len;
+ compat_caddr_t object_name; /* an userspace data, in most cases user name */
+};
+
+struct compat_ncp_fs_info_v2 {
+ s32 version;
+ u32 mounted_uid;
+ u32 connection;
+ u32 buffer_size;
+
+ u32 volume_number;
+ u32 directory_id;
+
+ u32 dummy1;
+ u32 dummy2;
+ u32 dummy3;
+};
+
+struct compat_ncp_ioctl_request {
+ u32 function;
+ u32 size;
+ compat_caddr_t data;
+};
+
+struct compat_ncp_privatedata_ioctl
+{
+ u32 len;
+ compat_caddr_t data; /* ~1000 for NDS */
+};
+
+#define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct compat_ncp_fs_info_v2)
+#define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct compat_ncp_ioctl_request)
+#define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct compat_ncp_objectname_ioctl)
+#define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct compat_ncp_objectname_ioctl)
+#define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct compat_ncp_privatedata_ioctl)
+#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl)
+
+static int
+ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file,
+ struct compat_ncp_fs_info_v2 __user * arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct compat_ncp_fs_info_v2 info2;
+
+ if ((file_permission(file, MAY_WRITE) != 0)
+ && (current->uid != server->m.mounted_uid)) {
+ return -EACCES;
+ }
+ if (copy_from_user(&info2, arg, sizeof(info2)))
+ return -EFAULT;
+
+ if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
+ DPRINTK("info.version invalid: %d\n", info2.version);
+ return -EINVAL;
+ }
+ info2.mounted_uid = server->m.mounted_uid;
+ info2.connection = server->connection;
+ info2.buffer_size = server->buffer_size;
+ info2.volume_number = NCP_FINFO(inode)->volNumber;
+ info2.directory_id = NCP_FINFO(inode)->DosDirNum;
+ info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
+
+ if (copy_to_user(arg, &info2, sizeof(info2)))
+ return -EFAULT;
+ return 0;
+}
+#endif
+
+#define NCP_IOC_GETMOUNTUID16 _IOW('n', 2, u16)
+#define NCP_IOC_GETMOUNTUID32 _IOW('n', 2, u32)
+#define NCP_IOC_GETMOUNTUID64 _IOW('n', 2, u64)
+
#ifdef CONFIG_NCPFS_NLS
/* Here we are select the iocharset and the codepage for NLS.
* Thanks Petr Vandrovec for idea and many hints.
@@ -192,12 +270,24 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
void __user *argp = (void __user *)arg;
switch (cmd) {
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_NCPREQUEST_32:
+#endif
case NCP_IOC_NCPREQUEST:
-
if ((file_permission(filp, MAY_WRITE) != 0)
&& (current->uid != server->m.mounted_uid)) {
return -EACCES;
}
+#ifdef CONFIG_COMPAT
+ if (cmd == NCP_IOC_NCPREQUEST_32) {
+ struct compat_ncp_ioctl_request request32;
+ if (copy_from_user(&request32, argp, sizeof(request32)))
+ return -EFAULT;
+ request.function = request32.function;
+ request.size = request32.size;
+ request.data = compat_ptr(request32.data);
+ } else
+#endif
if (copy_from_user(&request, argp, sizeof(request)))
return -EFAULT;
@@ -254,19 +344,35 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
case NCP_IOC_GET_FS_INFO_V2:
return ncp_get_fs_info_v2(server, filp, argp);
- case NCP_IOC_GETMOUNTUID2:
- {
- unsigned long tmp = server->m.mounted_uid;
-
- if ((file_permission(filp, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid))
- {
- return -EACCES;
- }
- if (put_user(tmp, (unsigned long __user *)argp))
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_GET_FS_INFO_V2_32:
+ return ncp_get_compat_fs_info_v2(server, filp, argp);
+#endif
+ /* we have too many combinations of CONFIG_COMPAT,
+ * CONFIG_64BIT and CONFIG_UID16, so just handle
+ * any of the possible ioctls */
+ case NCP_IOC_GETMOUNTUID16:
+ case NCP_IOC_GETMOUNTUID32:
+ case NCP_IOC_GETMOUNTUID64:
+ if ((file_permission(filp, MAY_READ) != 0)
+ && (current->uid != server->m.mounted_uid)) {
+ return -EACCES;
+ }
+ if (cmd == NCP_IOC_GETMOUNTUID16) {
+ u16 uid;
+ SET_UID(uid, server->m.mounted_uid);
+ if (put_user(uid, (u16 __user *)argp))
+ return -EFAULT;
+ } else if (cmd == NCP_IOC_GETMOUNTUID32) {
+ if (put_user(server->m.mounted_uid,
+ (u32 __user *)argp))
+ return -EFAULT;
+ } else {
+ if (put_user(server->m.mounted_uid,
+ (u64 __user *)argp))
return -EFAULT;
- return 0;
}
+ return 0;
case NCP_IOC_GETROOT:
{
@@ -476,6 +582,32 @@ outrel:
}
#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_GETOBJECTNAME_32:
+ if (current->uid != server->m.mounted_uid) {
+ return -EACCES;
+ }
+ {
+ struct compat_ncp_objectname_ioctl user;
+ size_t outl;
+
+ if (copy_from_user(&user, argp, sizeof(user)))
+ return -EFAULT;
+ user.auth_type = server->auth.auth_type;
+ outl = user.object_name_len;
+ user.object_name_len = server->auth.object_name_len;
+ if (outl > user.object_name_len)
+ outl = user.object_name_len;
+ if (outl) {
+ if (copy_to_user(compat_ptr(user.object_name),
+ server->auth.object_name,
+ outl)) return -EFAULT;
+ }
+ if (copy_to_user(argp, &user, sizeof(user)))
+ return -EFAULT;
+ return 0;
+ }
+#endif
case NCP_IOC_GETOBJECTNAME:
if (current->uid != server->m.mounted_uid) {
return -EACCES;
@@ -500,6 +632,9 @@ outrel:
return -EFAULT;
return 0;
}
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_SETOBJECTNAME_32:
+#endif
case NCP_IOC_SETOBJECTNAME:
if (current->uid != server->m.mounted_uid) {
return -EACCES;
@@ -512,8 +647,19 @@ outrel:
void* oldprivate;
size_t oldprivatelen;
+#ifdef CONFIG_COMPAT
+ if (cmd == NCP_IOC_SETOBJECTNAME_32) {
+ struct compat_ncp_objectname_ioctl user32;
+ if (copy_from_user(&user32, argp, sizeof(user32)))
+ return -EFAULT;
+ user.auth_type = user32.auth_type;
+ user.object_name_len = user32.object_name_len;
+ user.object_name = compat_ptr(user32.object_name);
+ } else
+#endif
if (copy_from_user(&user, argp, sizeof(user)))
return -EFAULT;
+
if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN)
return -ENOMEM;
if (user.object_name_len) {
@@ -544,6 +690,9 @@ outrel:
kfree(oldname);
return 0;
}
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_GETPRIVATEDATA_32:
+#endif
case NCP_IOC_GETPRIVATEDATA:
if (current->uid != server->m.mounted_uid) {
return -EACCES;
@@ -552,8 +701,18 @@ outrel:
struct ncp_privatedata_ioctl user;
size_t outl;
+#ifdef CONFIG_COMPAT
+ if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
+ struct compat_ncp_privatedata_ioctl user32;
+ if (copy_from_user(&user32, argp, sizeof(user32)))
+ return -EFAULT;
+ user.len = user32.len;
+ user.data = compat_ptr(user32.data);
+ } else
+#endif
if (copy_from_user(&user, argp, sizeof(user)))
return -EFAULT;
+
outl = user.len;
user.len = server->priv.len;
if (outl > user.len) outl = user.len;
@@ -562,10 +721,23 @@ outrel:
server->priv.data,
outl)) return -EFAULT;
}
+#ifdef CONFIG_COMPAT
+ if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
+ struct compat_ncp_privatedata_ioctl user32;
+ user32.len = user.len;
+ user32.data = (unsigned long) user.data;
+ if (copy_to_user(&user32, argp, sizeof(user32)))
+ return -EFAULT;
+ } else
+#endif
if (copy_to_user(argp, &user, sizeof(user)))
return -EFAULT;
+
return 0;
}
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_SETPRIVATEDATA_32:
+#endif
case NCP_IOC_SETPRIVATEDATA:
if (current->uid != server->m.mounted_uid) {
return -EACCES;
@@ -576,8 +748,18 @@ outrel:
void* old;
size_t oldlen;
+#ifdef CONFIG_COMPAT
+ if (cmd == NCP_IOC_SETPRIVATEDATA_32) {
+ struct compat_ncp_privatedata_ioctl user32;
+ if (copy_from_user(&user32, argp, sizeof(user32)))
+ return -EFAULT;
+ user.len = user32.len;
+ user.data = compat_ptr(user32.data);
+ } else
+#endif
if (copy_from_user(&user, argp, sizeof(user)))
return -EFAULT;
+
if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
return -ENOMEM;
if (user.len) {
@@ -636,20 +818,19 @@ outrel:
}
}
-/* #ifdef CONFIG_UID16 */
- /* NCP_IOC_GETMOUNTUID may be same as NCP_IOC_GETMOUNTUID2,
- so we have this out of switch */
- if (cmd == NCP_IOC_GETMOUNTUID) {
- __kernel_uid_t uid = 0;
- if ((file_permission(filp, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid)) {
- return -EACCES;
- }
- SET_UID(uid, server->m.mounted_uid);
- if (put_user(uid, (__kernel_uid_t __user *)argp))
- return -EFAULT;
- return 0;
- }
-/* #endif */
return -EINVAL;
}
+
+#ifdef CONFIG_COMPAT
+long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int ret;
+
+ lock_kernel();
+ arg = (unsigned long) compat_ptr(arg);
+ ret = ncp_ioctl(inode, file, cmd, arg);
+ unlock_kernel();
+ return ret;
+}
+#endif