Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / fs / ncpfs / ioctl.c
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/highuid.h>
18 #include <linux/smp_lock.h>
19 #include <linux/vmalloc.h>
20
21 #include <linux/ncp_fs.h>
22
23 #include <asm/uaccess.h>
24
25 #include "ncplib_kernel.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
34 static int
35 ncp_get_fs_info(struct ncp_server * server, struct file *file,
36                 struct ncp_fs_info __user *arg)
37 {
38         struct inode *inode = file->f_path.dentry->d_inode;
39         struct ncp_fs_info info;
40
41         if ((file_permission(file, MAY_WRITE) != 0)
42             && (current->uid != server->m.mounted_uid)) {
43                 return -EACCES;
44         }
45         if (copy_from_user(&info, arg, sizeof(info)))
46                 return -EFAULT;
47
48         if (info.version != NCP_GET_FS_INFO_VERSION) {
49                 DPRINTK("info.version invalid: %d\n", info.version);
50                 return -EINVAL;
51         }
52         /* TODO: info.addr = server->m.serv_addr; */
53         SET_UID(info.mounted_uid, server->m.mounted_uid);
54         info.connection         = server->connection;
55         info.buffer_size        = server->buffer_size;
56         info.volume_number      = NCP_FINFO(inode)->volNumber;
57         info.directory_id       = NCP_FINFO(inode)->DosDirNum;
58
59         if (copy_to_user(arg, &info, sizeof(info)))
60                 return -EFAULT;
61         return 0;
62 }
63
64 static int
65 ncp_get_fs_info_v2(struct ncp_server * server, struct file *file,
66                    struct ncp_fs_info_v2 __user * arg)
67 {
68         struct inode *inode = file->f_path.dentry->d_inode;
69         struct ncp_fs_info_v2 info2;
70
71         if ((file_permission(file, MAY_WRITE) != 0)
72             && (current->uid != server->m.mounted_uid)) {
73                 return -EACCES;
74         }
75         if (copy_from_user(&info2, arg, sizeof(info2)))
76                 return -EFAULT;
77
78         if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
79                 DPRINTK("info.version invalid: %d\n", info2.version);
80                 return -EINVAL;
81         }
82         info2.mounted_uid   = server->m.mounted_uid;
83         info2.connection    = server->connection;
84         info2.buffer_size   = server->buffer_size;
85         info2.volume_number = NCP_FINFO(inode)->volNumber;
86         info2.directory_id  = NCP_FINFO(inode)->DosDirNum;
87         info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
88
89         if (copy_to_user(arg, &info2, sizeof(info2)))
90                 return -EFAULT;
91         return 0;
92 }
93
94 #ifdef CONFIG_COMPAT
95 struct compat_ncp_objectname_ioctl
96 {
97         s32             auth_type;
98         u32             object_name_len;
99         compat_caddr_t  object_name;    /* an userspace data, in most cases user name */
100 };
101
102 struct compat_ncp_fs_info_v2 {
103         s32 version;
104         u32 mounted_uid;
105         u32 connection;
106         u32 buffer_size;
107
108         u32 volume_number;
109         u32 directory_id;
110
111         u32 dummy1;
112         u32 dummy2;
113         u32 dummy3;
114 };
115
116 struct compat_ncp_ioctl_request {
117         u32 function;
118         u32 size;
119         compat_caddr_t data;
120 };
121
122 struct compat_ncp_privatedata_ioctl
123 {
124         u32             len;
125         compat_caddr_t  data;           /* ~1000 for NDS */
126 };
127
128 #define NCP_IOC_GET_FS_INFO_V2_32       _IOWR('n', 4, struct compat_ncp_fs_info_v2)
129 #define NCP_IOC_NCPREQUEST_32           _IOR('n', 1, struct compat_ncp_ioctl_request)
130 #define NCP_IOC_GETOBJECTNAME_32        _IOWR('n', 9, struct compat_ncp_objectname_ioctl)
131 #define NCP_IOC_SETOBJECTNAME_32        _IOR('n', 9, struct compat_ncp_objectname_ioctl)
132 #define NCP_IOC_GETPRIVATEDATA_32       _IOWR('n', 10, struct compat_ncp_privatedata_ioctl)
133 #define NCP_IOC_SETPRIVATEDATA_32       _IOR('n', 10, struct compat_ncp_privatedata_ioctl)
134
135 static int
136 ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file,
137                    struct compat_ncp_fs_info_v2 __user * arg)
138 {
139         struct inode *inode = file->f_path.dentry->d_inode;
140         struct compat_ncp_fs_info_v2 info2;
141
142         if ((file_permission(file, MAY_WRITE) != 0)
143             && (current->uid != server->m.mounted_uid)) {
144                 return -EACCES;
145         }
146         if (copy_from_user(&info2, arg, sizeof(info2)))
147                 return -EFAULT;
148
149         if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
150                 DPRINTK("info.version invalid: %d\n", info2.version);
151                 return -EINVAL;
152         }
153         info2.mounted_uid   = server->m.mounted_uid;
154         info2.connection    = server->connection;
155         info2.buffer_size   = server->buffer_size;
156         info2.volume_number = NCP_FINFO(inode)->volNumber;
157         info2.directory_id  = NCP_FINFO(inode)->DosDirNum;
158         info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
159
160         if (copy_to_user(arg, &info2, sizeof(info2)))
161                 return -EFAULT;
162         return 0;
163 }
164 #endif
165
166 #define NCP_IOC_GETMOUNTUID16           _IOW('n', 2, u16)
167 #define NCP_IOC_GETMOUNTUID32           _IOW('n', 2, u32)
168 #define NCP_IOC_GETMOUNTUID64           _IOW('n', 2, u64)
169
170 #ifdef CONFIG_NCPFS_NLS
171 /* Here we are select the iocharset and the codepage for NLS.
172  * Thanks Petr Vandrovec for idea and many hints.
173  */
174 static int
175 ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
176 {
177         struct ncp_nls_ioctl user;
178         struct nls_table *codepage;
179         struct nls_table *iocharset;
180         struct nls_table *oldset_io;
181         struct nls_table *oldset_cp;
182
183         if (!capable(CAP_SYS_ADMIN))
184                 return -EACCES;
185         if (server->root_setuped)
186                 return -EBUSY;
187
188         if (copy_from_user(&user, arg, sizeof(user)))
189                 return -EFAULT;
190
191         codepage = NULL;
192         user.codepage[NCP_IOCSNAME_LEN] = 0;
193         if (!user.codepage[0] || !strcmp(user.codepage, "default"))
194                 codepage = load_nls_default();
195         else {
196                 codepage = load_nls(user.codepage);
197                 if (!codepage) {
198                         return -EBADRQC;
199                 }
200         }
201
202         iocharset = NULL;
203         user.iocharset[NCP_IOCSNAME_LEN] = 0;
204         if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) {
205                 iocharset = load_nls_default();
206                 NCP_CLR_FLAG(server, NCP_FLAG_UTF8);
207         } else if (!strcmp(user.iocharset, "utf8")) {
208                 iocharset = load_nls_default();
209                 NCP_SET_FLAG(server, NCP_FLAG_UTF8);
210         } else {
211                 iocharset = load_nls(user.iocharset);
212                 if (!iocharset) {
213                         unload_nls(codepage);
214                         return -EBADRQC;
215                 }
216                 NCP_CLR_FLAG(server, NCP_FLAG_UTF8);
217         }
218
219         oldset_cp = server->nls_vol;
220         server->nls_vol = codepage;
221         oldset_io = server->nls_io;
222         server->nls_io = iocharset;
223
224         if (oldset_cp)
225                 unload_nls(oldset_cp);
226         if (oldset_io)
227                 unload_nls(oldset_io);
228
229         return 0;
230 }
231
232 static int
233 ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
234 {
235         struct ncp_nls_ioctl user;
236         int len;
237
238         memset(&user, 0, sizeof(user));
239         if (server->nls_vol && server->nls_vol->charset) {
240                 len = strlen(server->nls_vol->charset);
241                 if (len > NCP_IOCSNAME_LEN)
242                         len = NCP_IOCSNAME_LEN;
243                 strncpy(user.codepage, server->nls_vol->charset, len);
244                 user.codepage[len] = 0;
245         }
246
247         if (NCP_IS_FLAG(server, NCP_FLAG_UTF8))
248                 strcpy(user.iocharset, "utf8");
249         else if (server->nls_io && server->nls_io->charset) {
250                 len = strlen(server->nls_io->charset);
251                 if (len > NCP_IOCSNAME_LEN)
252                         len = NCP_IOCSNAME_LEN;
253                 strncpy(user.iocharset, server->nls_io->charset, len);
254                 user.iocharset[len] = 0;
255         }
256
257         if (copy_to_user(arg, &user, sizeof(user)))
258                 return -EFAULT;
259         return 0;
260 }
261 #endif /* CONFIG_NCPFS_NLS */
262
263 int ncp_ioctl(struct inode *inode, struct file *filp,
264               unsigned int cmd, unsigned long arg)
265 {
266         struct ncp_server *server = NCP_SERVER(inode);
267         int result;
268         struct ncp_ioctl_request request;
269         char* bouncebuffer;
270         void __user *argp = (void __user *)arg;
271
272         switch (cmd) {
273 #ifdef CONFIG_COMPAT
274         case NCP_IOC_NCPREQUEST_32:
275 #endif
276         case NCP_IOC_NCPREQUEST:
277                 if ((file_permission(filp, MAY_WRITE) != 0)
278                     && (current->uid != server->m.mounted_uid)) {
279                         return -EACCES;
280                 }
281 #ifdef CONFIG_COMPAT
282                 if (cmd == NCP_IOC_NCPREQUEST_32) {
283                         struct compat_ncp_ioctl_request request32;
284                         if (copy_from_user(&request32, argp, sizeof(request32)))
285                                 return -EFAULT;
286                         request.function = request32.function;
287                         request.size = request32.size;
288                         request.data = compat_ptr(request32.data);
289                 } else
290 #endif
291                 if (copy_from_user(&request, argp, sizeof(request)))
292                         return -EFAULT;
293
294                 if ((request.function > 255)
295                     || (request.size >
296                   NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) {
297                         return -EINVAL;
298                 }
299                 bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL);
300                 if (!bouncebuffer)
301                         return -ENOMEM;
302                 if (copy_from_user(bouncebuffer, request.data, request.size)) {
303                         vfree(bouncebuffer);
304                         return -EFAULT;
305                 }
306                 ncp_lock_server(server);
307
308                 /* FIXME: We hack around in the server's structures
309                    here to be able to use ncp_request */
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                         && (current->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                             && (current->uid != server->m.mounted_uid))
383                         {
384                                 return -EACCES;
385                         }
386                         if (server->m.mounted_vol[0]) {
387                                 struct dentry* dentry = inode->i_sb->s_root;
388
389                                 if (dentry) {
390                                         struct inode* inode = dentry->d_inode;
391                                 
392                                         if (inode) {
393                                                 sr.volNumber = NCP_FINFO(inode)->volNumber;
394                                                 sr.dirEntNum = NCP_FINFO(inode)->dirEntNum;
395                                                 sr.namespace = server->name_space[sr.volNumber];
396                                         } else
397                                                 DPRINTK("ncpfs: s_root->d_inode==NULL\n");
398                                 } else
399                                         DPRINTK("ncpfs: s_root==NULL\n");
400                         } else {
401                                 sr.volNumber = -1;
402                                 sr.namespace = 0;
403                                 sr.dirEntNum = 0;
404                         }
405                         if (copy_to_user(argp, &sr, sizeof(sr)))
406                                 return -EFAULT;
407                         return 0;
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* inode = dentry->d_inode;
441                                 
442                                 if (inode) {
443                                         NCP_FINFO(inode)->volNumber = vnum;
444                                         NCP_FINFO(inode)->dirEntNum = de;
445                                         NCP_FINFO(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                     && (current->uid != server->m.mounted_uid))
458                 {
459                         return -EACCES;
460                 }
461                 if (argp) {
462                         if (server->sign_wanted)
463                         {
464                                 struct ncp_sign_init sign;
465
466                                 if (copy_from_user(&sign, argp, sizeof(sign)))
467                                         return -EFAULT;
468                                 memcpy(server->sign_root,sign.sign_root,8);
469                                 memcpy(server->sign_last,sign.sign_last,16);
470                                 server->sign_active = 1;
471                         }
472                         /* ignore when signatures not wanted */
473                 } else {
474                         server->sign_active = 0;
475                 }
476                 return 0;               
477                 
478         case NCP_IOC_SIGN_WANTED:
479                 if ((file_permission(filp, MAY_READ) != 0)
480                     && (current->uid != server->m.mounted_uid))
481                 {
482                         return -EACCES;
483                 }
484                 
485                 if (put_user(server->sign_wanted, (int __user *)argp))
486                         return -EFAULT;
487                 return 0;
488         case NCP_IOC_SET_SIGN_WANTED:
489                 {
490                         int newstate;
491
492                         if ((file_permission(filp, MAY_WRITE) != 0)
493                             && (current->uid != server->m.mounted_uid))
494                         {
495                                 return -EACCES;
496                         }
497                         /* get only low 8 bits... */
498                         if (get_user(newstate, (unsigned char __user *)argp))
499                                 return -EFAULT;
500                         if (server->sign_active) {
501                                 /* cannot turn signatures OFF when active */
502                                 if (!newstate) return -EINVAL;
503                         } else {
504                                 server->sign_wanted = newstate != 0;
505                         }
506                         return 0;
507                 }
508
509 #endif /* CONFIG_NCPFS_PACKET_SIGNING */
510
511 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
512         case NCP_IOC_LOCKUNLOCK:
513                 if ((file_permission(filp, MAY_WRITE) != 0)
514                     && (current->uid != server->m.mounted_uid))
515                 {
516                         return -EACCES;
517                 }
518                 {
519                         struct ncp_lock_ioctl    rqdata;
520                         int result;
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                                                         rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT;
532                                                 else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT)
533                                                         rqdata.timeout = NCP_LOCK_MAX_TIMEOUT;
534                                                 break;
535                                 case NCP_LOCK_LOG:
536                                                 rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT;      /* has no effect */
537                                 case NCP_LOCK_CLEAR:
538                                                 break;
539                                 default:
540                                                 return -EINVAL;
541                         }
542                         /* locking needs both read and write access */
543                         if ((result = ncp_make_open(inode, O_RDWR)) != 0)
544                         {
545                                 return result;
546                         }
547                         result = -EIO;
548                         if (!ncp_conn_valid(server))
549                                 goto outrel;
550                         result = -EISDIR;
551                         if (!S_ISREG(inode->i_mode))
552                                 goto outrel;
553                         if (rqdata.cmd == NCP_LOCK_CLEAR)
554                         {
555                                 result = ncp_ClearPhysicalRecord(NCP_SERVER(inode),
556                                                         NCP_FINFO(inode)->file_handle, 
557                                                         rqdata.offset,
558                                                         rqdata.length);
559                                 if (result > 0) result = 0;     /* no such lock */
560                         }
561                         else
562                         {
563                                 int lockcmd;
564
565                                 switch (rqdata.cmd)
566                                 {
567                                         case NCP_LOCK_EX:  lockcmd=1; break;
568                                         case NCP_LOCK_SH:  lockcmd=3; break;
569                                         default:           lockcmd=0; break;
570                                 }
571                                 result = ncp_LogPhysicalRecord(NCP_SERVER(inode),
572                                                         NCP_FINFO(inode)->file_handle,
573                                                         lockcmd,
574                                                         rqdata.offset,
575                                                         rqdata.length,
576                                                         rqdata.timeout);
577                                 if (result > 0) result = -EAGAIN;
578                         }
579 outrel:                 
580                         ncp_inode_close(inode);
581                         return result;
582                 }
583 #endif  /* CONFIG_NCPFS_IOCTL_LOCKING */
584
585 #ifdef CONFIG_COMPAT
586         case NCP_IOC_GETOBJECTNAME_32:
587                 if (current->uid != server->m.mounted_uid) {
588                         return -EACCES;
589                 }
590                 {
591                         struct compat_ncp_objectname_ioctl user;
592                         size_t outl;
593
594                         if (copy_from_user(&user, argp, sizeof(user)))
595                                 return -EFAULT;
596                         user.auth_type = server->auth.auth_type;
597                         outl = user.object_name_len;
598                         user.object_name_len = server->auth.object_name_len;
599                         if (outl > user.object_name_len)
600                                 outl = user.object_name_len;
601                         if (outl) {
602                                 if (copy_to_user(compat_ptr(user.object_name),
603                                                  server->auth.object_name,
604                                                  outl)) return -EFAULT;
605                         }
606                         if (copy_to_user(argp, &user, sizeof(user)))
607                                 return -EFAULT;
608                         return 0;
609                 }
610 #endif
611         case NCP_IOC_GETOBJECTNAME:
612                 if (current->uid != server->m.mounted_uid) {
613                         return -EACCES;
614                 }
615                 {
616                         struct ncp_objectname_ioctl user;
617                         size_t outl;
618
619                         if (copy_from_user(&user, argp, sizeof(user)))
620                                 return -EFAULT;
621                         user.auth_type = server->auth.auth_type;
622                         outl = user.object_name_len;
623                         user.object_name_len = server->auth.object_name_len;
624                         if (outl > user.object_name_len)
625                                 outl = user.object_name_len;
626                         if (outl) {
627                                 if (copy_to_user(user.object_name,
628                                                  server->auth.object_name,
629                                                  outl)) return -EFAULT;
630                         }
631                         if (copy_to_user(argp, &user, sizeof(user)))
632                                 return -EFAULT;
633                         return 0;
634                 }
635 #ifdef CONFIG_COMPAT
636         case NCP_IOC_SETOBJECTNAME_32:
637 #endif
638         case NCP_IOC_SETOBJECTNAME:
639                 if (current->uid != server->m.mounted_uid) {
640                         return -EACCES;
641                 }
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 = kmalloc(user.object_name_len, GFP_USER);
667                                 if (!newname)
668                                         return -ENOMEM;
669                                 if (copy_from_user(newname, user.object_name, user.object_name_len)) {
670                                         kfree(newname);
671                                         return -EFAULT;
672                                 }
673                         } else {
674                                 newname = NULL;
675                         }
676                         /* enter critical section */
677                         /* maybe that kfree can sleep so do that this way */
678                         /* it is at least more SMP friendly (in future...) */
679                         oldname = server->auth.object_name;
680                         oldnamelen = server->auth.object_name_len;
681                         oldprivate = server->priv.data;
682                         oldprivatelen = server->priv.len;
683                         server->auth.auth_type = user.auth_type;
684                         server->auth.object_name_len = user.object_name_len;
685                         server->auth.object_name = newname;
686                         server->priv.len = 0;
687                         server->priv.data = NULL;
688                         /* leave critical section */
689                         kfree(oldprivate);
690                         kfree(oldname);
691                         return 0;
692                 }
693 #ifdef CONFIG_COMPAT
694         case NCP_IOC_GETPRIVATEDATA_32:
695 #endif
696         case NCP_IOC_GETPRIVATEDATA:
697                 if (current->uid != server->m.mounted_uid) {
698                         return -EACCES;
699                 }
700                 {
701                         struct ncp_privatedata_ioctl user;
702                         size_t outl;
703
704 #ifdef CONFIG_COMPAT
705                         if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
706                                 struct compat_ncp_privatedata_ioctl user32;
707                                 if (copy_from_user(&user32, argp, sizeof(user32)))
708                                         return -EFAULT;
709                                 user.len = user32.len;
710                                 user.data = compat_ptr(user32.data);
711                         } else
712 #endif
713                         if (copy_from_user(&user, argp, sizeof(user)))
714                                 return -EFAULT;
715
716                         outl = user.len;
717                         user.len = server->priv.len;
718                         if (outl > user.len) outl = user.len;
719                         if (outl) {
720                                 if (copy_to_user(user.data,
721                                                  server->priv.data,
722                                                  outl)) return -EFAULT;
723                         }
724 #ifdef CONFIG_COMPAT
725                         if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
726                                 struct compat_ncp_privatedata_ioctl user32;
727                                 user32.len = user.len;
728                                 user32.data = (unsigned long) user.data;
729                                 if (copy_to_user(argp, &user32, sizeof(user32)))
730                                         return -EFAULT;
731                         } else
732 #endif
733                         if (copy_to_user(argp, &user, sizeof(user)))
734                                 return -EFAULT;
735
736                         return 0;
737                 }
738 #ifdef CONFIG_COMPAT
739         case NCP_IOC_SETPRIVATEDATA_32:
740 #endif
741         case NCP_IOC_SETPRIVATEDATA:
742                 if (current->uid != server->m.mounted_uid) {
743                         return -EACCES;
744                 }
745                 {
746                         struct ncp_privatedata_ioctl user;
747                         void* new;
748                         void* old;
749                         size_t oldlen;
750
751 #ifdef CONFIG_COMPAT
752                         if (cmd == NCP_IOC_SETPRIVATEDATA_32) {
753                                 struct compat_ncp_privatedata_ioctl user32;
754                                 if (copy_from_user(&user32, argp, sizeof(user32)))
755                                         return -EFAULT;
756                                 user.len = user32.len;
757                                 user.data = compat_ptr(user32.data);
758                         } else
759 #endif
760                         if (copy_from_user(&user, argp, sizeof(user)))
761                                 return -EFAULT;
762
763                         if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
764                                 return -ENOMEM;
765                         if (user.len) {
766                                 new = kmalloc(user.len, GFP_USER);
767                                 if (!new)
768                                         return -ENOMEM;
769                                 if (copy_from_user(new, user.data, user.len)) {
770                                         kfree(new);
771                                         return -EFAULT;
772                                 }
773                         } else {
774                                 new = NULL;
775                         }
776                         /* enter critical section */
777                         old = server->priv.data;
778                         oldlen = server->priv.len;
779                         server->priv.len = user.len;
780                         server->priv.data = new;
781                         /* leave critical section */
782                         kfree(old);
783                         return 0;
784                 }
785
786 #ifdef CONFIG_NCPFS_NLS
787         case NCP_IOC_SETCHARSETS:
788                 return ncp_set_charsets(server, argp);
789                 
790         case NCP_IOC_GETCHARSETS:
791                 return ncp_get_charsets(server, argp);
792
793 #endif /* CONFIG_NCPFS_NLS */
794
795         case NCP_IOC_SETDENTRYTTL:
796                 if ((file_permission(filp, MAY_WRITE) != 0) &&
797                                  (current->uid != server->m.mounted_uid))
798                         return -EACCES;
799                 {
800                         u_int32_t user;
801
802                         if (copy_from_user(&user, argp, sizeof(user)))
803                                 return -EFAULT;
804                         /* 20 secs at most... */
805                         if (user > 20000)
806                                 return -EINVAL;
807                         user = (user * HZ) / 1000;
808                         server->dentry_ttl = user;
809                         return 0;
810                 }
811                 
812         case NCP_IOC_GETDENTRYTTL:
813                 {
814                         u_int32_t user = (server->dentry_ttl * 1000) / HZ;
815                         if (copy_to_user(argp, &user, sizeof(user)))
816                                 return -EFAULT;
817                         return 0;
818                 }
819
820         }
821         return -EINVAL;
822 }
823
824 #ifdef CONFIG_COMPAT
825 long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
826 {
827         struct inode *inode = file->f_path.dentry->d_inode;
828         int ret;
829
830         lock_kernel();
831         arg = (unsigned long) compat_ptr(arg);
832         ret = ncp_ioctl(inode, file, cmd, arg);
833         unlock_kernel();
834         return ret;
835 }
836 #endif