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
10 #include <linux/config.h>
12 #include <asm/uaccess.h>
13 #include <linux/errno.h>
15 #include <linux/ioctl.h>
16 #include <linux/sched.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
32 int ncp_ioctl(struct inode
*inode
, struct file
*filp
,
33 unsigned int cmd
, unsigned long arg
)
35 struct ncp_server
*server
= NCP_SERVER(inode
);
37 struct ncp_ioctl_request request
;
41 case NCP_IOC_NCPREQUEST
:
43 if ((permission(inode
, MAY_WRITE
) != 0)
44 && (current
->uid
!= server
->m
.mounted_uid
)) {
47 if (copy_from_user(&request
, (struct ncp_ioctl_request
*) arg
,
51 if ((request
.function
> 255)
53 NCP_PACKET_SIZE
- sizeof(struct ncp_request_header
))) {
56 bouncebuffer
= vmalloc(NCP_PACKET_SIZE_INTERNAL
);
59 if (copy_from_user(bouncebuffer
, request
.data
, request
.size
)) {
63 ncp_lock_server(server
);
65 /* FIXME: We hack around in the server's structures
66 here to be able to use ncp_request */
68 server
->has_subfunction
= 0;
69 server
->current_size
= request
.size
;
70 memcpy(server
->packet
, bouncebuffer
, request
.size
);
72 result
= ncp_request2(server
, request
.function
,
73 bouncebuffer
, NCP_PACKET_SIZE_INTERNAL
);
77 result
= server
->reply_size
;
78 ncp_unlock_server(server
);
79 DPRINTK("ncp_ioctl: copy %d bytes\n",
82 if (copy_to_user(request
.data
, bouncebuffer
, result
))
87 case NCP_IOC_CONN_LOGGED_IN
:
89 if (!capable(CAP_SYS_ADMIN
))
91 if (!(server
->m
.int_flags
& NCP_IMOUNT_LOGGEDIN_POSSIBLE
))
93 if (server
->root_setuped
)
95 server
->root_setuped
= 1;
96 return ncp_conn_logged_in(inode
->i_sb
);
98 case NCP_IOC_GET_FS_INFO
:
100 struct ncp_fs_info info
;
102 if ((permission(inode
, MAY_WRITE
) != 0)
103 && (current
->uid
!= server
->m
.mounted_uid
)) {
106 if (copy_from_user(&info
, (struct ncp_fs_info
*) arg
,
110 if (info
.version
!= NCP_GET_FS_INFO_VERSION
) {
111 DPRINTK("info.version invalid: %d\n", info
.version
);
114 /* TODO: info.addr = server->m.serv_addr; */
115 info
.mounted_uid
= NEW_TO_OLD_UID(server
->m
.mounted_uid
);
116 info
.connection
= server
->connection
;
117 info
.buffer_size
= server
->buffer_size
;
118 info
.volume_number
= NCP_FINFO(inode
)->volNumber
;
119 info
.directory_id
= NCP_FINFO(inode
)->DosDirNum
;
121 if (copy_to_user((struct ncp_fs_info
*) arg
, &info
,
122 sizeof(info
))) return -EFAULT
;
126 case NCP_IOC_GET_FS_INFO_V2
:
128 struct ncp_fs_info_v2 info2
;
130 if ((permission(inode
, MAY_WRITE
) != 0)
131 && (current
->uid
!= server
->m
.mounted_uid
)) {
134 if (copy_from_user(&info2
, (struct ncp_fs_info_v2
*) arg
,
138 if (info2
.version
!= NCP_GET_FS_INFO_VERSION_V2
) {
139 DPRINTK("info.version invalid: %d\n", info2
.version
);
142 info2
.mounted_uid
= server
->m
.mounted_uid
;
143 info2
.connection
= server
->connection
;
144 info2
.buffer_size
= server
->buffer_size
;
145 info2
.volume_number
= NCP_FINFO(inode
)->volNumber
;
146 info2
.directory_id
= NCP_FINFO(inode
)->DosDirNum
;
147 info2
.dummy1
= info2
.dummy2
= info2
.dummy3
= 0;
149 if (copy_to_user((struct ncp_fs_info_v2
*) arg
, &info2
,
150 sizeof(info2
))) return -EFAULT
;
154 case NCP_IOC_GETMOUNTUID2
:
156 unsigned long tmp
= server
->m
.mounted_uid
;
158 if ( (permission(inode
, MAY_READ
) != 0)
159 && (current
->uid
!= server
->m
.mounted_uid
))
163 if (put_user(tmp
, (unsigned long*) arg
))
168 case NCP_IOC_GETROOT
:
170 struct ncp_setroot_ioctl sr
;
172 if ( (permission(inode
, MAY_READ
) != 0)
173 && (current
->uid
!= server
->m
.mounted_uid
))
177 if (server
->m
.mounted_vol
[0]) {
178 struct dentry
* dentry
= inode
->i_sb
->s_root
;
181 struct inode
* inode
= dentry
->d_inode
;
184 sr
.volNumber
= NCP_FINFO(inode
)->volNumber
;
185 sr
.dirEntNum
= NCP_FINFO(inode
)->dirEntNum
;
186 sr
.namespace = server
->name_space
[sr
.volNumber
];
188 DPRINTK("ncpfs: s_root->d_inode==NULL\n");
190 DPRINTK("ncpfs: s_root==NULL\n");
196 if (copy_to_user((struct ncp_setroot_ioctl
*)arg
,
198 sizeof(sr
))) return -EFAULT
;
201 case NCP_IOC_SETROOT
:
203 struct ncp_setroot_ioctl sr
;
204 struct nw_info_struct i
;
205 struct dentry
* dentry
;
207 if (!capable(CAP_SYS_ADMIN
))
211 if (server
->root_setuped
) return -EBUSY
;
212 if (copy_from_user(&sr
,
213 (struct ncp_setroot_ioctl
*)arg
,
214 sizeof(sr
))) return -EFAULT
;
215 if (sr
.volNumber
< 0) {
216 server
->m
.mounted_vol
[0] = 0;
217 i
.volNumber
= NCP_NUMBER_OF_VOLUMES
+ 1;
220 } else if (sr
.volNumber
>= NCP_NUMBER_OF_VOLUMES
) {
223 if (ncp_mount_subdir(server
, &i
, sr
.volNumber
,
224 sr
.namespace, sr
.dirEntNum
))
227 dentry
= inode
->i_sb
->s_root
;
228 server
->root_setuped
= 1;
230 struct inode
* inode
= dentry
->d_inode
;
233 NCP_FINFO(inode
)->volNumber
= i
.volNumber
;
234 NCP_FINFO(inode
)->dirEntNum
= i
.dirEntNum
;
235 NCP_FINFO(inode
)->DosDirNum
= i
.DosDirNum
;
237 DPRINTK("ncpfs: s_root->d_inode==NULL\n");
239 DPRINTK("ncpfs: s_root==NULL\n");
244 #ifdef CONFIG_NCPFS_PACKET_SIGNING
245 case NCP_IOC_SIGN_INIT
:
246 if ((permission(inode
, MAY_WRITE
) != 0)
247 && (current
->uid
!= server
->m
.mounted_uid
))
252 if (server
->sign_wanted
)
254 struct ncp_sign_init sign
;
256 if (copy_from_user(&sign
, (struct ncp_sign_init
*) arg
,
257 sizeof(sign
))) return -EFAULT
;
258 memcpy(server
->sign_root
,sign
.sign_root
,8);
259 memcpy(server
->sign_last
,sign
.sign_last
,16);
260 server
->sign_active
= 1;
262 /* ignore when signatures not wanted */
264 server
->sign_active
= 0;
268 case NCP_IOC_SIGN_WANTED
:
269 if ( (permission(inode
, MAY_READ
) != 0)
270 && (current
->uid
!= server
->m
.mounted_uid
))
275 if (put_user(server
->sign_wanted
, (int*) arg
))
278 case NCP_IOC_SET_SIGN_WANTED
:
282 if ( (permission(inode
, MAY_WRITE
) != 0)
283 && (current
->uid
!= server
->m
.mounted_uid
))
287 /* get only low 8 bits... */
288 if (get_user(newstate
, (unsigned char *) arg
))
290 if (server
->sign_active
) {
291 /* cannot turn signatures OFF when active */
292 if (!newstate
) return -EINVAL
;
294 server
->sign_wanted
= newstate
!= 0;
299 #endif /* CONFIG_NCPFS_PACKET_SIGNING */
301 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
302 case NCP_IOC_LOCKUNLOCK
:
303 if ( (permission(inode
, MAY_WRITE
) != 0)
304 && (current
->uid
!= server
->m
.mounted_uid
))
309 struct ncp_lock_ioctl rqdata
;
312 if (copy_from_user(&rqdata
, (struct ncp_lock_ioctl
*)arg
,
313 sizeof(rqdata
))) return -EFAULT
;
314 if (rqdata
.origin
!= 0)
317 switch (rqdata
.cmd
) {
320 if (rqdata
.timeout
== 0)
321 rqdata
.timeout
= NCP_LOCK_DEFAULT_TIMEOUT
;
322 else if (rqdata
.timeout
> NCP_LOCK_MAX_TIMEOUT
)
323 rqdata
.timeout
= NCP_LOCK_MAX_TIMEOUT
;
326 rqdata
.timeout
= NCP_LOCK_DEFAULT_TIMEOUT
; /* has no effect */
332 /* locking needs both read and write access */
333 if ((result
= ncp_make_open(inode
, O_RDWR
)) != 0)
338 if (!ncp_conn_valid(server
))
341 if (!S_ISREG(inode
->i_mode
))
343 if (rqdata
.cmd
== NCP_LOCK_CLEAR
)
345 result
= ncp_ClearPhysicalRecord(NCP_SERVER(inode
),
346 NCP_FINFO(inode
)->file_handle
,
349 if (result
> 0) result
= 0; /* no such lock */
357 case NCP_LOCK_EX
: lockcmd
=1; break;
358 case NCP_LOCK_SH
: lockcmd
=3; break;
359 default: lockcmd
=0; break;
361 result
= ncp_LogPhysicalRecord(NCP_SERVER(inode
),
362 NCP_FINFO(inode
)->file_handle
,
367 if (result
> 0) result
= -EAGAIN
;
370 ncp_inode_close(inode
);
373 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
375 case NCP_IOC_GETOBJECTNAME
:
376 if (current
->uid
!= server
->m
.mounted_uid
) {
380 struct ncp_objectname_ioctl user
;
383 if (copy_from_user(&user
,
384 (struct ncp_objectname_ioctl
*)arg
,
385 sizeof(user
))) return -EFAULT
;
386 user
.auth_type
= server
->auth
.auth_type
;
387 outl
= user
.object_name_len
;
388 user
.object_name_len
= server
->auth
.object_name_len
;
389 if (outl
> user
.object_name_len
)
390 outl
= user
.object_name_len
;
392 if (copy_to_user(user
.object_name
,
393 server
->auth
.object_name
,
394 outl
)) return -EFAULT
;
396 if (copy_to_user((struct ncp_objectname_ioctl
*)arg
,
398 sizeof(user
))) return -EFAULT
;
401 case NCP_IOC_SETOBJECTNAME
:
402 if (current
->uid
!= server
->m
.mounted_uid
) {
406 struct ncp_objectname_ioctl user
;
411 size_t oldprivatelen
;
413 if (copy_from_user(&user
,
414 (struct ncp_objectname_ioctl
*)arg
,
415 sizeof(user
))) return -EFAULT
;
416 if (user
.object_name_len
> NCP_OBJECT_NAME_MAX_LEN
)
418 if (user
.object_name_len
) {
419 newname
= ncp_kmalloc(user
.object_name_len
, GFP_USER
);
420 if (!newname
) return -ENOMEM
;
421 if (copy_from_user(newname
, user
.object_name
, sizeof(user
))) {
422 ncp_kfree_s(newname
, user
.object_name_len
);
428 /* enter critical section */
429 /* maybe that kfree can sleep so do that this way */
430 /* it is at least more SMP friendly (in future...) */
431 oldname
= server
->auth
.object_name
;
432 oldnamelen
= server
->auth
.object_name_len
;
433 oldprivate
= server
->priv
.data
;
434 oldprivatelen
= server
->priv
.len
;
435 server
->auth
.auth_type
= user
.auth_type
;
436 server
->auth
.object_name_len
= user
.object_name_len
;
437 server
->auth
.object_name
= user
.object_name
;
438 server
->priv
.len
= 0;
439 server
->priv
.data
= NULL
;
440 /* leave critical section */
441 if (oldprivate
) ncp_kfree_s(oldprivate
, oldprivatelen
);
442 if (oldname
) ncp_kfree_s(oldname
, oldnamelen
);
445 case NCP_IOC_GETPRIVATEDATA
:
446 if (current
->uid
!= server
->m
.mounted_uid
) {
450 struct ncp_privatedata_ioctl user
;
453 if (copy_from_user(&user
,
454 (struct ncp_privatedata_ioctl
*)arg
,
455 sizeof(user
))) return -EFAULT
;
457 user
.len
= server
->priv
.len
;
458 if (outl
> user
.len
) outl
= user
.len
;
460 if (copy_to_user(user
.data
,
462 outl
)) return -EFAULT
;
464 if (copy_to_user((struct ncp_privatedata_ioctl
*)arg
,
466 sizeof(user
))) return -EFAULT
;
469 case NCP_IOC_SETPRIVATEDATA
:
470 if (current
->uid
!= server
->m
.mounted_uid
) {
474 struct ncp_privatedata_ioctl user
;
479 if (copy_from_user(&user
,
480 (struct ncp_privatedata_ioctl
*)arg
,
481 sizeof(user
))) return -EFAULT
;
482 if (user
.len
> NCP_PRIVATE_DATA_MAX_LEN
)
485 new = ncp_kmalloc(user
.len
, GFP_USER
);
486 if (!new) return -ENOMEM
;
487 if (copy_from_user(new, user
.data
, user
.len
)) {
488 ncp_kfree_s(new, user
.len
);
494 /* enter critical section */
495 old
= server
->priv
.data
;
496 oldlen
= server
->priv
.len
;
497 server
->priv
.len
= user
.len
;
498 server
->priv
.data
= new;
499 /* leave critical section */
500 if (old
) ncp_kfree_s(old
, oldlen
);
504 #ifdef CONFIG_NCPFS_NLS
505 /* Here we are select the iocharset and the codepage for NLS.
506 * Thanks Petr Vandrovec for idea and many hints.
508 case NCP_IOC_SETCHARSETS
:
509 if (!capable(CAP_SYS_ADMIN
))
511 if (server
->root_setuped
)
515 struct ncp_nls_ioctl user
;
516 struct nls_table
*codepage
;
517 struct nls_table
*iocharset
;
518 struct nls_table
*oldset_io
;
519 struct nls_table
*oldset_cp
;
521 if (copy_from_user(&user
, (struct ncp_nls_ioctl
*)arg
,
526 user
.codepage
[NCP_IOCSNAME_LEN
] = 0;
527 if (!user
.codepage
[0] ||
528 !strcmp(user
.codepage
, "default"))
529 codepage
= load_nls_default();
531 codepage
= load_nls(user
.codepage
);
538 user
.iocharset
[NCP_IOCSNAME_LEN
] = 0;
539 if (!user
.iocharset
[0] ||
540 !strcmp(user
.iocharset
, "default")) {
541 iocharset
= load_nls_default();
542 NCP_CLR_FLAG(server
, NCP_FLAG_UTF8
);
544 if (!strcmp(user
.iocharset
, "utf8")) {
545 iocharset
= load_nls_default();
546 NCP_SET_FLAG(server
, NCP_FLAG_UTF8
);
548 iocharset
= load_nls(user
.iocharset
);
550 unload_nls(codepage
);
553 NCP_CLR_FLAG(server
, NCP_FLAG_UTF8
);
557 oldset_cp
= server
->nls_vol
;
558 server
->nls_vol
= codepage
;
559 oldset_io
= server
->nls_io
;
560 server
->nls_io
= iocharset
;
563 unload_nls(oldset_cp
);
565 unload_nls(oldset_io
);
570 case NCP_IOC_GETCHARSETS
: /* not tested */
572 struct ncp_nls_ioctl user
;
575 memset(&user
, 0, sizeof(user
));
576 if (server
->nls_vol
&& server
->nls_vol
->charset
) {
577 len
= strlen(server
->nls_vol
->charset
);
578 if (len
> NCP_IOCSNAME_LEN
)
579 len
= NCP_IOCSNAME_LEN
;
580 strncpy(user
.codepage
,
581 server
->nls_vol
->charset
, len
);
582 user
.codepage
[len
] = 0;
585 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
))
586 strcpy(user
.iocharset
, "utf8");
588 if (server
->nls_io
&& server
->nls_io
->charset
) {
589 len
= strlen(server
->nls_io
->charset
);
590 if (len
> NCP_IOCSNAME_LEN
)
591 len
= NCP_IOCSNAME_LEN
;
592 strncpy(user
.iocharset
,
593 server
->nls_io
->charset
, len
);
594 user
.iocharset
[len
] = 0;
597 if (copy_to_user((struct ncp_nls_ioctl
*)arg
, &user
,
603 #endif /* CONFIG_NCPFS_NLS */
604 case NCP_IOC_SETDENTRYTTL
:
605 if ((permission(inode
, MAY_WRITE
) != 0) &&
606 (current
->uid
!= server
->m
.mounted_uid
))
611 if (copy_from_user(&user
, (u_int32_t
*)arg
, sizeof(user
)))
613 /* 20 secs at most... */
616 user
= (user
* HZ
) / 1000;
617 server
->dentry_ttl
= user
;
621 case NCP_IOC_GETDENTRYTTL
:
623 u_int32_t user
= (server
->dentry_ttl
* 1000) / HZ
;
624 if (copy_to_user((u_int32_t
*)arg
, &user
, sizeof(user
)))
630 /* #ifdef CONFIG_UID16 */
631 /* NCP_IOC_GETMOUNTUID may be same as NCP_IOC_GETMOUNTUID2,
632 so we have this out of switch */
633 if (cmd
== NCP_IOC_GETMOUNTUID
) {
634 if ((permission(inode
, MAY_READ
) != 0)
635 && (current
->uid
!= server
->m
.mounted_uid
)) {
638 if (put_user(NEW_TO_OLD_UID(server
->m
.mounted_uid
), (__kernel_uid_t
*) arg
))