linux/fs/ncpfs/ioctl.c
<<
>>
Prefs
   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/highuid.h>
  18#include <linux/smp_lock.h>
  19#include <linux/vmalloc.h>
  20#include <linux/sched.h>
  21
  22#include <linux/ncp_fs.h>
  23
  24#include <asm/uaccess.h>
  25
  26#include "ncplib_kernel.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
  35static int
  36ncp_get_fs_info(struct ncp_server * server, struct file *file,
  37                struct ncp_fs_info __user *arg)
  38{
  39        struct inode *inode = file->f_path.dentry->d_inode;
  40        struct ncp_fs_info info;
  41
  42        if ((file_permission(file, MAY_WRITE) != 0)
  43            && (current->uid != server->m.mounted_uid)) {
  44                return -EACCES;
  45        }
  46        if (copy_from_user(&info, arg, sizeof(info)))
  47                return -EFAULT;
  48
  49        if (info.version != NCP_GET_FS_INFO_VERSION) {
  50                DPRINTK("info.version invalid: %d\n", info.version);
  51                return -EINVAL;
  52        }
  53        /* TODO: info.addr = server->m.serv_addr; */
  54        SET_UID(info.mounted_uid, server->m.mounted_uid);
  55        info.connection         = server->connection;
  56        info.buffer_size        = server->buffer_size;
  57        info.volume_number      = NCP_FINFO(inode)->volNumber;
  58        info.directory_id       = NCP_FINFO(inode)->DosDirNum;
  59
  60        if (copy_to_user(arg, &info, sizeof(info)))
  61                return -EFAULT;
  62        return 0;
  63}
  64
  65static int
  66ncp_get_fs_info_v2(struct ncp_server * server, struct file *file,
  67                   struct ncp_fs_info_v2 __user * arg)
  68{
  69        struct inode *inode = file->f_path.dentry->d_inode;
  70        struct ncp_fs_info_v2 info2;
  71
  72        if ((file_permission(file, MAY_WRITE) != 0)
  73            && (current->uid != server->m.mounted_uid)) {
  74                return -EACCES;
  75        }
  76        if (copy_from_user(&info2, arg, sizeof(info2)))
  77                return -EFAULT;
  78
  79        if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
  80                DPRINTK("info.version invalid: %d\n", info2.version);
  81                return -EINVAL;
  82        }
  83        info2.mounted_uid   = server->m.mounted_uid;
  84        info2.connection    = server->connection;
  85        info2.buffer_size   = server->buffer_size;
  86        info2.volume_number = NCP_FINFO(inode)->volNumber;
  87        info2.directory_id  = NCP_FINFO(inode)->DosDirNum;
  88        info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
  89
  90        if (copy_to_user(arg, &info2, sizeof(info2)))
  91                return -EFAULT;
  92        return 0;
  93}
  94
  95#ifdef CONFIG_COMPAT
  96struct compat_ncp_objectname_ioctl
  97{
  98        s32             auth_type;
  99        u32             object_name_len;
 100        compat_caddr_t  object_name;    /* an userspace data, in most cases user name */
 101};
 102
 103struct compat_ncp_fs_info_v2 {
 104        s32 version;
 105        u32 mounted_uid;
 106        u32 connection;
 107        u32 buffer_size;
 108
 109        u32 volume_number;
 110        u32 directory_id;
 111
 112        u32 dummy1;
 113        u32 dummy2;
 114        u32 dummy3;
 115};
 116
 117struct compat_ncp_ioctl_request {
 118        u32 function;
 119        u32 size;
 120        compat_caddr_t data;
 121};
 122
 123struct compat_ncp_privatedata_ioctl
 124{
 125        u32             len;
 126        compat_caddr_t  data;           /* ~1000 for NDS */
 127};
 128
 129#define NCP_IOC_GET_FS_INFO_V2_32       _IOWR('n', 4, struct compat_ncp_fs_info_v2)
 130#define NCP_IOC_NCPREQUEST_32           _IOR('n', 1, struct compat_ncp_ioctl_request)
 131#define NCP_IOC_GETOBJECTNAME_32        _IOWR('n', 9, struct compat_ncp_objectname_ioctl)
 132#define NCP_IOC_SETOBJECTNAME_32        _IOR('n', 9, struct compat_ncp_objectname_ioctl)
 133#define NCP_IOC_GETPRIVATEDATA_32       _IOWR('n', 10, struct compat_ncp_privatedata_ioctl)
 134#define NCP_IOC_SETPRIVATEDATA_32       _IOR('n', 10, struct compat_ncp_privatedata_ioctl)
 135
 136static int
 137ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file,
 138                   struct compat_ncp_fs_info_v2 __user * arg)
 139{
 140        struct inode *inode = file->f_path.dentry->d_inode;
 141        struct compat_ncp_fs_info_v2 info2;
 142
 143        if ((file_permission(file, MAY_WRITE) != 0)
 144            && (current->uid != server->m.mounted_uid)) {
 145                return -EACCES;
 146        }
 147        if (copy_from_user(&info2, arg, sizeof(info2)))
 148                return -EFAULT;
 149
 150        if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
 151                DPRINTK("info.version invalid: %d\n", info2.version);
 152                return -EINVAL;
 153        }
 154        info2.mounted_uid   = server->m.mounted_uid;
 155        info2.connection    = server->connection;
 156        info2.buffer_size   = server->buffer_size;
 157        info2.volume_number = NCP_FINFO(inode)->volNumber;
 158        info2.directory_id  = NCP_FINFO(inode)->DosDirNum;
 159        info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
 160
 161        if (copy_to_user(arg, &info2, sizeof(info2)))
 162                return -EFAULT;
 163        return 0;
 164}
 165#endif
 166
 167#define NCP_IOC_GETMOUNTUID16           _IOW('n', 2, u16)
 168#define NCP_IOC_GETMOUNTUID32           _IOW('n', 2, u32)
 169#define NCP_IOC_GETMOUNTUID64           _IOW('n', 2, u64)
 170
 171#ifdef CONFIG_NCPFS_NLS
 172/* Here we are select the iocharset and the codepage for NLS.
 173 * Thanks Petr Vandrovec for idea and many hints.
 174 */
 175static int
 176ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
 177{
 178        struct ncp_nls_ioctl user;
 179        struct nls_table *codepage;
 180        struct nls_table *iocharset;
 181        struct nls_table *oldset_io;
 182        struct nls_table *oldset_cp;
 183
 184        if (!capable(CAP_SYS_ADMIN))
 185                return -EACCES;
 186        if (server->root_setuped)
 187                return -EBUSY;
 188
 189        if (copy_from_user(&user, arg, sizeof(user)))
 190                return -EFAULT;
 191
 192        codepage = NULL;
 193        user.codepage[NCP_IOCSNAME_LEN] = 0;
 194        if (!user.codepage[0] || !strcmp(user.codepage, "default"))
 195                codepage = load_nls_default();
 196        else {
 197                codepage = load_nls(user.codepage);
 198                if (!codepage) {
 199                        return -EBADRQC;
 200                }
 201        }
 202
 203        iocharset = NULL;
 204        user.iocharset[NCP_IOCSNAME_LEN] = 0;
 205        if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) {
 206                iocharset = load_nls_default();
 207                NCP_CLR_FLAG(server, NCP_FLAG_UTF8);
 208        } else if (!strcmp(user.iocharset, "utf8")) {
 209                iocharset = load_nls_default();
 210                NCP_SET_FLAG(server, NCP_FLAG_UTF8);
 211        } else {
 212                iocharset = load_nls(user.iocharset);
 213                if (!iocharset) {
 214                        unload_nls(codepage);
 215                        return -EBADRQC;
 216                }
 217                NCP_CLR_FLAG(server, NCP_FLAG_UTF8);
 218        }
 219
 220        oldset_cp = server->nls_vol;
 221        server->nls_vol = codepage;
 222        oldset_io = server->nls_io;
 223        server->nls_io = iocharset;
 224
 225        if (oldset_cp)
 226                unload_nls(oldset_cp);
 227        if (oldset_io)
 228                unload_nls(oldset_io);
 229
 230        return 0;
 231}
 232
 233static int
 234ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
 235{
 236        struct ncp_nls_ioctl user;
 237        int len;
 238
 239        memset(&user, 0, sizeof(user));
 240        if (server->nls_vol && server->nls_vol->charset) {
 241                len = strlen(server->nls_vol->charset);
 242                if (len > NCP_IOCSNAME_LEN)
 243                        len = NCP_IOCSNAME_LEN;
 244                strncpy(user.codepage, server->nls_vol->charset, len);
 245                user.codepage[len] = 0;
 246        }
 247
 248        if (NCP_IS_FLAG(server, NCP_FLAG_UTF8))
 249                strcpy(user.iocharset, "utf8");
 250        else if (server->nls_io && server->nls_io->charset) {
 251                len = strlen(server->nls_io->charset);
 252                if (len > NCP_IOCSNAME_LEN)
 253                        len = NCP_IOCSNAME_LEN;
 254                strncpy(user.iocharset, server->nls_io->charset, len);
 255                user.iocharset[len] = 0;
 256        }
 257
 258        if (copy_to_user(arg, &user, sizeof(user)))
 259                return -EFAULT;
 260        return 0;
 261}
 262#endif /* CONFIG_NCPFS_NLS */
 263
 264int ncp_ioctl(struct inode *inode, struct file *filp,
 265              unsigned int cmd, unsigned long arg)
 266{
 267        struct ncp_server *server = NCP_SERVER(inode);
 268        int result;
 269        struct ncp_ioctl_request request;
 270        char* bouncebuffer;
 271        void __user *argp = (void __user *)arg;
 272
 273        switch (cmd) {
 274#ifdef CONFIG_COMPAT
 275        case NCP_IOC_NCPREQUEST_32:
 276#endif
 277        case NCP_IOC_NCPREQUEST:
 278                if ((file_permission(filp, MAY_WRITE) != 0)
 279                    && (current->uid != server->m.mounted_uid)) {
 280                        return -EACCES;
 281                }
 282#ifdef CONFIG_COMPAT
 283                if (cmd == NCP_IOC_NCPREQUEST_32) {
 284                        struct compat_ncp_ioctl_request request32;
 285                        if (copy_from_user(&request32, argp, sizeof(request32)))
 286                                return -EFAULT;
 287                        request.function = request32.function;
 288                        request.size = request32.size;
 289                        request.data = compat_ptr(request32.data);
 290                } else
 291#endif
 292                if (copy_from_user(&request, argp, sizeof(request)))
 293                        return -EFAULT;
 294
 295                if ((request.function > 255)
 296                    || (request.size >
 297                  NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) {
 298                        return -EINVAL;
 299                }
 300                bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL);
 301                if (!bouncebuffer)
 302                        return -ENOMEM;
 303                if (copy_from_user(bouncebuffer, request.data, request.size)) {
 304                        vfree(bouncebuffer);
 305                        return -EFAULT;
 306                }
 307                ncp_lock_server(server);
 308
 309                /* FIXME: We hack around in the server's structures
 310                   here to be able to use ncp_request */
 311
 312                server->has_subfunction = 0;
 313                server->current_size = request.size;
 314                memcpy(server->packet, bouncebuffer, request.size);
 315
 316                result = ncp_request2(server, request.function, 
 317                        bouncebuffer, NCP_PACKET_SIZE_INTERNAL);
 318                if (result < 0)
 319                        result = -EIO;
 320                else
 321                        result = server->reply_size;
 322                ncp_unlock_server(server);
 323                DPRINTK("ncp_ioctl: copy %d bytes\n",
 324                        result);
 325                if (result >= 0)
 326                        if (copy_to_user(request.data, bouncebuffer, result))
 327                                result = -EFAULT;
 328                vfree(bouncebuffer);
 329                return result;
 330
 331        case NCP_IOC_CONN_LOGGED_IN:
 332
 333                if (!capable(CAP_SYS_ADMIN))
 334                        return -EACCES;
 335                if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE))
 336                        return -EINVAL;
 337                if (server->root_setuped)
 338                        return -EBUSY;
 339                server->root_setuped = 1;
 340                return ncp_conn_logged_in(inode->i_sb);
 341
 342        case NCP_IOC_GET_FS_INFO:
 343                return ncp_get_fs_info(server, filp, argp);
 344
 345        case NCP_IOC_GET_FS_INFO_V2:
 346                return ncp_get_fs_info_v2(server, filp, argp);
 347
 348#ifdef CONFIG_COMPAT
 349        case NCP_IOC_GET_FS_INFO_V2_32:
 350                return ncp_get_compat_fs_info_v2(server, filp, argp);
 351#endif
 352        /* we have too many combinations of CONFIG_COMPAT,
 353         * CONFIG_64BIT and CONFIG_UID16, so just handle
 354         * any of the possible ioctls */
 355        case NCP_IOC_GETMOUNTUID16:
 356        case NCP_IOC_GETMOUNTUID32:
 357        case NCP_IOC_GETMOUNTUID64:
 358                if ((file_permission(filp, MAY_READ) != 0)
 359                        && (current->uid != server->m.mounted_uid)) {
 360                        return -EACCES;
 361                }
 362                if (cmd == NCP_IOC_GETMOUNTUID16) {
 363                        u16 uid;
 364                        SET_UID(uid, server->m.mounted_uid);
 365                        if (put_user(uid, (u16 __user *)argp))
 366                                return -EFAULT;
 367                } else if (cmd == NCP_IOC_GETMOUNTUID32) {
 368                        if (put_user(server->m.mounted_uid,
 369                                                (u32 __user *)argp))
 370                                return -EFAULT;
 371                } else {
 372                        if (put_user(server->m.mounted_uid,
 373                                                (u64 __user *)argp))
 374                                return -EFAULT;
 375                }
 376                return 0;
 377
 378        case NCP_IOC_GETROOT:
 379                {
 380                        struct ncp_setroot_ioctl sr;
 381
 382                        if ((file_permission(filp, MAY_READ) != 0)
 383                            && (current->uid != server->m.mounted_uid))
 384                        {
 385                                return -EACCES;
 386                        }
 387                        if (server->m.mounted_vol[0]) {
 388                                struct dentry* dentry = inode->i_sb->s_root;
 389
 390                                if (dentry) {
 391                                        struct inode* inode = dentry->d_inode;
 392                                
 393                                        if (inode) {
 394                                                sr.volNumber = NCP_FINFO(inode)->volNumber;
 395                                                sr.dirEntNum = NCP_FINFO(inode)->dirEntNum;
 396                                                sr.namespace = server->name_space[sr.volNumber];
 397                                        } else
 398                                                DPRINTK("ncpfs: s_root->d_inode==NULL\n");
 399                                } else
 400                                        DPRINTK("ncpfs: s_root==NULL\n");
 401                        } else {
 402                                sr.volNumber = -1;
 403                                sr.namespace = 0;
 404                                sr.dirEntNum = 0;
 405                        }
 406                        if (copy_to_user(argp, &sr, sizeof(sr)))
 407                                return -EFAULT;
 408                        return 0;
 409                }
 410        case NCP_IOC_SETROOT:
 411                {
 412                        struct ncp_setroot_ioctl sr;
 413                        __u32 vnum;
 414                        __le32 de;
 415                        __le32 dosde;
 416                        struct dentry* dentry;
 417
 418                        if (!capable(CAP_SYS_ADMIN))
 419                        {
 420                                return -EACCES;
 421                        }
 422                        if (server->root_setuped) return -EBUSY;
 423                        if (copy_from_user(&sr, argp, sizeof(sr)))
 424                                return -EFAULT;
 425                        if (sr.volNumber < 0) {
 426                                server->m.mounted_vol[0] = 0;
 427                                vnum = NCP_NUMBER_OF_VOLUMES;
 428                                de = 0;
 429                                dosde = 0;
 430                        } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) {
 431                                return -EINVAL;
 432                        } else if (ncp_mount_subdir(server, sr.volNumber,
 433                                                sr.namespace, sr.dirEntNum,
 434                                                &vnum, &de, &dosde)) {
 435                                return -ENOENT;
 436                        }
 437                        
 438                        dentry = inode->i_sb->s_root;
 439                        server->root_setuped = 1;
 440                        if (dentry) {
 441                                struct inode* inode = dentry->d_inode;
 442                                
 443                                if (inode) {
 444                                        NCP_FINFO(inode)->volNumber = vnum;
 445                                        NCP_FINFO(inode)->dirEntNum = de;
 446                                        NCP_FINFO(inode)->DosDirNum = dosde;
 447                                } else
 448                                        DPRINTK("ncpfs: s_root->d_inode==NULL\n");
 449                        } else
 450                                DPRINTK("ncpfs: s_root==NULL\n");
 451
 452                        return 0;
 453                }
 454
 455#ifdef CONFIG_NCPFS_PACKET_SIGNING      
 456        case NCP_IOC_SIGN_INIT:
 457                if ((file_permission(filp, MAY_WRITE) != 0)
 458                    && (current->uid != server->m.mounted_uid))
 459                {
 460                        return -EACCES;
 461                }
 462                if (argp) {
 463                        if (server->sign_wanted)
 464                        {
 465                                struct ncp_sign_init sign;
 466
 467                                if (copy_from_user(&sign, argp, sizeof(sign)))
 468                                        return -EFAULT;
 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                return 0;               
 478                
 479        case NCP_IOC_SIGN_WANTED:
 480                if ((file_permission(filp, MAY_READ) != 0)
 481                    && (current->uid != server->m.mounted_uid))
 482                {
 483                        return -EACCES;
 484                }
 485                
 486                if (put_user(server->sign_wanted, (int __user *)argp))
 487                        return -EFAULT;
 488                return 0;
 489        case NCP_IOC_SET_SIGN_WANTED:
 490                {
 491                        int newstate;
 492
 493                        if ((file_permission(filp, MAY_WRITE) != 0)
 494                            && (current->uid != server->m.mounted_uid))
 495                        {
 496                                return -EACCES;
 497                        }
 498                        /* get only low 8 bits... */
 499                        if (get_user(newstate, (unsigned char __user *)argp))
 500                                return -EFAULT;
 501                        if (server->sign_active) {
 502                                /* cannot turn signatures OFF when active */
 503                                if (!newstate) return -EINVAL;
 504                        } else {
 505                                server->sign_wanted = newstate != 0;
 506                        }
 507                        return 0;
 508                }
 509
 510#endif /* CONFIG_NCPFS_PACKET_SIGNING */
 511
 512#ifdef CONFIG_NCPFS_IOCTL_LOCKING
 513        case NCP_IOC_LOCKUNLOCK:
 514                if ((file_permission(filp, MAY_WRITE) != 0)
 515                    && (current->uid != server->m.mounted_uid))
 516                {
 517                        return -EACCES;
 518                }
 519                {
 520                        struct ncp_lock_ioctl    rqdata;
 521                        int result;
 522
 523                        if (copy_from_user(&rqdata, argp, sizeof(rqdata)))
 524                                return -EFAULT;
 525                        if (rqdata.origin != 0)
 526                                return -EINVAL;
 527                        /* check for cmd */
 528                        switch (rqdata.cmd) {
 529                                case NCP_LOCK_EX:
 530                                case NCP_LOCK_SH:
 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 = -EIO;
 549                        if (!ncp_conn_valid(server))
 550                                goto outrel;
 551                        result = -EISDIR;
 552                        if (!S_ISREG(inode->i_mode))
 553                                goto outrel;
 554                        if (rqdata.cmd == NCP_LOCK_CLEAR)
 555                        {
 556                                result = ncp_ClearPhysicalRecord(NCP_SERVER(inode),
 557                                                        NCP_FINFO(inode)->file_handle, 
 558                                                        rqdata.offset,
 559                                                        rqdata.length);
 560                                if (result > 0) result = 0;     /* no such lock */
 561                        }
 562                        else
 563                        {
 564                                int lockcmd;
 565
 566                                switch (rqdata.cmd)
 567                                {
 568                                        case NCP_LOCK_EX:  lockcmd=1; break;
 569                                        case NCP_LOCK_SH:  lockcmd=3; break;
 570                                        default:           lockcmd=0; break;
 571                                }
 572                                result = ncp_LogPhysicalRecord(NCP_SERVER(inode),
 573                                                        NCP_FINFO(inode)->file_handle,
 574                                                        lockcmd,
 575                                                        rqdata.offset,
 576                                                        rqdata.length,
 577                                                        rqdata.timeout);
 578                                if (result > 0) result = -EAGAIN;
 579                        }
 580outrel:                 
 581                        ncp_inode_close(inode);
 582                        return result;
 583                }
 584#endif  /* CONFIG_NCPFS_IOCTL_LOCKING */
 585
 586#ifdef CONFIG_COMPAT
 587        case NCP_IOC_GETOBJECTNAME_32:
 588                if (current->uid != server->m.mounted_uid) {
 589                        return -EACCES;
 590                }
 591                {
 592                        struct compat_ncp_objectname_ioctl user;
 593                        size_t outl;
 594
 595                        if (copy_from_user(&user, argp, sizeof(user)))
 596                                return -EFAULT;
 597                        user.auth_type = server->auth.auth_type;
 598                        outl = user.object_name_len;
 599                        user.object_name_len = server->auth.object_name_len;
 600                        if (outl > user.object_name_len)
 601                                outl = user.object_name_len;
 602                        if (outl) {
 603                                if (copy_to_user(compat_ptr(user.object_name),
 604                                                 server->auth.object_name,
 605                                                 outl)) return -EFAULT;
 606                        }
 607                        if (copy_to_user(argp, &user, sizeof(user)))
 608                                return -EFAULT;
 609                        return 0;
 610                }
 611#endif
 612        case NCP_IOC_GETOBJECTNAME:
 613                if (current->uid != server->m.mounted_uid) {
 614                        return -EACCES;
 615                }
 616                {
 617                        struct ncp_objectname_ioctl user;
 618                        size_t outl;
 619
 620                        if (copy_from_user(&user, argp, sizeof(user)))
 621                                return -EFAULT;
 622                        user.auth_type = server->auth.auth_type;
 623                        outl = user.object_name_len;
 624                        user.object_name_len = server->auth.object_name_len;
 625                        if (outl > user.object_name_len)
 626                                outl = user.object_name_len;
 627                        if (outl) {
 628                                if (copy_to_user(user.object_name,
 629                                                 server->auth.object_name,
 630                                                 outl)) return -EFAULT;
 631                        }
 632                        if (copy_to_user(argp, &user, sizeof(user)))
 633                                return -EFAULT;
 634                        return 0;
 635                }
 636#ifdef CONFIG_COMPAT
 637        case NCP_IOC_SETOBJECTNAME_32:
 638#endif
 639        case NCP_IOC_SETOBJECTNAME:
 640                if (current->uid != server->m.mounted_uid) {
 641                        return -EACCES;
 642                }
 643                {
 644                        struct ncp_objectname_ioctl user;
 645                        void* newname;
 646                        void* oldname;
 647                        size_t oldnamelen;
 648                        void* oldprivate;
 649                        size_t oldprivatelen;
 650
 651#ifdef CONFIG_COMPAT
 652                        if (cmd == NCP_IOC_SETOBJECTNAME_32) {
 653                                struct compat_ncp_objectname_ioctl user32;
 654                                if (copy_from_user(&user32, argp, sizeof(user32)))
 655                                        return -EFAULT;
 656                                user.auth_type = user32.auth_type;
 657                                user.object_name_len = user32.object_name_len;
 658                                user.object_name = compat_ptr(user32.object_name);
 659                        } else
 660#endif
 661                        if (copy_from_user(&user, argp, sizeof(user)))
 662                                return -EFAULT;
 663
 664                        if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN)
 665                                return -ENOMEM;
 666                        if (user.object_name_len) {
 667                                newname = kmalloc(user.object_name_len, GFP_USER);
 668                                if (!newname)
 669                                        return -ENOMEM;
 670                                if (copy_from_user(newname, user.object_name, user.object_name_len)) {
 671                                        kfree(newname);
 672                                        return -EFAULT;
 673                                }
 674                        } else {
 675                                newname = NULL;
 676                        }
 677                        /* enter critical section */
 678                        /* maybe that kfree can sleep so do that this way */
 679                        /* it is at least more SMP friendly (in future...) */
 680                        oldname = server->auth.object_name;
 681                        oldnamelen = server->auth.object_name_len;
 682                        oldprivate = server->priv.data;
 683                        oldprivatelen = server->priv.len;
 684                        server->auth.auth_type = user.auth_type;
 685                        server->auth.object_name_len = user.object_name_len;
 686                        server->auth.object_name = newname;
 687                        server->priv.len = 0;
 688                        server->priv.data = NULL;
 689                        /* leave critical section */
 690                        kfree(oldprivate);
 691                        kfree(oldname);
 692                        return 0;
 693                }
 694#ifdef CONFIG_COMPAT
 695        case NCP_IOC_GETPRIVATEDATA_32:
 696#endif
 697        case NCP_IOC_GETPRIVATEDATA:
 698                if (current->uid != server->m.mounted_uid) {
 699                        return -EACCES;
 700                }
 701                {
 702                        struct ncp_privatedata_ioctl user;
 703                        size_t outl;
 704
 705#ifdef CONFIG_COMPAT
 706                        if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
 707                                struct compat_ncp_privatedata_ioctl user32;
 708                                if (copy_from_user(&user32, argp, sizeof(user32)))
 709                                        return -EFAULT;
 710                                user.len = user32.len;
 711                                user.data = compat_ptr(user32.data);
 712                        } else
 713#endif
 714                        if (copy_from_user(&user, argp, sizeof(user)))
 715                                return -EFAULT;
 716
 717                        outl = user.len;
 718                        user.len = server->priv.len;
 719                        if (outl > user.len) outl = user.len;
 720                        if (outl) {
 721                                if (copy_to_user(user.data,
 722                                                 server->priv.data,
 723                                                 outl)) return -EFAULT;
 724                        }
 725#ifdef CONFIG_COMPAT
 726                        if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
 727                                struct compat_ncp_privatedata_ioctl user32;
 728                                user32.len = user.len;
 729                                user32.data = (unsigned long) user.data;
 730                                if (copy_to_user(argp, &user32, sizeof(user32)))
 731                                        return -EFAULT;
 732                        } else
 733#endif
 734                        if (copy_to_user(argp, &user, sizeof(user)))
 735                                return -EFAULT;
 736
 737                        return 0;
 738                }
 739#ifdef CONFIG_COMPAT
 740        case NCP_IOC_SETPRIVATEDATA_32:
 741#endif
 742        case NCP_IOC_SETPRIVATEDATA:
 743                if (current->uid != server->m.mounted_uid) {
 744                        return -EACCES;
 745                }
 746                {
 747                        struct ncp_privatedata_ioctl user;
 748                        void* new;
 749                        void* old;
 750                        size_t oldlen;
 751
 752#ifdef CONFIG_COMPAT
 753                        if (cmd == NCP_IOC_SETPRIVATEDATA_32) {
 754                                struct compat_ncp_privatedata_ioctl user32;
 755                                if (copy_from_user(&user32, argp, sizeof(user32)))
 756                                        return -EFAULT;
 757                                user.len = user32.len;
 758                                user.data = compat_ptr(user32.data);
 759                        } else
 760#endif
 761                        if (copy_from_user(&user, argp, sizeof(user)))
 762                                return -EFAULT;
 763
 764                        if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
 765                                return -ENOMEM;
 766                        if (user.len) {
 767                                new = kmalloc(user.len, GFP_USER);
 768                                if (!new)
 769                                        return -ENOMEM;
 770                                if (copy_from_user(new, user.data, user.len)) {
 771                                        kfree(new);
 772                                        return -EFAULT;
 773                                }
 774                        } else {
 775                                new = NULL;
 776                        }
 777                        /* enter critical section */
 778                        old = server->priv.data;
 779                        oldlen = server->priv.len;
 780                        server->priv.len = user.len;
 781                        server->priv.data = new;
 782                        /* leave critical section */
 783                        kfree(old);
 784                        return 0;
 785                }
 786
 787#ifdef CONFIG_NCPFS_NLS
 788        case NCP_IOC_SETCHARSETS:
 789                return ncp_set_charsets(server, argp);
 790                
 791        case NCP_IOC_GETCHARSETS:
 792                return ncp_get_charsets(server, argp);
 793
 794#endif /* CONFIG_NCPFS_NLS */
 795
 796        case NCP_IOC_SETDENTRYTTL:
 797                if ((file_permission(filp, MAY_WRITE) != 0) &&
 798                                 (current->uid != server->m.mounted_uid))
 799                        return -EACCES;
 800                {
 801                        u_int32_t user;
 802
 803                        if (copy_from_user(&user, argp, sizeof(user)))
 804                                return -EFAULT;
 805                        /* 20 secs at most... */
 806                        if (user > 20000)
 807                                return -EINVAL;
 808                        user = (user * HZ) / 1000;
 809                        server->dentry_ttl = user;
 810                        return 0;
 811                }
 812                
 813        case NCP_IOC_GETDENTRYTTL:
 814                {
 815                        u_int32_t user = (server->dentry_ttl * 1000) / HZ;
 816                        if (copy_to_user(argp, &user, sizeof(user)))
 817                                return -EFAULT;
 818                        return 0;
 819                }
 820
 821        }
 822        return -EINVAL;
 823}
 824
 825#ifdef CONFIG_COMPAT
 826long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 827{
 828        struct inode *inode = file->f_path.dentry->d_inode;
 829        int ret;
 830
 831        lock_kernel();
 832        arg = (unsigned long) compat_ptr(arg);
 833        ret = ncp_ioctl(inode, file, cmd, arg);
 834        unlock_kernel();
 835        return ret;
 836}
 837#endif
 838