at v4.14 923 lines 23 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * ioctl.c 4 * 5 * Copyright (C) 1995, 1996 by Volker Lendecke 6 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache 7 * Modified 1998, 1999 Wolfram Pienkoss for NLS 8 * 9 */ 10 11#include <linux/capability.h> 12#include <linux/compat.h> 13#include <linux/errno.h> 14#include <linux/fs.h> 15#include <linux/ioctl.h> 16#include <linux/time.h> 17#include <linux/mm.h> 18#include <linux/mount.h> 19#include <linux/slab.h> 20#include <linux/highuid.h> 21#include <linux/vmalloc.h> 22#include <linux/sched.h> 23#include <linux/cred.h> 24 25#include <linux/uaccess.h> 26 27#include "ncp_fs.h" 28 29/* maximum limit for ncp_objectname_ioctl */ 30#define NCP_OBJECT_NAME_MAX_LEN 4096 31/* maximum limit for ncp_privatedata_ioctl */ 32#define NCP_PRIVATE_DATA_MAX_LEN 8192 33/* maximum negotiable packet size */ 34#define NCP_PACKET_SIZE_INTERNAL 65536 35 36static int 37ncp_get_fs_info(struct ncp_server * server, struct inode *inode, 38 struct ncp_fs_info __user *arg) 39{ 40 struct ncp_fs_info info; 41 42 if (copy_from_user(&info, arg, sizeof(info))) 43 return -EFAULT; 44 45 if (info.version != NCP_GET_FS_INFO_VERSION) { 46 ncp_dbg(1, "info.version invalid: %d\n", info.version); 47 return -EINVAL; 48 } 49 /* TODO: info.addr = server->m.serv_addr; */ 50 SET_UID(info.mounted_uid, from_kuid_munged(current_user_ns(), server->m.mounted_uid)); 51 info.connection = server->connection; 52 info.buffer_size = server->buffer_size; 53 info.volume_number = NCP_FINFO(inode)->volNumber; 54 info.directory_id = NCP_FINFO(inode)->DosDirNum; 55 56 if (copy_to_user(arg, &info, sizeof(info))) 57 return -EFAULT; 58 return 0; 59} 60 61static int 62ncp_get_fs_info_v2(struct ncp_server * server, struct inode *inode, 63 struct ncp_fs_info_v2 __user * arg) 64{ 65 struct ncp_fs_info_v2 info2; 66 67 if (copy_from_user(&info2, arg, sizeof(info2))) 68 return -EFAULT; 69 70 if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { 71 ncp_dbg(1, "info.version invalid: %d\n", info2.version); 72 return -EINVAL; 73 } 74 info2.mounted_uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid); 75 info2.connection = server->connection; 76 info2.buffer_size = server->buffer_size; 77 info2.volume_number = NCP_FINFO(inode)->volNumber; 78 info2.directory_id = NCP_FINFO(inode)->DosDirNum; 79 info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; 80 81 if (copy_to_user(arg, &info2, sizeof(info2))) 82 return -EFAULT; 83 return 0; 84} 85 86#ifdef CONFIG_COMPAT 87struct compat_ncp_objectname_ioctl 88{ 89 s32 auth_type; 90 u32 object_name_len; 91 compat_caddr_t object_name; /* a userspace data, in most cases user name */ 92}; 93 94struct compat_ncp_fs_info_v2 { 95 s32 version; 96 u32 mounted_uid; 97 u32 connection; 98 u32 buffer_size; 99 100 u32 volume_number; 101 u32 directory_id; 102 103 u32 dummy1; 104 u32 dummy2; 105 u32 dummy3; 106}; 107 108struct compat_ncp_ioctl_request { 109 u32 function; 110 u32 size; 111 compat_caddr_t data; 112}; 113 114struct compat_ncp_privatedata_ioctl 115{ 116 u32 len; 117 compat_caddr_t data; /* ~1000 for NDS */ 118}; 119 120#define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct compat_ncp_fs_info_v2) 121#define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct compat_ncp_ioctl_request) 122#define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct compat_ncp_objectname_ioctl) 123#define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct compat_ncp_objectname_ioctl) 124#define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct compat_ncp_privatedata_ioctl) 125#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl) 126 127static int 128ncp_get_compat_fs_info_v2(struct ncp_server * server, struct inode *inode, 129 struct compat_ncp_fs_info_v2 __user * arg) 130{ 131 struct compat_ncp_fs_info_v2 info2; 132 133 if (copy_from_user(&info2, arg, sizeof(info2))) 134 return -EFAULT; 135 136 if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { 137 ncp_dbg(1, "info.version invalid: %d\n", info2.version); 138 return -EINVAL; 139 } 140 info2.mounted_uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid); 141 info2.connection = server->connection; 142 info2.buffer_size = server->buffer_size; 143 info2.volume_number = NCP_FINFO(inode)->volNumber; 144 info2.directory_id = NCP_FINFO(inode)->DosDirNum; 145 info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; 146 147 if (copy_to_user(arg, &info2, sizeof(info2))) 148 return -EFAULT; 149 return 0; 150} 151#endif 152 153#define NCP_IOC_GETMOUNTUID16 _IOW('n', 2, u16) 154#define NCP_IOC_GETMOUNTUID32 _IOW('n', 2, u32) 155#define NCP_IOC_GETMOUNTUID64 _IOW('n', 2, u64) 156 157#ifdef CONFIG_NCPFS_NLS 158/* Here we are select the iocharset and the codepage for NLS. 159 * Thanks Petr Vandrovec for idea and many hints. 160 */ 161static int 162ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) 163{ 164 struct ncp_nls_ioctl user; 165 struct nls_table *codepage; 166 struct nls_table *iocharset; 167 struct nls_table *oldset_io; 168 struct nls_table *oldset_cp; 169 int utf8; 170 int err; 171 172 if (copy_from_user(&user, arg, sizeof(user))) 173 return -EFAULT; 174 175 codepage = NULL; 176 user.codepage[NCP_IOCSNAME_LEN] = 0; 177 if (!user.codepage[0] || !strcmp(user.codepage, "default")) 178 codepage = load_nls_default(); 179 else { 180 codepage = load_nls(user.codepage); 181 if (!codepage) { 182 return -EBADRQC; 183 } 184 } 185 186 iocharset = NULL; 187 user.iocharset[NCP_IOCSNAME_LEN] = 0; 188 if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) { 189 iocharset = load_nls_default(); 190 utf8 = 0; 191 } else if (!strcmp(user.iocharset, "utf8")) { 192 iocharset = load_nls_default(); 193 utf8 = 1; 194 } else { 195 iocharset = load_nls(user.iocharset); 196 if (!iocharset) { 197 unload_nls(codepage); 198 return -EBADRQC; 199 } 200 utf8 = 0; 201 } 202 203 mutex_lock(&server->root_setup_lock); 204 if (server->root_setuped) { 205 oldset_cp = codepage; 206 oldset_io = iocharset; 207 err = -EBUSY; 208 } else { 209 if (utf8) 210 NCP_SET_FLAG(server, NCP_FLAG_UTF8); 211 else 212 NCP_CLR_FLAG(server, NCP_FLAG_UTF8); 213 oldset_cp = server->nls_vol; 214 server->nls_vol = codepage; 215 oldset_io = server->nls_io; 216 server->nls_io = iocharset; 217 err = 0; 218 } 219 mutex_unlock(&server->root_setup_lock); 220 unload_nls(oldset_cp); 221 unload_nls(oldset_io); 222 223 return err; 224} 225 226static int 227ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) 228{ 229 struct ncp_nls_ioctl user; 230 int len; 231 232 memset(&user, 0, sizeof(user)); 233 mutex_lock(&server->root_setup_lock); 234 if (server->nls_vol && server->nls_vol->charset) { 235 len = strlen(server->nls_vol->charset); 236 if (len > NCP_IOCSNAME_LEN) 237 len = NCP_IOCSNAME_LEN; 238 strncpy(user.codepage, server->nls_vol->charset, len); 239 user.codepage[len] = 0; 240 } 241 242 if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) 243 strcpy(user.iocharset, "utf8"); 244 else if (server->nls_io && server->nls_io->charset) { 245 len = strlen(server->nls_io->charset); 246 if (len > NCP_IOCSNAME_LEN) 247 len = NCP_IOCSNAME_LEN; 248 strncpy(user.iocharset, server->nls_io->charset, len); 249 user.iocharset[len] = 0; 250 } 251 mutex_unlock(&server->root_setup_lock); 252 253 if (copy_to_user(arg, &user, sizeof(user))) 254 return -EFAULT; 255 return 0; 256} 257#endif /* CONFIG_NCPFS_NLS */ 258 259static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg) 260{ 261 struct ncp_server *server = NCP_SERVER(inode); 262 int result; 263 struct ncp_ioctl_request request; 264 char* bouncebuffer; 265 void __user *argp = (void __user *)arg; 266 267 switch (cmd) { 268#ifdef CONFIG_COMPAT 269 case NCP_IOC_NCPREQUEST_32: 270#endif 271 case NCP_IOC_NCPREQUEST: 272#ifdef CONFIG_COMPAT 273 if (cmd == NCP_IOC_NCPREQUEST_32) { 274 struct compat_ncp_ioctl_request request32; 275 if (copy_from_user(&request32, argp, sizeof(request32))) 276 return -EFAULT; 277 request.function = request32.function; 278 request.size = request32.size; 279 request.data = compat_ptr(request32.data); 280 } else 281#endif 282 if (copy_from_user(&request, argp, sizeof(request))) 283 return -EFAULT; 284 285 if ((request.function > 255) 286 || (request.size > 287 NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) { 288 return -EINVAL; 289 } 290 bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL); 291 if (!bouncebuffer) 292 return -ENOMEM; 293 if (copy_from_user(bouncebuffer, request.data, request.size)) { 294 vfree(bouncebuffer); 295 return -EFAULT; 296 } 297 ncp_lock_server(server); 298 299 /* FIXME: We hack around in the server's structures 300 here to be able to use ncp_request */ 301 302 server->has_subfunction = 0; 303 server->current_size = request.size; 304 memcpy(server->packet, bouncebuffer, request.size); 305 306 result = ncp_request2(server, request.function, 307 bouncebuffer, NCP_PACKET_SIZE_INTERNAL); 308 if (result < 0) 309 result = -EIO; 310 else 311 result = server->reply_size; 312 ncp_unlock_server(server); 313 ncp_dbg(1, "copy %d bytes\n", result); 314 if (result >= 0) 315 if (copy_to_user(request.data, bouncebuffer, result)) 316 result = -EFAULT; 317 vfree(bouncebuffer); 318 return result; 319 320 case NCP_IOC_CONN_LOGGED_IN: 321 322 if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE)) 323 return -EINVAL; 324 mutex_lock(&server->root_setup_lock); 325 if (server->root_setuped) 326 result = -EBUSY; 327 else { 328 result = ncp_conn_logged_in(inode->i_sb); 329 if (result == 0) 330 server->root_setuped = 1; 331 } 332 mutex_unlock(&server->root_setup_lock); 333 return result; 334 335 case NCP_IOC_GET_FS_INFO: 336 return ncp_get_fs_info(server, inode, argp); 337 338 case NCP_IOC_GET_FS_INFO_V2: 339 return ncp_get_fs_info_v2(server, inode, argp); 340 341#ifdef CONFIG_COMPAT 342 case NCP_IOC_GET_FS_INFO_V2_32: 343 return ncp_get_compat_fs_info_v2(server, inode, argp); 344#endif 345 /* we have too many combinations of CONFIG_COMPAT, 346 * CONFIG_64BIT and CONFIG_UID16, so just handle 347 * any of the possible ioctls */ 348 case NCP_IOC_GETMOUNTUID16: 349 { 350 u16 uid; 351 352 SET_UID(uid, from_kuid_munged(current_user_ns(), server->m.mounted_uid)); 353 if (put_user(uid, (u16 __user *)argp)) 354 return -EFAULT; 355 return 0; 356 } 357 case NCP_IOC_GETMOUNTUID32: 358 { 359 uid_t uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid); 360 if (put_user(uid, (u32 __user *)argp)) 361 return -EFAULT; 362 return 0; 363 } 364 case NCP_IOC_GETMOUNTUID64: 365 { 366 uid_t uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid); 367 if (put_user(uid, (u64 __user *)argp)) 368 return -EFAULT; 369 return 0; 370 } 371 case NCP_IOC_GETROOT: 372 { 373 struct ncp_setroot_ioctl sr; 374 375 result = -EACCES; 376 mutex_lock(&server->root_setup_lock); 377 if (server->m.mounted_vol[0]) { 378 struct dentry* dentry = inode->i_sb->s_root; 379 380 if (dentry) { 381 struct inode* s_inode = d_inode(dentry); 382 383 if (s_inode) { 384 sr.volNumber = NCP_FINFO(s_inode)->volNumber; 385 sr.dirEntNum = NCP_FINFO(s_inode)->dirEntNum; 386 sr.namespace = server->name_space[sr.volNumber]; 387 result = 0; 388 } else 389 ncp_dbg(1, "d_inode(s_root)==NULL\n"); 390 } else 391 ncp_dbg(1, "s_root==NULL\n"); 392 } else { 393 sr.volNumber = -1; 394 sr.namespace = 0; 395 sr.dirEntNum = 0; 396 result = 0; 397 } 398 mutex_unlock(&server->root_setup_lock); 399 if (!result && copy_to_user(argp, &sr, sizeof(sr))) 400 result = -EFAULT; 401 return result; 402 } 403 404 case NCP_IOC_SETROOT: 405 { 406 struct ncp_setroot_ioctl sr; 407 __u32 vnum; 408 __le32 de; 409 __le32 dosde; 410 struct dentry* dentry; 411 412 if (copy_from_user(&sr, argp, sizeof(sr))) 413 return -EFAULT; 414 mutex_lock(&server->root_setup_lock); 415 if (server->root_setuped) 416 result = -EBUSY; 417 else { 418 if (sr.volNumber < 0) { 419 server->m.mounted_vol[0] = 0; 420 vnum = NCP_NUMBER_OF_VOLUMES; 421 de = 0; 422 dosde = 0; 423 result = 0; 424 } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) { 425 result = -EINVAL; 426 } else if (ncp_mount_subdir(server, sr.volNumber, 427 sr.namespace, sr.dirEntNum, 428 &vnum, &de, &dosde)) { 429 result = -ENOENT; 430 } else 431 result = 0; 432 433 if (result == 0) { 434 dentry = inode->i_sb->s_root; 435 if (dentry) { 436 struct inode* s_inode = d_inode(dentry); 437 438 if (s_inode) { 439 NCP_FINFO(s_inode)->volNumber = vnum; 440 NCP_FINFO(s_inode)->dirEntNum = de; 441 NCP_FINFO(s_inode)->DosDirNum = dosde; 442 server->root_setuped = 1; 443 } else { 444 ncp_dbg(1, "d_inode(s_root)==NULL\n"); 445 result = -EIO; 446 } 447 } else { 448 ncp_dbg(1, "s_root==NULL\n"); 449 result = -EIO; 450 } 451 } 452 } 453 mutex_unlock(&server->root_setup_lock); 454 455 return result; 456 } 457 458#ifdef CONFIG_NCPFS_PACKET_SIGNING 459 case NCP_IOC_SIGN_INIT: 460 { 461 struct ncp_sign_init sign; 462 463 if (argp) 464 if (copy_from_user(&sign, argp, sizeof(sign))) 465 return -EFAULT; 466 ncp_lock_server(server); 467 mutex_lock(&server->rcv.creq_mutex); 468 if (argp) { 469 if (server->sign_wanted) { 470 memcpy(server->sign_root,sign.sign_root,8); 471 memcpy(server->sign_last,sign.sign_last,16); 472 server->sign_active = 1; 473 } 474 /* ignore when signatures not wanted */ 475 } else { 476 server->sign_active = 0; 477 } 478 mutex_unlock(&server->rcv.creq_mutex); 479 ncp_unlock_server(server); 480 return 0; 481 } 482 483 case NCP_IOC_SIGN_WANTED: 484 { 485 int state; 486 487 ncp_lock_server(server); 488 state = server->sign_wanted; 489 ncp_unlock_server(server); 490 if (put_user(state, (int __user *)argp)) 491 return -EFAULT; 492 return 0; 493 } 494 495 case NCP_IOC_SET_SIGN_WANTED: 496 { 497 int newstate; 498 499 /* get only low 8 bits... */ 500 if (get_user(newstate, (unsigned char __user *)argp)) 501 return -EFAULT; 502 result = 0; 503 ncp_lock_server(server); 504 if (server->sign_active) { 505 /* cannot turn signatures OFF when active */ 506 if (!newstate) 507 result = -EINVAL; 508 } else { 509 server->sign_wanted = newstate != 0; 510 } 511 ncp_unlock_server(server); 512 return result; 513 } 514 515#endif /* CONFIG_NCPFS_PACKET_SIGNING */ 516 517#ifdef CONFIG_NCPFS_IOCTL_LOCKING 518 case NCP_IOC_LOCKUNLOCK: 519 { 520 struct ncp_lock_ioctl rqdata; 521 522 if (copy_from_user(&rqdata, argp, sizeof(rqdata))) 523 return -EFAULT; 524 if (rqdata.origin != 0) 525 return -EINVAL; 526 /* check for cmd */ 527 switch (rqdata.cmd) { 528 case NCP_LOCK_EX: 529 case NCP_LOCK_SH: 530 if (rqdata.timeout < 0) 531 return -EINVAL; 532 if (rqdata.timeout == 0) 533 rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; 534 else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT) 535 rqdata.timeout = NCP_LOCK_MAX_TIMEOUT; 536 break; 537 case NCP_LOCK_LOG: 538 rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; /* has no effect */ 539 case NCP_LOCK_CLEAR: 540 break; 541 default: 542 return -EINVAL; 543 } 544 /* locking needs both read and write access */ 545 if ((result = ncp_make_open(inode, O_RDWR)) != 0) 546 { 547 return result; 548 } 549 result = -EISDIR; 550 if (!S_ISREG(inode->i_mode)) 551 goto outrel; 552 if (rqdata.cmd == NCP_LOCK_CLEAR) 553 { 554 result = ncp_ClearPhysicalRecord(NCP_SERVER(inode), 555 NCP_FINFO(inode)->file_handle, 556 rqdata.offset, 557 rqdata.length); 558 if (result > 0) result = 0; /* no such lock */ 559 } 560 else 561 { 562 int lockcmd; 563 564 switch (rqdata.cmd) 565 { 566 case NCP_LOCK_EX: lockcmd=1; break; 567 case NCP_LOCK_SH: lockcmd=3; break; 568 default: lockcmd=0; break; 569 } 570 result = ncp_LogPhysicalRecord(NCP_SERVER(inode), 571 NCP_FINFO(inode)->file_handle, 572 lockcmd, 573 rqdata.offset, 574 rqdata.length, 575 rqdata.timeout); 576 if (result > 0) result = -EAGAIN; 577 } 578outrel: 579 ncp_inode_close(inode); 580 return result; 581 } 582#endif /* CONFIG_NCPFS_IOCTL_LOCKING */ 583 584#ifdef CONFIG_COMPAT 585 case NCP_IOC_GETOBJECTNAME_32: 586 { 587 struct compat_ncp_objectname_ioctl user; 588 size_t outl; 589 590 if (copy_from_user(&user, argp, sizeof(user))) 591 return -EFAULT; 592 down_read(&server->auth_rwsem); 593 user.auth_type = server->auth.auth_type; 594 outl = user.object_name_len; 595 user.object_name_len = server->auth.object_name_len; 596 if (outl > user.object_name_len) 597 outl = user.object_name_len; 598 result = 0; 599 if (outl) { 600 if (copy_to_user(compat_ptr(user.object_name), 601 server->auth.object_name, 602 outl)) 603 result = -EFAULT; 604 } 605 up_read(&server->auth_rwsem); 606 if (!result && copy_to_user(argp, &user, sizeof(user))) 607 result = -EFAULT; 608 return result; 609 } 610#endif 611 612 case NCP_IOC_GETOBJECTNAME: 613 { 614 struct ncp_objectname_ioctl user; 615 size_t outl; 616 617 if (copy_from_user(&user, argp, sizeof(user))) 618 return -EFAULT; 619 down_read(&server->auth_rwsem); 620 user.auth_type = server->auth.auth_type; 621 outl = user.object_name_len; 622 user.object_name_len = server->auth.object_name_len; 623 if (outl > user.object_name_len) 624 outl = user.object_name_len; 625 result = 0; 626 if (outl) { 627 if (copy_to_user(user.object_name, 628 server->auth.object_name, 629 outl)) 630 result = -EFAULT; 631 } 632 up_read(&server->auth_rwsem); 633 if (!result && copy_to_user(argp, &user, sizeof(user))) 634 result = -EFAULT; 635 return result; 636 } 637 638#ifdef CONFIG_COMPAT 639 case NCP_IOC_SETOBJECTNAME_32: 640#endif 641 case NCP_IOC_SETOBJECTNAME: 642 { 643 struct ncp_objectname_ioctl user; 644 void* newname; 645 void* oldname; 646 size_t oldnamelen; 647 void* oldprivate; 648 size_t oldprivatelen; 649 650#ifdef CONFIG_COMPAT 651 if (cmd == NCP_IOC_SETOBJECTNAME_32) { 652 struct compat_ncp_objectname_ioctl user32; 653 if (copy_from_user(&user32, argp, sizeof(user32))) 654 return -EFAULT; 655 user.auth_type = user32.auth_type; 656 user.object_name_len = user32.object_name_len; 657 user.object_name = compat_ptr(user32.object_name); 658 } else 659#endif 660 if (copy_from_user(&user, argp, sizeof(user))) 661 return -EFAULT; 662 663 if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN) 664 return -ENOMEM; 665 if (user.object_name_len) { 666 newname = memdup_user(user.object_name, 667 user.object_name_len); 668 if (IS_ERR(newname)) 669 return PTR_ERR(newname); 670 } else { 671 newname = NULL; 672 } 673 down_write(&server->auth_rwsem); 674 oldname = server->auth.object_name; 675 oldnamelen = server->auth.object_name_len; 676 oldprivate = server->priv.data; 677 oldprivatelen = server->priv.len; 678 server->auth.auth_type = user.auth_type; 679 server->auth.object_name_len = user.object_name_len; 680 server->auth.object_name = newname; 681 server->priv.len = 0; 682 server->priv.data = NULL; 683 up_write(&server->auth_rwsem); 684 kfree(oldprivate); 685 kfree(oldname); 686 return 0; 687 } 688 689#ifdef CONFIG_COMPAT 690 case NCP_IOC_GETPRIVATEDATA_32: 691#endif 692 case NCP_IOC_GETPRIVATEDATA: 693 { 694 struct ncp_privatedata_ioctl user; 695 size_t outl; 696 697#ifdef CONFIG_COMPAT 698 if (cmd == NCP_IOC_GETPRIVATEDATA_32) { 699 struct compat_ncp_privatedata_ioctl user32; 700 if (copy_from_user(&user32, argp, sizeof(user32))) 701 return -EFAULT; 702 user.len = user32.len; 703 user.data = compat_ptr(user32.data); 704 } else 705#endif 706 if (copy_from_user(&user, argp, sizeof(user))) 707 return -EFAULT; 708 709 down_read(&server->auth_rwsem); 710 outl = user.len; 711 user.len = server->priv.len; 712 if (outl > user.len) outl = user.len; 713 result = 0; 714 if (outl) { 715 if (copy_to_user(user.data, 716 server->priv.data, 717 outl)) 718 result = -EFAULT; 719 } 720 up_read(&server->auth_rwsem); 721 if (result) 722 return result; 723#ifdef CONFIG_COMPAT 724 if (cmd == NCP_IOC_GETPRIVATEDATA_32) { 725 struct compat_ncp_privatedata_ioctl user32; 726 user32.len = user.len; 727 user32.data = (unsigned long) user.data; 728 if (copy_to_user(argp, &user32, sizeof(user32))) 729 return -EFAULT; 730 } else 731#endif 732 if (copy_to_user(argp, &user, sizeof(user))) 733 return -EFAULT; 734 735 return 0; 736 } 737 738#ifdef CONFIG_COMPAT 739 case NCP_IOC_SETPRIVATEDATA_32: 740#endif 741 case NCP_IOC_SETPRIVATEDATA: 742 { 743 struct ncp_privatedata_ioctl user; 744 void* new; 745 void* old; 746 size_t oldlen; 747 748#ifdef CONFIG_COMPAT 749 if (cmd == NCP_IOC_SETPRIVATEDATA_32) { 750 struct compat_ncp_privatedata_ioctl user32; 751 if (copy_from_user(&user32, argp, sizeof(user32))) 752 return -EFAULT; 753 user.len = user32.len; 754 user.data = compat_ptr(user32.data); 755 } else 756#endif 757 if (copy_from_user(&user, argp, sizeof(user))) 758 return -EFAULT; 759 760 if (user.len > NCP_PRIVATE_DATA_MAX_LEN) 761 return -ENOMEM; 762 if (user.len) { 763 new = memdup_user(user.data, user.len); 764 if (IS_ERR(new)) 765 return PTR_ERR(new); 766 } else { 767 new = NULL; 768 } 769 down_write(&server->auth_rwsem); 770 old = server->priv.data; 771 oldlen = server->priv.len; 772 server->priv.len = user.len; 773 server->priv.data = new; 774 up_write(&server->auth_rwsem); 775 kfree(old); 776 return 0; 777 } 778 779#ifdef CONFIG_NCPFS_NLS 780 case NCP_IOC_SETCHARSETS: 781 return ncp_set_charsets(server, argp); 782 783 case NCP_IOC_GETCHARSETS: 784 return ncp_get_charsets(server, argp); 785 786#endif /* CONFIG_NCPFS_NLS */ 787 788 case NCP_IOC_SETDENTRYTTL: 789 { 790 u_int32_t user; 791 792 if (copy_from_user(&user, argp, sizeof(user))) 793 return -EFAULT; 794 /* 20 secs at most... */ 795 if (user > 20000) 796 return -EINVAL; 797 user = (user * HZ) / 1000; 798 atomic_set(&server->dentry_ttl, user); 799 return 0; 800 } 801 802 case NCP_IOC_GETDENTRYTTL: 803 { 804 u_int32_t user = (atomic_read(&server->dentry_ttl) * 1000) / HZ; 805 if (copy_to_user(argp, &user, sizeof(user))) 806 return -EFAULT; 807 return 0; 808 } 809 810 } 811 return -EINVAL; 812} 813 814long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 815{ 816 struct inode *inode = file_inode(filp); 817 struct ncp_server *server = NCP_SERVER(inode); 818 kuid_t uid = current_uid(); 819 int need_drop_write = 0; 820 long ret; 821 822 switch (cmd) { 823 case NCP_IOC_SETCHARSETS: 824 case NCP_IOC_CONN_LOGGED_IN: 825 case NCP_IOC_SETROOT: 826 if (!capable(CAP_SYS_ADMIN)) { 827 ret = -EPERM; 828 goto out; 829 } 830 break; 831 } 832 if (!uid_eq(server->m.mounted_uid, uid)) { 833 switch (cmd) { 834 /* 835 * Only mount owner can issue these ioctls. Information 836 * necessary to authenticate to other NDS servers are 837 * stored here. 838 */ 839 case NCP_IOC_GETOBJECTNAME: 840 case NCP_IOC_SETOBJECTNAME: 841 case NCP_IOC_GETPRIVATEDATA: 842 case NCP_IOC_SETPRIVATEDATA: 843#ifdef CONFIG_COMPAT 844 case NCP_IOC_GETOBJECTNAME_32: 845 case NCP_IOC_SETOBJECTNAME_32: 846 case NCP_IOC_GETPRIVATEDATA_32: 847 case NCP_IOC_SETPRIVATEDATA_32: 848#endif 849 ret = -EACCES; 850 goto out; 851 /* 852 * These require write access on the inode if user id 853 * does not match. Note that they do not write to the 854 * file... But old code did mnt_want_write, so I keep 855 * it as is. Of course not for mountpoint owner, as 856 * that breaks read-only mounts altogether as ncpmount 857 * needs working NCP_IOC_NCPREQUEST and 858 * NCP_IOC_GET_FS_INFO. Some of these codes (setdentryttl, 859 * signinit, setsignwanted) should be probably restricted 860 * to owner only, or even more to CAP_SYS_ADMIN). 861 */ 862 case NCP_IOC_GET_FS_INFO: 863 case NCP_IOC_GET_FS_INFO_V2: 864 case NCP_IOC_NCPREQUEST: 865 case NCP_IOC_SETDENTRYTTL: 866 case NCP_IOC_SIGN_INIT: 867 case NCP_IOC_LOCKUNLOCK: 868 case NCP_IOC_SET_SIGN_WANTED: 869#ifdef CONFIG_COMPAT 870 case NCP_IOC_GET_FS_INFO_V2_32: 871 case NCP_IOC_NCPREQUEST_32: 872#endif 873 ret = mnt_want_write_file(filp); 874 if (ret) 875 goto out; 876 need_drop_write = 1; 877 ret = inode_permission(inode, MAY_WRITE); 878 if (ret) 879 goto outDropWrite; 880 break; 881 /* 882 * Read access required. 883 */ 884 case NCP_IOC_GETMOUNTUID16: 885 case NCP_IOC_GETMOUNTUID32: 886 case NCP_IOC_GETMOUNTUID64: 887 case NCP_IOC_GETROOT: 888 case NCP_IOC_SIGN_WANTED: 889 ret = inode_permission(inode, MAY_READ); 890 if (ret) 891 goto out; 892 break; 893 /* 894 * Anybody can read these. 895 */ 896 case NCP_IOC_GETCHARSETS: 897 case NCP_IOC_GETDENTRYTTL: 898 default: 899 /* Three codes below are protected by CAP_SYS_ADMIN above. */ 900 case NCP_IOC_SETCHARSETS: 901 case NCP_IOC_CONN_LOGGED_IN: 902 case NCP_IOC_SETROOT: 903 break; 904 } 905 } 906 ret = __ncp_ioctl(inode, cmd, arg); 907outDropWrite: 908 if (need_drop_write) 909 mnt_drop_write_file(filp); 910out: 911 return ret; 912} 913 914#ifdef CONFIG_COMPAT 915long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 916{ 917 long ret; 918 919 arg = (unsigned long) compat_ptr(arg); 920 ret = ncp_ioctl(file, cmd, arg); 921 return ret; 922} 923#endif