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