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