at v2.6.39 918 lines 23 kB view raw
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