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