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