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