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/smp_lock.h> 21#include <linux/vmalloc.h> 22#include <linux/sched.h> 23 24#include <linux/ncp_fs.h> 25 26#include <asm/uaccess.h> 27 28#include "ncplib_kernel.h" 29 30/* maximum limit for ncp_objectname_ioctl */ 31#define NCP_OBJECT_NAME_MAX_LEN 4096 32/* maximum limit for ncp_privatedata_ioctl */ 33#define NCP_PRIVATE_DATA_MAX_LEN 8192 34/* maximum negotiable packet size */ 35#define NCP_PACKET_SIZE_INTERNAL 65536 36 37static int 38ncp_get_fs_info(struct ncp_server * server, struct file *file, 39 struct ncp_fs_info __user *arg) 40{ 41 struct inode *inode = file->f_path.dentry->d_inode; 42 struct ncp_fs_info info; 43 44 if (file_permission(file, MAY_WRITE) != 0 45 && current_uid() != server->m.mounted_uid) 46 return -EACCES; 47 48 if (copy_from_user(&info, arg, sizeof(info))) 49 return -EFAULT; 50 51 if (info.version != NCP_GET_FS_INFO_VERSION) { 52 DPRINTK("info.version invalid: %d\n", info.version); 53 return -EINVAL; 54 } 55 /* TODO: info.addr = server->m.serv_addr; */ 56 SET_UID(info.mounted_uid, server->m.mounted_uid); 57 info.connection = server->connection; 58 info.buffer_size = server->buffer_size; 59 info.volume_number = NCP_FINFO(inode)->volNumber; 60 info.directory_id = NCP_FINFO(inode)->DosDirNum; 61 62 if (copy_to_user(arg, &info, sizeof(info))) 63 return -EFAULT; 64 return 0; 65} 66 67static int 68ncp_get_fs_info_v2(struct ncp_server * server, struct file *file, 69 struct ncp_fs_info_v2 __user * arg) 70{ 71 struct inode *inode = file->f_path.dentry->d_inode; 72 struct ncp_fs_info_v2 info2; 73 74 if (file_permission(file, MAY_WRITE) != 0 75 && current_uid() != server->m.mounted_uid) 76 return -EACCES; 77 78 if (copy_from_user(&info2, arg, sizeof(info2))) 79 return -EFAULT; 80 81 if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { 82 DPRINTK("info.version invalid: %d\n", info2.version); 83 return -EINVAL; 84 } 85 info2.mounted_uid = server->m.mounted_uid; 86 info2.connection = server->connection; 87 info2.buffer_size = server->buffer_size; 88 info2.volume_number = NCP_FINFO(inode)->volNumber; 89 info2.directory_id = NCP_FINFO(inode)->DosDirNum; 90 info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; 91 92 if (copy_to_user(arg, &info2, sizeof(info2))) 93 return -EFAULT; 94 return 0; 95} 96 97#ifdef CONFIG_COMPAT 98struct compat_ncp_objectname_ioctl 99{ 100 s32 auth_type; 101 u32 object_name_len; 102 compat_caddr_t object_name; /* a userspace data, in most cases user name */ 103}; 104 105struct compat_ncp_fs_info_v2 { 106 s32 version; 107 u32 mounted_uid; 108 u32 connection; 109 u32 buffer_size; 110 111 u32 volume_number; 112 u32 directory_id; 113 114 u32 dummy1; 115 u32 dummy2; 116 u32 dummy3; 117}; 118 119struct compat_ncp_ioctl_request { 120 u32 function; 121 u32 size; 122 compat_caddr_t data; 123}; 124 125struct compat_ncp_privatedata_ioctl 126{ 127 u32 len; 128 compat_caddr_t data; /* ~1000 for NDS */ 129}; 130 131#define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct compat_ncp_fs_info_v2) 132#define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct compat_ncp_ioctl_request) 133#define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct compat_ncp_objectname_ioctl) 134#define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct compat_ncp_objectname_ioctl) 135#define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct compat_ncp_privatedata_ioctl) 136#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl) 137 138static int 139ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file, 140 struct compat_ncp_fs_info_v2 __user * arg) 141{ 142 struct inode *inode = file->f_path.dentry->d_inode; 143 struct compat_ncp_fs_info_v2 info2; 144 145 if (file_permission(file, MAY_WRITE) != 0 146 && current_uid() != server->m.mounted_uid) 147 return -EACCES; 148 149 if (copy_from_user(&info2, arg, sizeof(info2))) 150 return -EFAULT; 151 152 if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { 153 DPRINTK("info.version invalid: %d\n", info2.version); 154 return -EINVAL; 155 } 156 info2.mounted_uid = server->m.mounted_uid; 157 info2.connection = server->connection; 158 info2.buffer_size = server->buffer_size; 159 info2.volume_number = NCP_FINFO(inode)->volNumber; 160 info2.directory_id = NCP_FINFO(inode)->DosDirNum; 161 info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; 162 163 if (copy_to_user(arg, &info2, sizeof(info2))) 164 return -EFAULT; 165 return 0; 166} 167#endif 168 169#define NCP_IOC_GETMOUNTUID16 _IOW('n', 2, u16) 170#define NCP_IOC_GETMOUNTUID32 _IOW('n', 2, u32) 171#define NCP_IOC_GETMOUNTUID64 _IOW('n', 2, u64) 172 173#ifdef CONFIG_NCPFS_NLS 174/* Here we are select the iocharset and the codepage for NLS. 175 * Thanks Petr Vandrovec for idea and many hints. 176 */ 177static int 178ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) 179{ 180 struct ncp_nls_ioctl user; 181 struct nls_table *codepage; 182 struct nls_table *iocharset; 183 struct nls_table *oldset_io; 184 struct nls_table *oldset_cp; 185 186 if (!capable(CAP_SYS_ADMIN)) 187 return -EACCES; 188 if (server->root_setuped) 189 return -EBUSY; 190 191 if (copy_from_user(&user, arg, sizeof(user))) 192 return -EFAULT; 193 194 codepage = NULL; 195 user.codepage[NCP_IOCSNAME_LEN] = 0; 196 if (!user.codepage[0] || !strcmp(user.codepage, "default")) 197 codepage = load_nls_default(); 198 else { 199 codepage = load_nls(user.codepage); 200 if (!codepage) { 201 return -EBADRQC; 202 } 203 } 204 205 iocharset = NULL; 206 user.iocharset[NCP_IOCSNAME_LEN] = 0; 207 if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) { 208 iocharset = load_nls_default(); 209 NCP_CLR_FLAG(server, NCP_FLAG_UTF8); 210 } else if (!strcmp(user.iocharset, "utf8")) { 211 iocharset = load_nls_default(); 212 NCP_SET_FLAG(server, NCP_FLAG_UTF8); 213 } else { 214 iocharset = load_nls(user.iocharset); 215 if (!iocharset) { 216 unload_nls(codepage); 217 return -EBADRQC; 218 } 219 NCP_CLR_FLAG(server, NCP_FLAG_UTF8); 220 } 221 222 oldset_cp = server->nls_vol; 223 server->nls_vol = codepage; 224 oldset_io = server->nls_io; 225 server->nls_io = iocharset; 226 227 unload_nls(oldset_cp); 228 unload_nls(oldset_io); 229 230 return 0; 231} 232 233static int 234ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) 235{ 236 struct ncp_nls_ioctl user; 237 int len; 238 239 memset(&user, 0, sizeof(user)); 240 if (server->nls_vol && server->nls_vol->charset) { 241 len = strlen(server->nls_vol->charset); 242 if (len > NCP_IOCSNAME_LEN) 243 len = NCP_IOCSNAME_LEN; 244 strncpy(user.codepage, server->nls_vol->charset, len); 245 user.codepage[len] = 0; 246 } 247 248 if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) 249 strcpy(user.iocharset, "utf8"); 250 else if (server->nls_io && server->nls_io->charset) { 251 len = strlen(server->nls_io->charset); 252 if (len > NCP_IOCSNAME_LEN) 253 len = NCP_IOCSNAME_LEN; 254 strncpy(user.iocharset, server->nls_io->charset, len); 255 user.iocharset[len] = 0; 256 } 257 258 if (copy_to_user(arg, &user, sizeof(user))) 259 return -EFAULT; 260 return 0; 261} 262#endif /* CONFIG_NCPFS_NLS */ 263 264static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 265{ 266 struct inode *inode = filp->f_dentry->d_inode; 267 struct ncp_server *server = NCP_SERVER(inode); 268 int result; 269 struct ncp_ioctl_request request; 270 char* bouncebuffer; 271 void __user *argp = (void __user *)arg; 272 uid_t uid = current_uid(); 273 274 switch (cmd) { 275#ifdef CONFIG_COMPAT 276 case NCP_IOC_NCPREQUEST_32: 277#endif 278 case NCP_IOC_NCPREQUEST: 279 if (file_permission(filp, MAY_WRITE) != 0 280 && uid != server->m.mounted_uid) 281 return -EACCES; 282 283#ifdef CONFIG_COMPAT 284 if (cmd == NCP_IOC_NCPREQUEST_32) { 285 struct compat_ncp_ioctl_request request32; 286 if (copy_from_user(&request32, argp, sizeof(request32))) 287 return -EFAULT; 288 request.function = request32.function; 289 request.size = request32.size; 290 request.data = compat_ptr(request32.data); 291 } else 292#endif 293 if (copy_from_user(&request, argp, sizeof(request))) 294 return -EFAULT; 295 296 if ((request.function > 255) 297 || (request.size > 298 NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) { 299 return -EINVAL; 300 } 301 bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL); 302 if (!bouncebuffer) 303 return -ENOMEM; 304 if (copy_from_user(bouncebuffer, request.data, request.size)) { 305 vfree(bouncebuffer); 306 return -EFAULT; 307 } 308 ncp_lock_server(server); 309 310 311 server->has_subfunction = 0; 312 server->current_size = request.size; 313 memcpy(server->packet, bouncebuffer, request.size); 314 315 result = ncp_request2(server, request.function, 316 bouncebuffer, NCP_PACKET_SIZE_INTERNAL); 317 if (result < 0) 318 result = -EIO; 319 else 320 result = server->reply_size; 321 ncp_unlock_server(server); 322 DPRINTK("ncp_ioctl: copy %d bytes\n", 323 result); 324 if (result >= 0) 325 if (copy_to_user(request.data, bouncebuffer, result)) 326 result = -EFAULT; 327 vfree(bouncebuffer); 328 return result; 329 330 case NCP_IOC_CONN_LOGGED_IN: 331 332 if (!capable(CAP_SYS_ADMIN)) 333 return -EACCES; 334 if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE)) 335 return -EINVAL; 336 if (server->root_setuped) 337 return -EBUSY; 338 server->root_setuped = 1; 339 return ncp_conn_logged_in(inode->i_sb); 340 341 case NCP_IOC_GET_FS_INFO: 342 return ncp_get_fs_info(server, filp, argp); 343 344 case NCP_IOC_GET_FS_INFO_V2: 345 return ncp_get_fs_info_v2(server, filp, argp); 346 347#ifdef CONFIG_COMPAT 348 case NCP_IOC_GET_FS_INFO_V2_32: 349 return ncp_get_compat_fs_info_v2(server, filp, argp); 350#endif 351 /* we have too many combinations of CONFIG_COMPAT, 352 * CONFIG_64BIT and CONFIG_UID16, so just handle 353 * any of the possible ioctls */ 354 case NCP_IOC_GETMOUNTUID16: 355 case NCP_IOC_GETMOUNTUID32: 356 case NCP_IOC_GETMOUNTUID64: 357 if (file_permission(filp, MAY_READ) != 0 358 && uid != server->m.mounted_uid) 359 return -EACCES; 360 361 if (cmd == NCP_IOC_GETMOUNTUID16) { 362 u16 uid; 363 SET_UID(uid, server->m.mounted_uid); 364 if (put_user(uid, (u16 __user *)argp)) 365 return -EFAULT; 366 } else if (cmd == NCP_IOC_GETMOUNTUID32) { 367 if (put_user(server->m.mounted_uid, 368 (u32 __user *)argp)) 369 return -EFAULT; 370 } else { 371 if (put_user(server->m.mounted_uid, 372 (u64 __user *)argp)) 373 return -EFAULT; 374 } 375 return 0; 376 377 case NCP_IOC_GETROOT: 378 { 379 struct ncp_setroot_ioctl sr; 380 381 if (file_permission(filp, MAY_READ) != 0 382 && uid != server->m.mounted_uid) 383 return -EACCES; 384 385 if (server->m.mounted_vol[0]) { 386 struct dentry* dentry = inode->i_sb->s_root; 387 388 if (dentry) { 389 struct inode* s_inode = dentry->d_inode; 390 391 if (s_inode) { 392 sr.volNumber = NCP_FINFO(s_inode)->volNumber; 393 sr.dirEntNum = NCP_FINFO(s_inode)->dirEntNum; 394 sr.namespace = server->name_space[sr.volNumber]; 395 } else 396 DPRINTK("ncpfs: s_root->d_inode==NULL\n"); 397 } else 398 DPRINTK("ncpfs: s_root==NULL\n"); 399 } else { 400 sr.volNumber = -1; 401 sr.namespace = 0; 402 sr.dirEntNum = 0; 403 } 404 if (copy_to_user(argp, &sr, sizeof(sr))) 405 return -EFAULT; 406 return 0; 407 } 408 409 case NCP_IOC_SETROOT: 410 { 411 struct ncp_setroot_ioctl sr; 412 __u32 vnum; 413 __le32 de; 414 __le32 dosde; 415 struct dentry* dentry; 416 417 if (!capable(CAP_SYS_ADMIN)) 418 { 419 return -EACCES; 420 } 421 if (server->root_setuped) return -EBUSY; 422 if (copy_from_user(&sr, argp, sizeof(sr))) 423 return -EFAULT; 424 if (sr.volNumber < 0) { 425 server->m.mounted_vol[0] = 0; 426 vnum = NCP_NUMBER_OF_VOLUMES; 427 de = 0; 428 dosde = 0; 429 } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) { 430 return -EINVAL; 431 } else if (ncp_mount_subdir(server, sr.volNumber, 432 sr.namespace, sr.dirEntNum, 433 &vnum, &de, &dosde)) { 434 return -ENOENT; 435 } 436 437 dentry = inode->i_sb->s_root; 438 server->root_setuped = 1; 439 if (dentry) { 440 struct inode* s_inode = dentry->d_inode; 441 442 if (s_inode) { 443 NCP_FINFO(s_inode)->volNumber = vnum; 444 NCP_FINFO(s_inode)->dirEntNum = de; 445 NCP_FINFO(s_inode)->DosDirNum = dosde; 446 } else 447 DPRINTK("ncpfs: s_root->d_inode==NULL\n"); 448 } else 449 DPRINTK("ncpfs: s_root==NULL\n"); 450 451 return 0; 452 } 453 454#ifdef CONFIG_NCPFS_PACKET_SIGNING 455 case NCP_IOC_SIGN_INIT: 456 if (file_permission(filp, MAY_WRITE) != 0 457 && uid != server->m.mounted_uid) 458 return -EACCES; 459 460 if (argp) { 461 if (server->sign_wanted) 462 { 463 struct ncp_sign_init sign; 464 465 if (copy_from_user(&sign, argp, sizeof(sign))) 466 return -EFAULT; 467 memcpy(server->sign_root,sign.sign_root,8); 468 memcpy(server->sign_last,sign.sign_last,16); 469 server->sign_active = 1; 470 } 471 /* ignore when signatures not wanted */ 472 } else { 473 server->sign_active = 0; 474 } 475 return 0; 476 477 case NCP_IOC_SIGN_WANTED: 478 if (file_permission(filp, MAY_READ) != 0 479 && uid != server->m.mounted_uid) 480 return -EACCES; 481 482 if (put_user(server->sign_wanted, (int __user *)argp)) 483 return -EFAULT; 484 return 0; 485 486 case NCP_IOC_SET_SIGN_WANTED: 487 { 488 int newstate; 489 490 if (file_permission(filp, MAY_WRITE) != 0 491 && uid != server->m.mounted_uid) 492 return -EACCES; 493 494 /* get only low 8 bits... */ 495 if (get_user(newstate, (unsigned char __user *)argp)) 496 return -EFAULT; 497 if (server->sign_active) { 498 /* cannot turn signatures OFF when active */ 499 if (!newstate) return -EINVAL; 500 } else { 501 server->sign_wanted = newstate != 0; 502 } 503 return 0; 504 } 505 506#endif /* CONFIG_NCPFS_PACKET_SIGNING */ 507 508#ifdef CONFIG_NCPFS_IOCTL_LOCKING 509 case NCP_IOC_LOCKUNLOCK: 510 if (file_permission(filp, MAY_WRITE) != 0 511 && uid != server->m.mounted_uid) 512 return -EACCES; 513 514 { 515 struct ncp_lock_ioctl rqdata; 516 517 if (copy_from_user(&rqdata, argp, sizeof(rqdata))) 518 return -EFAULT; 519 if (rqdata.origin != 0) 520 return -EINVAL; 521 /* check for cmd */ 522 switch (rqdata.cmd) { 523 case NCP_LOCK_EX: 524 case NCP_LOCK_SH: 525 if (rqdata.timeout == 0) 526 rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; 527 else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT) 528 rqdata.timeout = NCP_LOCK_MAX_TIMEOUT; 529 break; 530 case NCP_LOCK_LOG: 531 rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; /* has no effect */ 532 case NCP_LOCK_CLEAR: 533 break; 534 default: 535 return -EINVAL; 536 } 537 /* locking needs both read and write access */ 538 if ((result = ncp_make_open(inode, O_RDWR)) != 0) 539 { 540 return result; 541 } 542 result = -EIO; 543 if (!ncp_conn_valid(server)) 544 goto outrel; 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 if (uid != server->m.mounted_uid) 583 return -EACCES; 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 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 if (outl) { 596 if (copy_to_user(compat_ptr(user.object_name), 597 server->auth.object_name, 598 outl)) return -EFAULT; 599 } 600 if (copy_to_user(argp, &user, sizeof(user))) 601 return -EFAULT; 602 return 0; 603 } 604#endif 605 606 case NCP_IOC_GETOBJECTNAME: 607 if (uid != server->m.mounted_uid) 608 return -EACCES; 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 user.auth_type = server->auth.auth_type; 616 outl = user.object_name_len; 617 user.object_name_len = server->auth.object_name_len; 618 if (outl > user.object_name_len) 619 outl = user.object_name_len; 620 if (outl) { 621 if (copy_to_user(user.object_name, 622 server->auth.object_name, 623 outl)) return -EFAULT; 624 } 625 if (copy_to_user(argp, &user, sizeof(user))) 626 return -EFAULT; 627 return 0; 628 } 629 630#ifdef CONFIG_COMPAT 631 case NCP_IOC_SETOBJECTNAME_32: 632#endif 633 case NCP_IOC_SETOBJECTNAME: 634 if (uid != server->m.mounted_uid) 635 return -EACCES; 636 { 637 struct ncp_objectname_ioctl user; 638 void* newname; 639 void* oldname; 640 size_t oldnamelen; 641 void* oldprivate; 642 size_t oldprivatelen; 643 644#ifdef CONFIG_COMPAT 645 if (cmd == NCP_IOC_SETOBJECTNAME_32) { 646 struct compat_ncp_objectname_ioctl user32; 647 if (copy_from_user(&user32, argp, sizeof(user32))) 648 return -EFAULT; 649 user.auth_type = user32.auth_type; 650 user.object_name_len = user32.object_name_len; 651 user.object_name = compat_ptr(user32.object_name); 652 } else 653#endif 654 if (copy_from_user(&user, argp, sizeof(user))) 655 return -EFAULT; 656 657 if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN) 658 return -ENOMEM; 659 if (user.object_name_len) { 660 newname = memdup_user(user.object_name, 661 user.object_name_len); 662 if (IS_ERR(newname)) 663 return PTR_ERR(newname); 664 } else { 665 newname = NULL; 666 } 667 /* enter critical section */ 668 /* maybe that kfree can sleep so do that this way */ 669 /* it is at least more SMP friendly (in future...) */ 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 /* leave critical section */ 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 if (uid != server->m.mounted_uid) 690 return -EACCES; 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 outl = user.len; 708 user.len = server->priv.len; 709 if (outl > user.len) outl = user.len; 710 if (outl) { 711 if (copy_to_user(user.data, 712 server->priv.data, 713 outl)) return -EFAULT; 714 } 715#ifdef CONFIG_COMPAT 716 if (cmd == NCP_IOC_GETPRIVATEDATA_32) { 717 struct compat_ncp_privatedata_ioctl user32; 718 user32.len = user.len; 719 user32.data = (unsigned long) user.data; 720 if (copy_to_user(argp, &user32, sizeof(user32))) 721 return -EFAULT; 722 } else 723#endif 724 if (copy_to_user(argp, &user, sizeof(user))) 725 return -EFAULT; 726 727 return 0; 728 } 729 730#ifdef CONFIG_COMPAT 731 case NCP_IOC_SETPRIVATEDATA_32: 732#endif 733 case NCP_IOC_SETPRIVATEDATA: 734 if (uid != server->m.mounted_uid) 735 return -EACCES; 736 { 737 struct ncp_privatedata_ioctl user; 738 void* new; 739 void* old; 740 size_t oldlen; 741 742#ifdef CONFIG_COMPAT 743 if (cmd == NCP_IOC_SETPRIVATEDATA_32) { 744 struct compat_ncp_privatedata_ioctl user32; 745 if (copy_from_user(&user32, argp, sizeof(user32))) 746 return -EFAULT; 747 user.len = user32.len; 748 user.data = compat_ptr(user32.data); 749 } else 750#endif 751 if (copy_from_user(&user, argp, sizeof(user))) 752 return -EFAULT; 753 754 if (user.len > NCP_PRIVATE_DATA_MAX_LEN) 755 return -ENOMEM; 756 if (user.len) { 757 new = memdup_user(user.data, user.len); 758 if (IS_ERR(new)) 759 return PTR_ERR(new); 760 } else { 761 new = NULL; 762 } 763 /* enter critical section */ 764 old = server->priv.data; 765 oldlen = server->priv.len; 766 server->priv.len = user.len; 767 server->priv.data = new; 768 /* leave critical section */ 769 kfree(old); 770 return 0; 771 } 772 773#ifdef CONFIG_NCPFS_NLS 774 case NCP_IOC_SETCHARSETS: 775 return ncp_set_charsets(server, argp); 776 777 case NCP_IOC_GETCHARSETS: 778 return ncp_get_charsets(server, argp); 779 780#endif /* CONFIG_NCPFS_NLS */ 781 782 case NCP_IOC_SETDENTRYTTL: 783 if (file_permission(filp, MAY_WRITE) != 0 && 784 uid != server->m.mounted_uid) 785 return -EACCES; 786 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 server->dentry_ttl = user; 797 return 0; 798 } 799 800 case NCP_IOC_GETDENTRYTTL: 801 { 802 u_int32_t user = (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 812static int ncp_ioctl_need_write(unsigned int cmd) 813{ 814 switch (cmd) { 815 case NCP_IOC_GET_FS_INFO: 816 case NCP_IOC_GET_FS_INFO_V2: 817 case NCP_IOC_NCPREQUEST: 818 case NCP_IOC_SETDENTRYTTL: 819 case NCP_IOC_SIGN_INIT: 820 case NCP_IOC_LOCKUNLOCK: 821 case NCP_IOC_SET_SIGN_WANTED: 822 return 1; 823 case NCP_IOC_GETOBJECTNAME: 824 case NCP_IOC_SETOBJECTNAME: 825 case NCP_IOC_GETPRIVATEDATA: 826 case NCP_IOC_SETPRIVATEDATA: 827 case NCP_IOC_SETCHARSETS: 828 case NCP_IOC_GETCHARSETS: 829 case NCP_IOC_CONN_LOGGED_IN: 830 case NCP_IOC_GETDENTRYTTL: 831 case NCP_IOC_GETMOUNTUID2: 832 case NCP_IOC_SIGN_WANTED: 833 case NCP_IOC_GETROOT: 834 case NCP_IOC_SETROOT: 835 return 0; 836 default: 837 /* unknown IOCTL command, assume write */ 838 return 1; 839 } 840} 841 842long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 843{ 844 long ret; 845 846 lock_kernel(); 847 if (ncp_ioctl_need_write(cmd)) { 848 /* 849 * inside the ioctl(), any failures which 850 * are because of file_permission() are 851 * -EACCESS, so it seems consistent to keep 852 * that here. 853 */ 854 if (mnt_want_write(filp->f_path.mnt)) { 855 ret = -EACCES; 856 goto out; 857 } 858 } 859 ret = __ncp_ioctl(filp, cmd, arg); 860 if (ncp_ioctl_need_write(cmd)) 861 mnt_drop_write(filp->f_path.mnt); 862 863out: 864 unlock_kernel(); 865 return ret; 866} 867 868#ifdef CONFIG_COMPAT 869long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 870{ 871 long ret; 872 873 lock_kernel(); 874 arg = (unsigned long) compat_ptr(arg); 875 ret = ncp_ioctl(file, cmd, arg); 876 unlock_kernel(); 877 return ret; 878} 879#endif 880