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 rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; 530 else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT) 531 rqdata.timeout = NCP_LOCK_MAX_TIMEOUT; 532 break; 533 case NCP_LOCK_LOG: 534 rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; /* has no effect */ 535 case NCP_LOCK_CLEAR: 536 break; 537 default: 538 return -EINVAL; 539 } 540 /* locking needs both read and write access */ 541 if ((result = ncp_make_open(inode, O_RDWR)) != 0) 542 { 543 return result; 544 } 545 result = -EISDIR; 546 if (!S_ISREG(inode->i_mode)) 547 goto outrel; 548 if (rqdata.cmd == NCP_LOCK_CLEAR) 549 { 550 result = ncp_ClearPhysicalRecord(NCP_SERVER(inode), 551 NCP_FINFO(inode)->file_handle, 552 rqdata.offset, 553 rqdata.length); 554 if (result > 0) result = 0; /* no such lock */ 555 } 556 else 557 { 558 int lockcmd; 559 560 switch (rqdata.cmd) 561 { 562 case NCP_LOCK_EX: lockcmd=1; break; 563 case NCP_LOCK_SH: lockcmd=3; break; 564 default: lockcmd=0; break; 565 } 566 result = ncp_LogPhysicalRecord(NCP_SERVER(inode), 567 NCP_FINFO(inode)->file_handle, 568 lockcmd, 569 rqdata.offset, 570 rqdata.length, 571 rqdata.timeout); 572 if (result > 0) result = -EAGAIN; 573 } 574outrel: 575 ncp_inode_close(inode); 576 return result; 577 } 578#endif /* CONFIG_NCPFS_IOCTL_LOCKING */ 579 580#ifdef CONFIG_COMPAT 581 case NCP_IOC_GETOBJECTNAME_32: 582 { 583 struct compat_ncp_objectname_ioctl user; 584 size_t outl; 585 586 if (copy_from_user(&user, argp, sizeof(user))) 587 return -EFAULT; 588 down_read(&server->auth_rwsem); 589 user.auth_type = server->auth.auth_type; 590 outl = user.object_name_len; 591 user.object_name_len = server->auth.object_name_len; 592 if (outl > user.object_name_len) 593 outl = user.object_name_len; 594 result = 0; 595 if (outl) { 596 if (copy_to_user(compat_ptr(user.object_name), 597 server->auth.object_name, 598 outl)) 599 result = -EFAULT; 600 } 601 up_read(&server->auth_rwsem); 602 if (!result && copy_to_user(argp, &user, sizeof(user))) 603 result = -EFAULT; 604 return result; 605 } 606#endif 607 608 case NCP_IOC_GETOBJECTNAME: 609 { 610 struct ncp_objectname_ioctl user; 611 size_t outl; 612 613 if (copy_from_user(&user, argp, sizeof(user))) 614 return -EFAULT; 615 down_read(&server->auth_rwsem); 616 user.auth_type = server->auth.auth_type; 617 outl = user.object_name_len; 618 user.object_name_len = server->auth.object_name_len; 619 if (outl > user.object_name_len) 620 outl = user.object_name_len; 621 result = 0; 622 if (outl) { 623 if (copy_to_user(user.object_name, 624 server->auth.object_name, 625 outl)) 626 result = -EFAULT; 627 } 628 up_read(&server->auth_rwsem); 629 if (!result && copy_to_user(argp, &user, sizeof(user))) 630 result = -EFAULT; 631 return result; 632 } 633 634#ifdef CONFIG_COMPAT 635 case NCP_IOC_SETOBJECTNAME_32: 636#endif 637 case NCP_IOC_SETOBJECTNAME: 638 { 639 struct ncp_objectname_ioctl user; 640 void* newname; 641 void* oldname; 642 size_t oldnamelen; 643 void* oldprivate; 644 size_t oldprivatelen; 645 646#ifdef CONFIG_COMPAT 647 if (cmd == NCP_IOC_SETOBJECTNAME_32) { 648 struct compat_ncp_objectname_ioctl user32; 649 if (copy_from_user(&user32, argp, sizeof(user32))) 650 return -EFAULT; 651 user.auth_type = user32.auth_type; 652 user.object_name_len = user32.object_name_len; 653 user.object_name = compat_ptr(user32.object_name); 654 } else 655#endif 656 if (copy_from_user(&user, argp, sizeof(user))) 657 return -EFAULT; 658 659 if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN) 660 return -ENOMEM; 661 if (user.object_name_len) { 662 newname = memdup_user(user.object_name, 663 user.object_name_len); 664 if (IS_ERR(newname)) 665 return PTR_ERR(newname); 666 } else { 667 newname = NULL; 668 } 669 down_write(&server->auth_rwsem); 670 oldname = server->auth.object_name; 671 oldnamelen = server->auth.object_name_len; 672 oldprivate = server->priv.data; 673 oldprivatelen = server->priv.len; 674 server->auth.auth_type = user.auth_type; 675 server->auth.object_name_len = user.object_name_len; 676 server->auth.object_name = newname; 677 server->priv.len = 0; 678 server->priv.data = NULL; 679 up_write(&server->auth_rwsem); 680 kfree(oldprivate); 681 kfree(oldname); 682 return 0; 683 } 684 685#ifdef CONFIG_COMPAT 686 case NCP_IOC_GETPRIVATEDATA_32: 687#endif 688 case NCP_IOC_GETPRIVATEDATA: 689 { 690 struct ncp_privatedata_ioctl user; 691 size_t outl; 692 693#ifdef CONFIG_COMPAT 694 if (cmd == NCP_IOC_GETPRIVATEDATA_32) { 695 struct compat_ncp_privatedata_ioctl user32; 696 if (copy_from_user(&user32, argp, sizeof(user32))) 697 return -EFAULT; 698 user.len = user32.len; 699 user.data = compat_ptr(user32.data); 700 } else 701#endif 702 if (copy_from_user(&user, argp, sizeof(user))) 703 return -EFAULT; 704 705 down_read(&server->auth_rwsem); 706 outl = user.len; 707 user.len = server->priv.len; 708 if (outl > user.len) outl = user.len; 709 result = 0; 710 if (outl) { 711 if (copy_to_user(user.data, 712 server->priv.data, 713 outl)) 714 result = -EFAULT; 715 } 716 up_read(&server->auth_rwsem); 717 if (result) 718 return result; 719#ifdef CONFIG_COMPAT 720 if (cmd == NCP_IOC_GETPRIVATEDATA_32) { 721 struct compat_ncp_privatedata_ioctl user32; 722 user32.len = user.len; 723 user32.data = (unsigned long) user.data; 724 if (copy_to_user(argp, &user32, sizeof(user32))) 725 return -EFAULT; 726 } else 727#endif 728 if (copy_to_user(argp, &user, sizeof(user))) 729 return -EFAULT; 730 731 return 0; 732 } 733 734#ifdef CONFIG_COMPAT 735 case NCP_IOC_SETPRIVATEDATA_32: 736#endif 737 case NCP_IOC_SETPRIVATEDATA: 738 { 739 struct ncp_privatedata_ioctl user; 740 void* new; 741 void* old; 742 size_t oldlen; 743 744#ifdef CONFIG_COMPAT 745 if (cmd == NCP_IOC_SETPRIVATEDATA_32) { 746 struct compat_ncp_privatedata_ioctl user32; 747 if (copy_from_user(&user32, argp, sizeof(user32))) 748 return -EFAULT; 749 user.len = user32.len; 750 user.data = compat_ptr(user32.data); 751 } else 752#endif 753 if (copy_from_user(&user, argp, sizeof(user))) 754 return -EFAULT; 755 756 if (user.len > NCP_PRIVATE_DATA_MAX_LEN) 757 return -ENOMEM; 758 if (user.len) { 759 new = memdup_user(user.data, user.len); 760 if (IS_ERR(new)) 761 return PTR_ERR(new); 762 } else { 763 new = NULL; 764 } 765 down_write(&server->auth_rwsem); 766 old = server->priv.data; 767 oldlen = server->priv.len; 768 server->priv.len = user.len; 769 server->priv.data = new; 770 up_write(&server->auth_rwsem); 771 kfree(old); 772 return 0; 773 } 774 775#ifdef CONFIG_NCPFS_NLS 776 case NCP_IOC_SETCHARSETS: 777 return ncp_set_charsets(server, argp); 778 779 case NCP_IOC_GETCHARSETS: 780 return ncp_get_charsets(server, argp); 781 782#endif /* CONFIG_NCPFS_NLS */ 783 784 case NCP_IOC_SETDENTRYTTL: 785 { 786 u_int32_t user; 787 788 if (copy_from_user(&user, argp, sizeof(user))) 789 return -EFAULT; 790 /* 20 secs at most... */ 791 if (user > 20000) 792 return -EINVAL; 793 user = (user * HZ) / 1000; 794 atomic_set(&server->dentry_ttl, user); 795 return 0; 796 } 797 798 case NCP_IOC_GETDENTRYTTL: 799 { 800 u_int32_t user = (atomic_read(&server->dentry_ttl) * 1000) / HZ; 801 if (copy_to_user(argp, &user, sizeof(user))) 802 return -EFAULT; 803 return 0; 804 } 805 806 } 807 return -EINVAL; 808} 809 810long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 811{ 812 struct inode *inode = file_inode(filp); 813 struct ncp_server *server = NCP_SERVER(inode); 814 kuid_t uid = current_uid(); 815 int need_drop_write = 0; 816 long ret; 817 818 switch (cmd) { 819 case NCP_IOC_SETCHARSETS: 820 case NCP_IOC_CONN_LOGGED_IN: 821 case NCP_IOC_SETROOT: 822 if (!capable(CAP_SYS_ADMIN)) { 823 ret = -EPERM; 824 goto out; 825 } 826 break; 827 } 828 if (!uid_eq(server->m.mounted_uid, uid)) { 829 switch (cmd) { 830 /* 831 * Only mount owner can issue these ioctls. Information 832 * necessary to authenticate to other NDS servers are 833 * stored here. 834 */ 835 case NCP_IOC_GETOBJECTNAME: 836 case NCP_IOC_SETOBJECTNAME: 837 case NCP_IOC_GETPRIVATEDATA: 838 case NCP_IOC_SETPRIVATEDATA: 839#ifdef CONFIG_COMPAT 840 case NCP_IOC_GETOBJECTNAME_32: 841 case NCP_IOC_SETOBJECTNAME_32: 842 case NCP_IOC_GETPRIVATEDATA_32: 843 case NCP_IOC_SETPRIVATEDATA_32: 844#endif 845 ret = -EACCES; 846 goto out; 847 /* 848 * These require write access on the inode if user id 849 * does not match. Note that they do not write to the 850 * file... But old code did mnt_want_write, so I keep 851 * it as is. Of course not for mountpoint owner, as 852 * that breaks read-only mounts altogether as ncpmount 853 * needs working NCP_IOC_NCPREQUEST and 854 * NCP_IOC_GET_FS_INFO. Some of these codes (setdentryttl, 855 * signinit, setsignwanted) should be probably restricted 856 * to owner only, or even more to CAP_SYS_ADMIN). 857 */ 858 case NCP_IOC_GET_FS_INFO: 859 case NCP_IOC_GET_FS_INFO_V2: 860 case NCP_IOC_NCPREQUEST: 861 case NCP_IOC_SETDENTRYTTL: 862 case NCP_IOC_SIGN_INIT: 863 case NCP_IOC_LOCKUNLOCK: 864 case NCP_IOC_SET_SIGN_WANTED: 865#ifdef CONFIG_COMPAT 866 case NCP_IOC_GET_FS_INFO_V2_32: 867 case NCP_IOC_NCPREQUEST_32: 868#endif 869 ret = mnt_want_write_file(filp); 870 if (ret) 871 goto out; 872 need_drop_write = 1; 873 ret = inode_permission(inode, MAY_WRITE); 874 if (ret) 875 goto outDropWrite; 876 break; 877 /* 878 * Read access required. 879 */ 880 case NCP_IOC_GETMOUNTUID16: 881 case NCP_IOC_GETMOUNTUID32: 882 case NCP_IOC_GETMOUNTUID64: 883 case NCP_IOC_GETROOT: 884 case NCP_IOC_SIGN_WANTED: 885 ret = inode_permission(inode, MAY_READ); 886 if (ret) 887 goto out; 888 break; 889 /* 890 * Anybody can read these. 891 */ 892 case NCP_IOC_GETCHARSETS: 893 case NCP_IOC_GETDENTRYTTL: 894 default: 895 /* Three codes below are protected by CAP_SYS_ADMIN above. */ 896 case NCP_IOC_SETCHARSETS: 897 case NCP_IOC_CONN_LOGGED_IN: 898 case NCP_IOC_SETROOT: 899 break; 900 } 901 } 902 ret = __ncp_ioctl(inode, cmd, arg); 903outDropWrite: 904 if (need_drop_write) 905 mnt_drop_write_file(filp); 906out: 907 return ret; 908} 909 910#ifdef CONFIG_COMPAT 911long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 912{ 913 long ret; 914 915 arg = (unsigned long) compat_ptr(arg); 916 ret = ncp_ioctl(file, cmd, arg); 917 return ret; 918} 919#endif 920