|
@@ -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
|