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
11 #include <asm/uaccess.h>
12 #include <linux/capability.h>
13 #include <linux/errno.h>
15 #include <linux/ioctl.h>
16 #include <linux/time.h>
18 #include <linux/highuid.h>
19 #include <linux/vmalloc.h>
21 #include <linux/ncp_fs.h>
23 #include "ncplib_kernel.h"
25 /* maximum limit for ncp_objectname_ioctl */
26 #define NCP_OBJECT_NAME_MAX_LEN 4096
27 /* maximum limit for ncp_privatedata_ioctl */
28 #define NCP_PRIVATE_DATA_MAX_LEN 8192
29 /* maximum negotiable packet size */
30 #define NCP_PACKET_SIZE_INTERNAL 65536
33 ncp_get_fs_info(struct ncp_server
* server
, struct file
*file
,
34 struct ncp_fs_info __user
*arg
)
36 struct inode
*inode
= file
->f_dentry
->d_inode
;
37 struct ncp_fs_info info
;
39 if ((file_permission(file
, MAY_WRITE
) != 0)
40 && (current
->uid
!= server
->m
.mounted_uid
)) {
43 if (copy_from_user(&info
, arg
, sizeof(info
)))
46 if (info
.version
!= NCP_GET_FS_INFO_VERSION
) {
47 DPRINTK("info.version invalid: %d\n", info
.version
);
50 /* TODO: info.addr = server->m.serv_addr; */
51 SET_UID(info
.mounted_uid
, server
->m
.mounted_uid
);
52 info
.connection
= server
->connection
;
53 info
.buffer_size
= server
->buffer_size
;
54 info
.volume_number
= NCP_FINFO(inode
)->volNumber
;
55 info
.directory_id
= NCP_FINFO(inode
)->DosDirNum
;
57 if (copy_to_user(arg
, &info
, sizeof(info
)))
63 ncp_get_fs_info_v2(struct ncp_server
* server
, struct file
*file
,
64 struct ncp_fs_info_v2 __user
* arg
)
66 struct inode
*inode
= file
->f_dentry
->d_inode
;
67 struct ncp_fs_info_v2 info2
;
69 if ((file_permission(file
, MAY_WRITE
) != 0)
70 && (current
->uid
!= server
->m
.mounted_uid
)) {
73 if (copy_from_user(&info2
, arg
, sizeof(info2
)))
76 if (info2
.version
!= NCP_GET_FS_INFO_VERSION_V2
) {
77 DPRINTK("info.version invalid: %d\n", info2
.version
);
80 info2
.mounted_uid
= server
->m
.mounted_uid
;
81 info2
.connection
= server
->connection
;
82 info2
.buffer_size
= server
->buffer_size
;
83 info2
.volume_number
= NCP_FINFO(inode
)->volNumber
;
84 info2
.directory_id
= NCP_FINFO(inode
)->DosDirNum
;
85 info2
.dummy1
= info2
.dummy2
= info2
.dummy3
= 0;
87 if (copy_to_user(arg
, &info2
, sizeof(info2
)))
92 #ifdef CONFIG_NCPFS_NLS
93 /* Here we are select the iocharset and the codepage for NLS.
94 * Thanks Petr Vandrovec for idea and many hints.
97 ncp_set_charsets(struct ncp_server
* server
, struct ncp_nls_ioctl __user
*arg
)
99 struct ncp_nls_ioctl user
;
100 struct nls_table
*codepage
;
101 struct nls_table
*iocharset
;
102 struct nls_table
*oldset_io
;
103 struct nls_table
*oldset_cp
;
105 if (!capable(CAP_SYS_ADMIN
))
107 if (server
->root_setuped
)
110 if (copy_from_user(&user
, arg
, sizeof(user
)))
114 user
.codepage
[NCP_IOCSNAME_LEN
] = 0;
115 if (!user
.codepage
[0] || !strcmp(user
.codepage
, "default"))
116 codepage
= load_nls_default();
118 codepage
= load_nls(user
.codepage
);
125 user
.iocharset
[NCP_IOCSNAME_LEN
] = 0;
126 if (!user
.iocharset
[0] || !strcmp(user
.iocharset
, "default")) {
127 iocharset
= load_nls_default();
128 NCP_CLR_FLAG(server
, NCP_FLAG_UTF8
);
129 } else if (!strcmp(user
.iocharset
, "utf8")) {
130 iocharset
= load_nls_default();
131 NCP_SET_FLAG(server
, NCP_FLAG_UTF8
);
133 iocharset
= load_nls(user
.iocharset
);
135 unload_nls(codepage
);
138 NCP_CLR_FLAG(server
, NCP_FLAG_UTF8
);
141 oldset_cp
= server
->nls_vol
;
142 server
->nls_vol
= codepage
;
143 oldset_io
= server
->nls_io
;
144 server
->nls_io
= iocharset
;
147 unload_nls(oldset_cp
);
149 unload_nls(oldset_io
);
155 ncp_get_charsets(struct ncp_server
* server
, struct ncp_nls_ioctl __user
*arg
)
157 struct ncp_nls_ioctl user
;
160 memset(&user
, 0, sizeof(user
));
161 if (server
->nls_vol
&& server
->nls_vol
->charset
) {
162 len
= strlen(server
->nls_vol
->charset
);
163 if (len
> NCP_IOCSNAME_LEN
)
164 len
= NCP_IOCSNAME_LEN
;
165 strncpy(user
.codepage
, server
->nls_vol
->charset
, len
);
166 user
.codepage
[len
] = 0;
169 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
))
170 strcpy(user
.iocharset
, "utf8");
171 else if (server
->nls_io
&& server
->nls_io
->charset
) {
172 len
= strlen(server
->nls_io
->charset
);
173 if (len
> NCP_IOCSNAME_LEN
)
174 len
= NCP_IOCSNAME_LEN
;
175 strncpy(user
.iocharset
, server
->nls_io
->charset
, len
);
176 user
.iocharset
[len
] = 0;
179 if (copy_to_user(arg
, &user
, sizeof(user
)))
183 #endif /* CONFIG_NCPFS_NLS */
185 int ncp_ioctl(struct inode
*inode
, struct file
*filp
,
186 unsigned int cmd
, unsigned long arg
)
188 struct ncp_server
*server
= NCP_SERVER(inode
);
190 struct ncp_ioctl_request request
;
192 void __user
*argp
= (void __user
*)arg
;
195 case NCP_IOC_NCPREQUEST
:
197 if ((file_permission(filp
, MAY_WRITE
) != 0)
198 && (current
->uid
!= server
->m
.mounted_uid
)) {
201 if (copy_from_user(&request
, argp
, sizeof(request
)))
204 if ((request
.function
> 255)
206 NCP_PACKET_SIZE
- sizeof(struct ncp_request_header
))) {
209 bouncebuffer
= vmalloc(NCP_PACKET_SIZE_INTERNAL
);
212 if (copy_from_user(bouncebuffer
, request
.data
, request
.size
)) {
216 ncp_lock_server(server
);
218 /* FIXME: We hack around in the server's structures
219 here to be able to use ncp_request */
221 server
->has_subfunction
= 0;
222 server
->current_size
= request
.size
;
223 memcpy(server
->packet
, bouncebuffer
, request
.size
);
225 result
= ncp_request2(server
, request
.function
,
226 bouncebuffer
, NCP_PACKET_SIZE_INTERNAL
);
230 result
= server
->reply_size
;
231 ncp_unlock_server(server
);
232 DPRINTK("ncp_ioctl: copy %d bytes\n",
235 if (copy_to_user(request
.data
, bouncebuffer
, result
))
240 case NCP_IOC_CONN_LOGGED_IN
:
242 if (!capable(CAP_SYS_ADMIN
))
244 if (!(server
->m
.int_flags
& NCP_IMOUNT_LOGGEDIN_POSSIBLE
))
246 if (server
->root_setuped
)
248 server
->root_setuped
= 1;
249 return ncp_conn_logged_in(inode
->i_sb
);
251 case NCP_IOC_GET_FS_INFO
:
252 return ncp_get_fs_info(server
, filp
, argp
);
254 case NCP_IOC_GET_FS_INFO_V2
:
255 return ncp_get_fs_info_v2(server
, filp
, argp
);
257 case NCP_IOC_GETMOUNTUID2
:
259 unsigned long tmp
= server
->m
.mounted_uid
;
261 if ((file_permission(filp
, MAY_READ
) != 0)
262 && (current
->uid
!= server
->m
.mounted_uid
))
266 if (put_user(tmp
, (unsigned long __user
*)argp
))
271 case NCP_IOC_GETROOT
:
273 struct ncp_setroot_ioctl sr
;
275 if ((file_permission(filp
, MAY_READ
) != 0)
276 && (current
->uid
!= server
->m
.mounted_uid
))
280 if (server
->m
.mounted_vol
[0]) {
281 struct dentry
* dentry
= inode
->i_sb
->s_root
;
284 struct inode
* inode
= dentry
->d_inode
;
287 sr
.volNumber
= NCP_FINFO(inode
)->volNumber
;
288 sr
.dirEntNum
= NCP_FINFO(inode
)->dirEntNum
;
289 sr
.namespace = server
->name_space
[sr
.volNumber
];
291 DPRINTK("ncpfs: s_root->d_inode==NULL\n");
293 DPRINTK("ncpfs: s_root==NULL\n");
299 if (copy_to_user(argp
, &sr
, sizeof(sr
)))
303 case NCP_IOC_SETROOT
:
305 struct ncp_setroot_ioctl sr
;
309 struct dentry
* dentry
;
311 if (!capable(CAP_SYS_ADMIN
))
315 if (server
->root_setuped
) return -EBUSY
;
316 if (copy_from_user(&sr
, argp
, sizeof(sr
)))
318 if (sr
.volNumber
< 0) {
319 server
->m
.mounted_vol
[0] = 0;
320 vnum
= NCP_NUMBER_OF_VOLUMES
;
323 } else if (sr
.volNumber
>= NCP_NUMBER_OF_VOLUMES
) {
325 } else if (ncp_mount_subdir(server
, sr
.volNumber
,
326 sr
.namespace, sr
.dirEntNum
,
327 &vnum
, &de
, &dosde
)) {
331 dentry
= inode
->i_sb
->s_root
;
332 server
->root_setuped
= 1;
334 struct inode
* inode
= dentry
->d_inode
;
337 NCP_FINFO(inode
)->volNumber
= vnum
;
338 NCP_FINFO(inode
)->dirEntNum
= de
;
339 NCP_FINFO(inode
)->DosDirNum
= dosde
;
341 DPRINTK("ncpfs: s_root->d_inode==NULL\n");
343 DPRINTK("ncpfs: s_root==NULL\n");
348 #ifdef CONFIG_NCPFS_PACKET_SIGNING
349 case NCP_IOC_SIGN_INIT
:
350 if ((file_permission(filp
, MAY_WRITE
) != 0)
351 && (current
->uid
!= server
->m
.mounted_uid
))
356 if (server
->sign_wanted
)
358 struct ncp_sign_init sign
;
360 if (copy_from_user(&sign
, argp
, sizeof(sign
)))
362 memcpy(server
->sign_root
,sign
.sign_root
,8);
363 memcpy(server
->sign_last
,sign
.sign_last
,16);
364 server
->sign_active
= 1;
366 /* ignore when signatures not wanted */
368 server
->sign_active
= 0;
372 case NCP_IOC_SIGN_WANTED
:
373 if ((file_permission(filp
, MAY_READ
) != 0)
374 && (current
->uid
!= server
->m
.mounted_uid
))
379 if (put_user(server
->sign_wanted
, (int __user
*)argp
))
382 case NCP_IOC_SET_SIGN_WANTED
:
386 if ((file_permission(filp
, MAY_WRITE
) != 0)
387 && (current
->uid
!= server
->m
.mounted_uid
))
391 /* get only low 8 bits... */
392 if (get_user(newstate
, (unsigned char __user
*)argp
))
394 if (server
->sign_active
) {
395 /* cannot turn signatures OFF when active */
396 if (!newstate
) return -EINVAL
;
398 server
->sign_wanted
= newstate
!= 0;
403 #endif /* CONFIG_NCPFS_PACKET_SIGNING */
405 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
406 case NCP_IOC_LOCKUNLOCK
:
407 if ((file_permission(filp
, MAY_WRITE
) != 0)
408 && (current
->uid
!= server
->m
.mounted_uid
))
413 struct ncp_lock_ioctl rqdata
;
416 if (copy_from_user(&rqdata
, argp
, sizeof(rqdata
)))
418 if (rqdata
.origin
!= 0)
421 switch (rqdata
.cmd
) {
424 if (rqdata
.timeout
== 0)
425 rqdata
.timeout
= NCP_LOCK_DEFAULT_TIMEOUT
;
426 else if (rqdata
.timeout
> NCP_LOCK_MAX_TIMEOUT
)
427 rqdata
.timeout
= NCP_LOCK_MAX_TIMEOUT
;
430 rqdata
.timeout
= NCP_LOCK_DEFAULT_TIMEOUT
; /* has no effect */
436 /* locking needs both read and write access */
437 if ((result
= ncp_make_open(inode
, O_RDWR
)) != 0)
442 if (!ncp_conn_valid(server
))
445 if (!S_ISREG(inode
->i_mode
))
447 if (rqdata
.cmd
== NCP_LOCK_CLEAR
)
449 result
= ncp_ClearPhysicalRecord(NCP_SERVER(inode
),
450 NCP_FINFO(inode
)->file_handle
,
453 if (result
> 0) result
= 0; /* no such lock */
461 case NCP_LOCK_EX
: lockcmd
=1; break;
462 case NCP_LOCK_SH
: lockcmd
=3; break;
463 default: lockcmd
=0; break;
465 result
= ncp_LogPhysicalRecord(NCP_SERVER(inode
),
466 NCP_FINFO(inode
)->file_handle
,
471 if (result
> 0) result
= -EAGAIN
;
474 ncp_inode_close(inode
);
477 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
479 case NCP_IOC_GETOBJECTNAME
:
480 if (current
->uid
!= server
->m
.mounted_uid
) {
484 struct ncp_objectname_ioctl user
;
487 if (copy_from_user(&user
, argp
, sizeof(user
)))
489 user
.auth_type
= server
->auth
.auth_type
;
490 outl
= user
.object_name_len
;
491 user
.object_name_len
= server
->auth
.object_name_len
;
492 if (outl
> user
.object_name_len
)
493 outl
= user
.object_name_len
;
495 if (copy_to_user(user
.object_name
,
496 server
->auth
.object_name
,
497 outl
)) return -EFAULT
;
499 if (copy_to_user(argp
, &user
, sizeof(user
)))
503 case NCP_IOC_SETOBJECTNAME
:
504 if (current
->uid
!= server
->m
.mounted_uid
) {
508 struct ncp_objectname_ioctl user
;
513 size_t oldprivatelen
;
515 if (copy_from_user(&user
, argp
, sizeof(user
)))
517 if (user
.object_name_len
> NCP_OBJECT_NAME_MAX_LEN
)
519 if (user
.object_name_len
) {
520 newname
= kmalloc(user
.object_name_len
, GFP_USER
);
523 if (copy_from_user(newname
, user
.object_name
, user
.object_name_len
)) {
530 /* enter critical section */
531 /* maybe that kfree can sleep so do that this way */
532 /* it is at least more SMP friendly (in future...) */
533 oldname
= server
->auth
.object_name
;
534 oldnamelen
= server
->auth
.object_name_len
;
535 oldprivate
= server
->priv
.data
;
536 oldprivatelen
= server
->priv
.len
;
537 server
->auth
.auth_type
= user
.auth_type
;
538 server
->auth
.object_name_len
= user
.object_name_len
;
539 server
->auth
.object_name
= newname
;
540 server
->priv
.len
= 0;
541 server
->priv
.data
= NULL
;
542 /* leave critical section */
547 case NCP_IOC_GETPRIVATEDATA
:
548 if (current
->uid
!= server
->m
.mounted_uid
) {
552 struct ncp_privatedata_ioctl user
;
555 if (copy_from_user(&user
, argp
, sizeof(user
)))
558 user
.len
= server
->priv
.len
;
559 if (outl
> user
.len
) outl
= user
.len
;
561 if (copy_to_user(user
.data
,
563 outl
)) return -EFAULT
;
565 if (copy_to_user(argp
, &user
, sizeof(user
)))
569 case NCP_IOC_SETPRIVATEDATA
:
570 if (current
->uid
!= server
->m
.mounted_uid
) {
574 struct ncp_privatedata_ioctl user
;
579 if (copy_from_user(&user
, argp
, sizeof(user
)))
581 if (user
.len
> NCP_PRIVATE_DATA_MAX_LEN
)
584 new = kmalloc(user
.len
, GFP_USER
);
587 if (copy_from_user(new, user
.data
, user
.len
)) {
594 /* enter critical section */
595 old
= server
->priv
.data
;
596 oldlen
= server
->priv
.len
;
597 server
->priv
.len
= user
.len
;
598 server
->priv
.data
= new;
599 /* leave critical section */
604 #ifdef CONFIG_NCPFS_NLS
605 case NCP_IOC_SETCHARSETS
:
606 return ncp_set_charsets(server
, argp
);
608 case NCP_IOC_GETCHARSETS
:
609 return ncp_get_charsets(server
, argp
);
611 #endif /* CONFIG_NCPFS_NLS */
613 case NCP_IOC_SETDENTRYTTL
:
614 if ((file_permission(filp
, MAY_WRITE
) != 0) &&
615 (current
->uid
!= server
->m
.mounted_uid
))
620 if (copy_from_user(&user
, argp
, sizeof(user
)))
622 /* 20 secs at most... */
625 user
= (user
* HZ
) / 1000;
626 server
->dentry_ttl
= user
;
630 case NCP_IOC_GETDENTRYTTL
:
632 u_int32_t user
= (server
->dentry_ttl
* 1000) / HZ
;
633 if (copy_to_user(argp
, &user
, sizeof(user
)))
639 /* #ifdef CONFIG_UID16 */
640 /* NCP_IOC_GETMOUNTUID may be same as NCP_IOC_GETMOUNTUID2,
641 so we have this out of switch */
642 if (cmd
== NCP_IOC_GETMOUNTUID
) {
643 __kernel_uid_t uid
= 0;
644 if ((file_permission(filp
, MAY_READ
) != 0)
645 && (current
->uid
!= server
->m
.mounted_uid
)) {
648 SET_UID(uid
, server
->m
.mounted_uid
);
649 if (put_user(uid
, (__kernel_uid_t __user
*)argp
))