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