fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / ncpfs / ioctl.c
index eb3813a..8843a83 100644 (file)
@@ -7,20 +7,21 @@
  *
  */
 
-#include <linux/config.h>
-
-#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 */
@@ -34,7 +35,7 @@ static int
 ncp_get_fs_info(struct ncp_server * server, struct file *file,
                struct ncp_fs_info __user *arg)
 {
-       struct inode *inode = file->f_dentry->d_inode;
+       struct inode *inode = file->f_path.dentry->d_inode;
        struct ncp_fs_info info;
 
        if ((file_permission(file, MAY_WRITE) != 0)
@@ -64,7 +65,7 @@ static int
 ncp_get_fs_info_v2(struct ncp_server * server, struct file *file,
                   struct ncp_fs_info_v2 __user * arg)
 {
-       struct inode *inode = file->f_dentry->d_inode;
+       struct inode *inode = file->f_path.dentry->d_inode;
        struct ncp_fs_info_v2 info2;
 
        if ((file_permission(file, MAY_WRITE) != 0)
@@ -90,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_path.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.
@@ -193,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;
 
@@ -255,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:
                {
@@ -477,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;
@@ -501,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;
@@ -513,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) {
@@ -545,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;
@@ -553,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;
@@ -563,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(argp, &user32, 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;
@@ -577,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) {
@@ -637,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_path.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