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                ncp_dbg(1, "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, from_kuid_munged(current_user_ns(), 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                ncp_dbg(1, "info.version invalid: %d\n", info2.version);
  70                return -EINVAL;
  71        }
  72        info2.mounted_uid   = from_kuid_munged(current_user_ns(), 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                ncp_dbg(1, "info.version invalid: %d\n", info2.version);
 136                return -EINVAL;
 137        }
 138        info2.mounted_uid   = from_kuid_munged(current_user_ns(), 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                ncp_dbg(1, "copy %d bytes\n", result);
 312                if (result >= 0)
 313                        if (copy_to_user(request.data, bouncebuffer, result))
 314                                result = -EFAULT;
 315                vfree(bouncebuffer);
 316                return result;
 317
 318        case NCP_IOC_CONN_LOGGED_IN:
 319
 320                if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE))
 321                        return -EINVAL;
 322                mutex_lock(&server->root_setup_lock);
 323                if (server->root_setuped)
 324                        result = -EBUSY;
 325                else {
 326                        result = ncp_conn_logged_in(inode->i_sb);
 327                        if (result == 0)
 328                                server->root_setuped = 1;
 329                }
 330                mutex_unlock(&server->root_setup_lock);
 331                return result;
 332
 333        case NCP_IOC_GET_FS_INFO:
 334                return ncp_get_fs_info(server, inode, argp);
 335
 336        case NCP_IOC_GET_FS_INFO_V2:
 337                return ncp_get_fs_info_v2(server, inode, argp);
 338
 339#ifdef CONFIG_COMPAT
 340        case NCP_IOC_GET_FS_INFO_V2_32:
 341                return ncp_get_compat_fs_info_v2(server, inode, argp);
 342#endif
 343        /* we have too many combinations of CONFIG_COMPAT,
 344         * CONFIG_64BIT and CONFIG_UID16, so just handle
 345         * any of the possible ioctls */
 346        case NCP_IOC_GETMOUNTUID16:
 347                {
 348                        u16 uid;
 349
 350                        SET_UID(uid, from_kuid_munged(current_user_ns(), server->m.mounted_uid));
 351                        if (put_user(uid, (u16 __user *)argp))
 352                                return -EFAULT;
 353                        return 0;
 354                }
 355        case NCP_IOC_GETMOUNTUID32:
 356        {
 357                uid_t uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
 358                if (put_user(uid, (u32 __user *)argp))
 359                        return -EFAULT;
 360                return 0;
 361        }
 362        case NCP_IOC_GETMOUNTUID64:
 363        {
 364                uid_t uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
 365                if (put_user(uid, (u64 __user *)argp))
 366                        return -EFAULT;
 367                return 0;
 368        }
 369        case NCP_IOC_GETROOT:
 370                {
 371                        struct ncp_setroot_ioctl sr;
 372
 373                        result = -EACCES;
 374                        mutex_lock(&server->root_setup_lock);
 375                        if (server->m.mounted_vol[0]) {
 376                                struct dentry* dentry = inode->i_sb->s_root;
 377
 378                                if (dentry) {
 379                                        struct inode* s_inode = d_inode(dentry);
 380
 381                                        if (s_inode) {
 382                                                sr.volNumber = NCP_FINFO(s_inode)->volNumber;
 383                                                sr.dirEntNum = NCP_FINFO(s_inode)->dirEntNum;
 384                                                sr.namespace = server->name_space[sr.volNumber];
 385                                                result = 0;
 386                                        } else
 387                                                ncp_dbg(1, "d_inode(s_root)==NULL\n");
 388                                } else
 389                                        ncp_dbg(1, "s_root==NULL\n");
 390                        } else {
 391                                sr.volNumber = -1;
 392                                sr.namespace = 0;
 393                                sr.dirEntNum = 0;
 394                                result = 0;
 395                        }
 396                        mutex_unlock(&server->root_setup_lock);
 397                        if (!result && copy_to_user(argp, &sr, sizeof(sr)))
 398                                result = -EFAULT;
 399                        return result;
 400                }
 401
 402        case NCP_IOC_SETROOT:
 403                {
 404                        struct ncp_setroot_ioctl sr;
 405                        __u32 vnum;
 406                        __le32 de;
 407                        __le32 dosde;
 408                        struct dentry* dentry;
 409
 410                        if (copy_from_user(&sr, argp, sizeof(sr)))
 411                                return -EFAULT;
 412                        mutex_lock(&server->root_setup_lock);
 413                        if (server->root_setuped)
 414                                result = -EBUSY;
 415                        else {
 416                                if (sr.volNumber < 0) {
 417                                        server->m.mounted_vol[0] = 0;
 418                                        vnum = NCP_NUMBER_OF_VOLUMES;
 419                                        de = 0;
 420                                        dosde = 0;
 421                                        result = 0;
 422                                } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) {
 423                                        result = -EINVAL;
 424                                } else if (ncp_mount_subdir(server, sr.volNumber,
 425                                                        sr.namespace, sr.dirEntNum,
 426                                                        &vnum, &de, &dosde)) {
 427                                        result = -ENOENT;
 428                                } else
 429                                        result = 0;
 430
 431                                if (result == 0) {
 432                                        dentry = inode->i_sb->s_root;
 433                                        if (dentry) {
 434                                                struct inode* s_inode = d_inode(dentry);
 435
 436                                                if (s_inode) {
 437                                                        NCP_FINFO(s_inode)->volNumber = vnum;
 438                                                        NCP_FINFO(s_inode)->dirEntNum = de;
 439                                                        NCP_FINFO(s_inode)->DosDirNum = dosde;
 440                                                        server->root_setuped = 1;
 441                                                } else {
 442                                                        ncp_dbg(1, "d_inode(s_root)==NULL\n");
 443                                                        result = -EIO;
 444                                                }
 445                                        } else {
 446                                                ncp_dbg(1, "s_root==NULL\n");
 447                                                result = -EIO;
 448                                        }
 449                                }
 450                        }
 451                        mutex_unlock(&server->root_setup_lock);
 452
 453                        return result;
 454                }
 455
 456#ifdef CONFIG_NCPFS_PACKET_SIGNING
 457        case NCP_IOC_SIGN_INIT:
 458                {
 459                        struct ncp_sign_init sign;
 460
 461                        if (argp)
 462                                if (copy_from_user(&sign, argp, sizeof(sign)))
 463                                        return -EFAULT;
 464                        ncp_lock_server(server);
 465                        mutex_lock(&server->rcv.creq_mutex);
 466                        if (argp) {
 467                                if (server->sign_wanted) {
 468                                        memcpy(server->sign_root,sign.sign_root,8);
 469                                        memcpy(server->sign_last,sign.sign_last,16);
 470                                        server->sign_active = 1;
 471                                }
 472                                /* ignore when signatures not wanted */
 473                        } else {
 474                                server->sign_active = 0;
 475                        }
 476                        mutex_unlock(&server->rcv.creq_mutex);
 477                        ncp_unlock_server(server);
 478                        return 0;
 479                }
 480
 481        case NCP_IOC_SIGN_WANTED:
 482                {
 483                        int state;
 484
 485                        ncp_lock_server(server);
 486                        state = server->sign_wanted;
 487                        ncp_unlock_server(server);
 488                        if (put_user(state, (int __user *)argp))
 489                                return -EFAULT;
 490                        return 0;
 491                }
 492
 493        case NCP_IOC_SET_SIGN_WANTED:
 494                {
 495                        int newstate;
 496
 497                        /* get only low 8 bits... */
 498                        if (get_user(newstate, (unsigned char __user *)argp))
 499                                return -EFAULT;
 500                        result = 0;
 501                        ncp_lock_server(server);
 502                        if (server->sign_active) {
 503                                /* cannot turn signatures OFF when active */
 504                                if (!newstate)
 505                                        result = -EINVAL;
 506                        } else {
 507                                server->sign_wanted = newstate != 0;
 508                        }
 509                        ncp_unlock_server(server);
 510                        return result;
 511                }
 512
 513#endif /* CONFIG_NCPFS_PACKET_SIGNING */
 514
 515#ifdef CONFIG_NCPFS_IOCTL_LOCKING
 516        case NCP_IOC_LOCKUNLOCK:
 517                {
 518                        struct ncp_lock_ioctl    rqdata;
 519
 520                        if (copy_from_user(&rqdata, argp, sizeof(rqdata)))
 521                                return -EFAULT;
 522                        if (rqdata.origin != 0)
 523                                return -EINVAL;
 524                        /* check for cmd */
 525                        switch (rqdata.cmd) {
 526                                case NCP_LOCK_EX:
 527                                case NCP_LOCK_SH:
 528                                                if (rqdata.timeout < 0)
 529                                                        return -EINVAL;
 530                                                if (rqdata.timeout == 0)
 531                                                        rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT;
 532                                                else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT)
 533                                                        rqdata.timeout = NCP_LOCK_MAX_TIMEOUT;
 534                                                break;
 535                                case NCP_LOCK_LOG:
 536                                                rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT;      /* has no effect */
 537                                case NCP_LOCK_CLEAR:
 538                                                break;
 539                                default:
 540                                                return -EINVAL;
 541                        }
 542                        /* locking needs both read and write access */
 543                        if ((result = ncp_make_open(inode, O_RDWR)) != 0)
 544                        {
 545                                return result;
 546                        }
 547                        result = -EISDIR;
 548                        if (!S_ISREG(inode->i_mode))
 549                                goto outrel;
 550                        if (rqdata.cmd == NCP_LOCK_CLEAR)
 551                        {
 552                                result = ncp_ClearPhysicalRecord(NCP_SERVER(inode),
 553                                                        NCP_FINFO(inode)->file_handle,
 554                                                        rqdata.offset,
 555                                                        rqdata.length);
 556                                if (result > 0) result = 0;     /* no such lock */
 557                        }
 558                        else
 559                        {
 560                                int lockcmd;
 561
 562                                switch (rqdata.cmd)
 563                                {
 564                                        case NCP_LOCK_EX:  lockcmd=1; break;
 565                                        case NCP_LOCK_SH:  lockcmd=3; break;
 566                                        default:           lockcmd=0; break;
 567                                }
 568                                result = ncp_LogPhysicalRecord(NCP_SERVER(inode),
 569                                                        NCP_FINFO(inode)->file_handle,
 570                                                        lockcmd,
 571                                                        rqdata.offset,
 572                                                        rqdata.length,
 573                                                        rqdata.timeout);
 574                                if (result > 0) result = -EAGAIN;
 575                        }
 576outrel:
 577                        ncp_inode_close(inode);
 578                        return result;
 579                }
 580#endif  /* CONFIG_NCPFS_IOCTL_LOCKING */
 581
 582#ifdef CONFIG_COMPAT
 583        case NCP_IOC_GETOBJECTNAME_32:
 584                {
 585                        struct compat_ncp_objectname_ioctl user;
 586                        size_t outl;
 587
 588                        if (copy_from_user(&user, argp, sizeof(user)))
 589                                return -EFAULT;
 590                        down_read(&server->auth_rwsem);
 591                        user.auth_type = server->auth.auth_type;
 592                        outl = user.object_name_len;
 593                        user.object_name_len = server->auth.object_name_len;
 594                        if (outl > user.object_name_len)
 595                                outl = user.object_name_len;
 596                        result = 0;
 597                        if (outl) {
 598                                if (copy_to_user(compat_ptr(user.object_name),
 599                                                 server->auth.object_name,
 600                                                 outl))
 601                                        result = -EFAULT;
 602                        }
 603                        up_read(&server->auth_rwsem);
 604                        if (!result && copy_to_user(argp, &user, sizeof(user)))
 605                                result = -EFAULT;
 606                        return result;
 607                }
 608#endif
 609
 610        case NCP_IOC_GETOBJECTNAME:
 611                {
 612                        struct ncp_objectname_ioctl user;
 613                        size_t outl;
 614
 615                        if (copy_from_user(&user, argp, sizeof(user)))
 616                                return -EFAULT;
 617                        down_read(&server->auth_rwsem);
 618                        user.auth_type = server->auth.auth_type;
 619                        outl = user.object_name_len;
 620                        user.object_name_len = server->auth.object_name_len;
 621                        if (outl > user.object_name_len)
 622                                outl = user.object_name_len;
 623                        result = 0;
 624                        if (outl) {
 625                                if (copy_to_user(user.object_name,
 626                                                 server->auth.object_name,
 627                                                 outl))
 628                                        result = -EFAULT;
 629                        }
 630                        up_read(&server->auth_rwsem);
 631                        if (!result && copy_to_user(argp, &user, sizeof(user)))
 632                                result = -EFAULT;
 633                        return result;
 634                }
 635
 636#ifdef CONFIG_COMPAT
 637        case NCP_IOC_SETOBJECTNAME_32:
 638#endif
 639        case NCP_IOC_SETOBJECTNAME:
 640                {
 641                        struct ncp_objectname_ioctl user;
 642                        void* newname;
 643                        void* oldname;
 644                        size_t oldnamelen;
 645                        void* oldprivate;
 646                        size_t oldprivatelen;
 647
 648#ifdef CONFIG_COMPAT
 649                        if (cmd == NCP_IOC_SETOBJECTNAME_32) {
 650                                struct compat_ncp_objectname_ioctl user32;
 651                                if (copy_from_user(&user32, argp, sizeof(user32)))
 652                                        return -EFAULT;
 653                                user.auth_type = user32.auth_type;
 654                                user.object_name_len = user32.object_name_len;
 655                                user.object_name = compat_ptr(user32.object_name);
 656                        } else
 657#endif
 658                        if (copy_from_user(&user, argp, sizeof(user)))
 659                                return -EFAULT;
 660
 661                        if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN)
 662                                return -ENOMEM;
 663                        if (user.object_name_len) {
 664                                newname = memdup_user(user.object_name,
 665                                                      user.object_name_len);
 666                                if (IS_ERR(newname))
 667                                        return PTR_ERR(newname);
 668                        } else {
 669                                newname = NULL;
 670                        }
 671                        down_write(&server->auth_rwsem);
 672                        oldname = server->auth.object_name;
 673                        oldnamelen = server->auth.object_name_len;
 674                        oldprivate = server->priv.data;
 675                        oldprivatelen = server->priv.len;
 676                        server->auth.auth_type = user.auth_type;
 677                        server->auth.object_name_len = user.object_name_len;
 678                        server->auth.object_name = newname;
 679                        server->priv.len = 0;
 680                        server->priv.data = NULL;
 681                        up_write(&server->auth_rwsem);
 682                        kfree(oldprivate);
 683                        kfree(oldname);
 684                        return 0;
 685                }
 686
 687#ifdef CONFIG_COMPAT
 688        case NCP_IOC_GETPRIVATEDATA_32:
 689#endif
 690        case NCP_IOC_GETPRIVATEDATA:
 691                {
 692                        struct ncp_privatedata_ioctl user;
 693                        size_t outl;
 694
 695#ifdef CONFIG_COMPAT
 696                        if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
 697                                struct compat_ncp_privatedata_ioctl user32;
 698                                if (copy_from_user(&user32, argp, sizeof(user32)))
 699                                        return -EFAULT;
 700                                user.len = user32.len;
 701                                user.data = compat_ptr(user32.data);
 702                        } else
 703#endif
 704                        if (copy_from_user(&user, argp, sizeof(user)))
 705                                return -EFAULT;
 706
 707                        down_read(&server->auth_rwsem);
 708                        outl = user.len;
 709                        user.len = server->priv.len;
 710                        if (outl > user.len) outl = user.len;
 711                        result = 0;
 712                        if (outl) {
 713                                if (copy_to_user(user.data,
 714                                                 server->priv.data,
 715                                                 outl))
 716                                        result = -EFAULT;
 717                        }
 718                        up_read(&server->auth_rwsem);
 719                        if (result)
 720                                return result;
 721#ifdef CONFIG_COMPAT
 722                        if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
 723                                struct compat_ncp_privatedata_ioctl user32;
 724                                user32.len = user.len;
 725                                user32.data = (unsigned long) user.data;
 726                                if (copy_to_user(argp, &user32, sizeof(user32)))
 727                                        return -EFAULT;
 728                        } else
 729#endif
 730                        if (copy_to_user(argp, &user, sizeof(user)))
 731                                return -EFAULT;
 732
 733                        return 0;
 734                }
 735
 736#ifdef CONFIG_COMPAT
 737        case NCP_IOC_SETPRIVATEDATA_32:
 738#endif
 739        case NCP_IOC_SETPRIVATEDATA:
 740                {
 741                        struct ncp_privatedata_ioctl user;
 742                        void* new;
 743                        void* old;
 744                        size_t oldlen;
 745
 746#ifdef CONFIG_COMPAT
 747                        if (cmd == NCP_IOC_SETPRIVATEDATA_32) {
 748                                struct compat_ncp_privatedata_ioctl user32;
 749                                if (copy_from_user(&user32, argp, sizeof(user32)))
 750                                        return -EFAULT;
 751                                user.len = user32.len;
 752                                user.data = compat_ptr(user32.data);
 753                        } else
 754#endif
 755                        if (copy_from_user(&user, argp, sizeof(user)))
 756                                return -EFAULT;
 757
 758                        if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
 759                                return -ENOMEM;
 760                        if (user.len) {
 761                                new = memdup_user(user.data, user.len);
 762                                if (IS_ERR(new))
 763                                        return PTR_ERR(new);
 764                        } else {
 765                                new = NULL;
 766                        }
 767                        down_write(&server->auth_rwsem);
 768                        old = server->priv.data;
 769                        oldlen = server->priv.len;
 770                        server->priv.len = user.len;
 771                        server->priv.data = new;
 772                        up_write(&server->auth_rwsem);
 773                        kfree(old);
 774                        return 0;
 775                }
 776
 777#ifdef CONFIG_NCPFS_NLS
 778        case NCP_IOC_SETCHARSETS:
 779                return ncp_set_charsets(server, argp);
 780
 781        case NCP_IOC_GETCHARSETS:
 782                return ncp_get_charsets(server, argp);
 783
 784#endif /* CONFIG_NCPFS_NLS */
 785
 786        case NCP_IOC_SETDENTRYTTL:
 787                {
 788                        u_int32_t user;
 789
 790                        if (copy_from_user(&user, argp, sizeof(user)))
 791                                return -EFAULT;
 792                        /* 20 secs at most... */
 793                        if (user > 20000)
 794                                return -EINVAL;
 795                        user = (user * HZ) / 1000;
 796                        atomic_set(&server->dentry_ttl, user);
 797                        return 0;
 798                }
 799
 800        case NCP_IOC_GETDENTRYTTL:
 801                {
 802                        u_int32_t user = (atomic_read(&server->dentry_ttl) * 1000) / HZ;
 803                        if (copy_to_user(argp, &user, sizeof(user)))
 804                                return -EFAULT;
 805                        return 0;
 806                }
 807
 808        }
 809        return -EINVAL;
 810}
 811
 812long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 813{
 814        struct inode *inode = file_inode(filp);
 815        struct ncp_server *server = NCP_SERVER(inode);
 816        kuid_t uid = current_uid();
 817        int need_drop_write = 0;
 818        long ret;
 819
 820        switch (cmd) {
 821        case NCP_IOC_SETCHARSETS:
 822        case NCP_IOC_CONN_LOGGED_IN:
 823        case NCP_IOC_SETROOT:
 824                if (!capable(CAP_SYS_ADMIN)) {
 825                        ret = -EPERM;
 826                        goto out;
 827                }
 828                break;
 829        }
 830        if (!uid_eq(server->m.mounted_uid, uid)) {
 831                switch (cmd) {
 832                /*
 833                 * Only mount owner can issue these ioctls.  Information
 834                 * necessary to authenticate to other NDS servers are
 835                 * stored here.
 836                 */
 837                case NCP_IOC_GETOBJECTNAME:
 838                case NCP_IOC_SETOBJECTNAME:
 839                case NCP_IOC_GETPRIVATEDATA:
 840                case NCP_IOC_SETPRIVATEDATA:
 841#ifdef CONFIG_COMPAT
 842                case NCP_IOC_GETOBJECTNAME_32:
 843                case NCP_IOC_SETOBJECTNAME_32:
 844                case NCP_IOC_GETPRIVATEDATA_32:
 845                case NCP_IOC_SETPRIVATEDATA_32:
 846#endif
 847                        ret = -EACCES;
 848                        goto out;
 849                /*
 850                 * These require write access on the inode if user id
 851                 * does not match.  Note that they do not write to the
 852                 * file...  But old code did mnt_want_write, so I keep
 853                 * it as is.  Of course not for mountpoint owner, as
 854                 * that breaks read-only mounts altogether as ncpmount
 855                 * needs working NCP_IOC_NCPREQUEST and
 856                 * NCP_IOC_GET_FS_INFO.  Some of these codes (setdentryttl,
 857                 * signinit, setsignwanted) should be probably restricted
 858                 * to owner only, or even more to CAP_SYS_ADMIN).
 859                 */
 860                case NCP_IOC_GET_FS_INFO:
 861                case NCP_IOC_GET_FS_INFO_V2:
 862                case NCP_IOC_NCPREQUEST:
 863                case NCP_IOC_SETDENTRYTTL:
 864                case NCP_IOC_SIGN_INIT:
 865                case NCP_IOC_LOCKUNLOCK:
 866                case NCP_IOC_SET_SIGN_WANTED:
 867#ifdef CONFIG_COMPAT
 868                case NCP_IOC_GET_FS_INFO_V2_32:
 869                case NCP_IOC_NCPREQUEST_32:
 870#endif
 871                        ret = mnt_want_write_file(filp);
 872                        if (ret)
 873                                goto out;
 874                        need_drop_write = 1;
 875                        ret = inode_permission(inode, MAY_WRITE);
 876                        if (ret)
 877                                goto outDropWrite;
 878                        break;
 879                /*
 880                 * Read access required.
 881                 */
 882                case NCP_IOC_GETMOUNTUID16:
 883                case NCP_IOC_GETMOUNTUID32:
 884                case NCP_IOC_GETMOUNTUID64:
 885                case NCP_IOC_GETROOT:
 886                case NCP_IOC_SIGN_WANTED:
 887                        ret = inode_permission(inode, MAY_READ);
 888                        if (ret)
 889                                goto out;
 890                        break;
 891                /*
 892                 * Anybody can read these.
 893                 */
 894                case NCP_IOC_GETCHARSETS:
 895                case NCP_IOC_GETDENTRYTTL:
 896                default:
 897                /* Three codes below are protected by CAP_SYS_ADMIN above. */
 898                case NCP_IOC_SETCHARSETS:
 899                case NCP_IOC_CONN_LOGGED_IN:
 900                case NCP_IOC_SETROOT:
 901                        break;
 902                }
 903        }
 904        ret = __ncp_ioctl(inode, cmd, arg);
 905outDropWrite:
 906        if (need_drop_write)
 907                mnt_drop_write_file(filp);
 908out:
 909        return ret;
 910}
 911
 912#ifdef CONFIG_COMPAT
 913long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 914{
 915        long ret;
 916
 917        arg = (unsigned long) compat_ptr(arg);
 918        ret = ncp_ioctl(file, cmd, arg);
 919        return ret;
 920}
 921#endif
 922