ioctl.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:16k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  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. #include <linux/config.h>
  10. #include <asm/uaccess.h>
  11. #include <linux/errno.h>
  12. #include <linux/fs.h>
  13. #include <linux/ioctl.h>
  14. #include <linux/sched.h>
  15. #include <linux/mm.h>
  16. #include <linux/highuid.h>
  17. #include <linux/vmalloc.h>
  18. #include <linux/ncp_fs.h>
  19. #include "ncplib_kernel.h"
  20. /* maximum limit for ncp_objectname_ioctl */
  21. #define NCP_OBJECT_NAME_MAX_LEN 4096
  22. /* maximum limit for ncp_privatedata_ioctl */
  23. #define NCP_PRIVATE_DATA_MAX_LEN 8192
  24. /* maximum negotiable packet size */
  25. #define NCP_PACKET_SIZE_INTERNAL 65536
  26. int ncp_ioctl(struct inode *inode, struct file *filp,
  27.       unsigned int cmd, unsigned long arg)
  28. {
  29. struct ncp_server *server = NCP_SERVER(inode);
  30. int result;
  31. struct ncp_ioctl_request request;
  32. char* bouncebuffer;
  33. switch (cmd) {
  34. case NCP_IOC_NCPREQUEST:
  35. if ((permission(inode, MAY_WRITE) != 0)
  36.     && (current->uid != server->m.mounted_uid)) {
  37. return -EACCES;
  38. }
  39. if (copy_from_user(&request, (struct ncp_ioctl_request *) arg,
  40.        sizeof(request)))
  41. return -EFAULT;
  42. if ((request.function > 255)
  43.     || (request.size >
  44.   NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) {
  45. return -EINVAL;
  46. }
  47. bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL);
  48. if (!bouncebuffer)
  49. return -ENOMEM;
  50. if (copy_from_user(bouncebuffer, request.data, request.size)) {
  51. vfree(bouncebuffer);
  52. return -EFAULT;
  53. }
  54. ncp_lock_server(server);
  55. /* FIXME: We hack around in the server's structures
  56.    here to be able to use ncp_request */
  57. server->has_subfunction = 0;
  58. server->current_size = request.size;
  59. memcpy(server->packet, bouncebuffer, request.size);
  60. result = ncp_request2(server, request.function, 
  61. bouncebuffer, NCP_PACKET_SIZE_INTERNAL);
  62. if (result < 0)
  63. result = -EIO;
  64. else
  65. result = server->reply_size;
  66. ncp_unlock_server(server);
  67. DPRINTK("ncp_ioctl: copy %d bytesn",
  68. result);
  69. if (result >= 0)
  70. if (copy_to_user(request.data, bouncebuffer, result))
  71. result = -EFAULT;
  72. vfree(bouncebuffer);
  73. return result;
  74. case NCP_IOC_CONN_LOGGED_IN:
  75. if (!capable(CAP_SYS_ADMIN))
  76. return -EACCES;
  77. if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE))
  78. return -EINVAL;
  79. if (server->root_setuped)
  80. return -EBUSY;
  81. server->root_setuped = 1;
  82. return ncp_conn_logged_in(inode->i_sb);
  83. case NCP_IOC_GET_FS_INFO:
  84. {
  85. struct ncp_fs_info info;
  86. if ((permission(inode, MAY_WRITE) != 0)
  87.     && (current->uid != server->m.mounted_uid)) {
  88. return -EACCES;
  89. }
  90. if (copy_from_user(&info, (struct ncp_fs_info *) arg, 
  91. sizeof(info)))
  92. return -EFAULT;
  93. if (info.version != NCP_GET_FS_INFO_VERSION) {
  94. DPRINTK("info.version invalid: %dn", info.version);
  95. return -EINVAL;
  96. }
  97. /* TODO: info.addr = server->m.serv_addr; */
  98. info.mounted_uid = NEW_TO_OLD_UID(server->m.mounted_uid);
  99. info.connection = server->connection;
  100. info.buffer_size = server->buffer_size;
  101. info.volume_number = NCP_FINFO(inode)->volNumber;
  102. info.directory_id = NCP_FINFO(inode)->DosDirNum;
  103. if (copy_to_user((struct ncp_fs_info *) arg, &info, 
  104. sizeof(info))) return -EFAULT;
  105. return 0;
  106. }
  107. case NCP_IOC_GET_FS_INFO_V2:
  108. {
  109. struct ncp_fs_info_v2 info2;
  110. if ((permission(inode, MAY_WRITE) != 0)
  111.     && (current->uid != server->m.mounted_uid)) {
  112. return -EACCES;
  113. }
  114. if (copy_from_user(&info2, (struct ncp_fs_info_v2 *) arg, 
  115. sizeof(info2)))
  116. return -EFAULT;
  117. if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
  118. DPRINTK("info.version invalid: %dn", info2.version);
  119. return -EINVAL;
  120. }
  121. info2.mounted_uid   = server->m.mounted_uid;
  122. info2.connection    = server->connection;
  123. info2.buffer_size   = server->buffer_size;
  124. info2.volume_number = NCP_FINFO(inode)->volNumber;
  125. info2.directory_id  = NCP_FINFO(inode)->DosDirNum;
  126. info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
  127. if (copy_to_user((struct ncp_fs_info_v2 *) arg, &info2, 
  128. sizeof(info2))) return -EFAULT;
  129. return 0;
  130. }
  131. case NCP_IOC_GETMOUNTUID2:
  132. {
  133. unsigned long tmp = server->m.mounted_uid;
  134. if (   (permission(inode, MAY_READ) != 0)
  135.     && (current->uid != server->m.mounted_uid))
  136. {
  137. return -EACCES;
  138. }
  139. if (put_user(tmp, (unsigned long*) arg)) 
  140. return -EFAULT;
  141. return 0;
  142. }
  143. case NCP_IOC_GETROOT:
  144. {
  145. struct ncp_setroot_ioctl sr;
  146. if (   (permission(inode, MAY_READ) != 0)
  147.     && (current->uid != server->m.mounted_uid))
  148. {
  149. return -EACCES;
  150. }
  151. if (server->m.mounted_vol[0]) {
  152. struct dentry* dentry = inode->i_sb->s_root;
  153. if (dentry) {
  154. struct inode* inode = dentry->d_inode;
  155. if (inode) {
  156. sr.volNumber = NCP_FINFO(inode)->volNumber;
  157. sr.dirEntNum = NCP_FINFO(inode)->dirEntNum;
  158. sr.namespace = server->name_space[sr.volNumber];
  159. } else
  160. DPRINTK("ncpfs: s_root->d_inode==NULLn");
  161. } else
  162. DPRINTK("ncpfs: s_root==NULLn");
  163. } else {
  164. sr.volNumber = -1;
  165. sr.namespace = 0;
  166. sr.dirEntNum = 0;
  167. }
  168. if (copy_to_user((struct ncp_setroot_ioctl*)arg, 
  169.        &sr, 
  170.   sizeof(sr))) return -EFAULT;
  171. return 0;
  172. }
  173. case NCP_IOC_SETROOT:
  174. {
  175. struct ncp_setroot_ioctl sr;
  176. struct nw_info_struct i;
  177. struct dentry* dentry;
  178. if (!capable(CAP_SYS_ADMIN))
  179. {
  180. return -EACCES;
  181. }
  182. if (server->root_setuped) return -EBUSY;
  183. if (copy_from_user(&sr,
  184.    (struct ncp_setroot_ioctl*)arg, 
  185.    sizeof(sr))) return -EFAULT;
  186. if (sr.volNumber < 0) {
  187. server->m.mounted_vol[0] = 0;
  188. i.volNumber = NCP_NUMBER_OF_VOLUMES + 1;
  189. i.dirEntNum = 0;
  190. i.DosDirNum = 0;
  191. } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) {
  192. return -EINVAL;
  193. } else
  194. if (ncp_mount_subdir(server, &i, sr.volNumber,
  195. sr.namespace, sr.dirEntNum))
  196. return -ENOENT;
  197. dentry = inode->i_sb->s_root;
  198. server->root_setuped = 1;
  199. if (dentry) {
  200. struct inode* inode = dentry->d_inode;
  201. if (inode) {
  202. NCP_FINFO(inode)->volNumber = i.volNumber;
  203. NCP_FINFO(inode)->dirEntNum = i.dirEntNum;
  204. NCP_FINFO(inode)->DosDirNum = i.DosDirNum;
  205. } else
  206. DPRINTK("ncpfs: s_root->d_inode==NULLn");
  207. } else
  208. DPRINTK("ncpfs: s_root==NULLn");
  209. return 0;
  210. }
  211. #ifdef CONFIG_NCPFS_PACKET_SIGNING
  212. case NCP_IOC_SIGN_INIT:
  213. if ((permission(inode, MAY_WRITE) != 0)
  214.     && (current->uid != server->m.mounted_uid))
  215. {
  216. return -EACCES;
  217. }
  218. if (arg) {
  219. if (server->sign_wanted)
  220. {
  221. struct ncp_sign_init sign;
  222. if (copy_from_user(&sign, (struct ncp_sign_init *) arg,
  223.       sizeof(sign))) return -EFAULT;
  224. memcpy(server->sign_root,sign.sign_root,8);
  225. memcpy(server->sign_last,sign.sign_last,16);
  226. server->sign_active = 1;
  227. }
  228. /* ignore when signatures not wanted */
  229. } else {
  230. server->sign_active = 0;
  231. }
  232. return 0;
  233.         case NCP_IOC_SIGN_WANTED:
  234. if (   (permission(inode, MAY_READ) != 0)
  235.     && (current->uid != server->m.mounted_uid))
  236. {
  237. return -EACCES;
  238. }
  239.                 if (put_user(server->sign_wanted, (int*) arg))
  240. return -EFAULT;
  241.                 return 0;
  242. case NCP_IOC_SET_SIGN_WANTED:
  243. {
  244. int newstate;
  245. if (   (permission(inode, MAY_WRITE) != 0)
  246.     && (current->uid != server->m.mounted_uid))
  247. {
  248. return -EACCES;
  249. }
  250. /* get only low 8 bits... */
  251. if (get_user(newstate, (unsigned char *) arg))
  252. return -EFAULT;
  253. if (server->sign_active) {
  254. /* cannot turn signatures OFF when active */
  255. if (!newstate) return -EINVAL;
  256. } else {
  257. server->sign_wanted = newstate != 0;
  258. }
  259. return 0;
  260. }
  261. #endif /* CONFIG_NCPFS_PACKET_SIGNING */
  262. #ifdef CONFIG_NCPFS_IOCTL_LOCKING
  263. case NCP_IOC_LOCKUNLOCK:
  264. if (   (permission(inode, MAY_WRITE) != 0)
  265.     && (current->uid != server->m.mounted_uid))
  266. {
  267. return -EACCES;
  268. }
  269. {
  270. struct ncp_lock_ioctl  rqdata;
  271. int result;
  272. if (copy_from_user(&rqdata, (struct ncp_lock_ioctl*)arg,
  273. sizeof(rqdata))) return -EFAULT;
  274. if (rqdata.origin != 0)
  275. return -EINVAL;
  276. /* check for cmd */
  277. switch (rqdata.cmd) {
  278. case NCP_LOCK_EX:
  279. case NCP_LOCK_SH:
  280. if (rqdata.timeout == 0)
  281. rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT;
  282. else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT)
  283. rqdata.timeout = NCP_LOCK_MAX_TIMEOUT;
  284. break;
  285. case NCP_LOCK_LOG:
  286. rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; /* has no effect */
  287. case NCP_LOCK_CLEAR:
  288. break;
  289. default:
  290. return -EINVAL;
  291. }
  292. /* locking needs both read and write access */
  293. if ((result = ncp_make_open(inode, O_RDWR)) != 0)
  294. {
  295. return result;
  296. }
  297. result = -EIO;
  298. if (!ncp_conn_valid(server))
  299. goto outrel;
  300. result = -EISDIR;
  301. if (!S_ISREG(inode->i_mode))
  302. goto outrel;
  303. if (rqdata.cmd == NCP_LOCK_CLEAR)
  304. {
  305. result = ncp_ClearPhysicalRecord(NCP_SERVER(inode),
  306. NCP_FINFO(inode)->file_handle, 
  307. rqdata.offset,
  308. rqdata.length);
  309. if (result > 0) result = 0; /* no such lock */
  310. }
  311. else
  312. {
  313. int lockcmd;
  314. switch (rqdata.cmd)
  315. {
  316. case NCP_LOCK_EX:  lockcmd=1; break;
  317. case NCP_LOCK_SH:  lockcmd=3; break;
  318. default:    lockcmd=0; break;
  319. }
  320. result = ncp_LogPhysicalRecord(NCP_SERVER(inode),
  321. NCP_FINFO(inode)->file_handle,
  322. lockcmd,
  323. rqdata.offset,
  324. rqdata.length,
  325. rqdata.timeout);
  326. if (result > 0) result = -EAGAIN;
  327. }
  328. outrel:
  329. ncp_inode_close(inode);
  330. return result;
  331. }
  332. #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
  333. case NCP_IOC_GETOBJECTNAME:
  334. if (current->uid != server->m.mounted_uid) {
  335. return -EACCES;
  336. }
  337. {
  338. struct ncp_objectname_ioctl user;
  339. size_t outl;
  340. if (copy_from_user(&user, 
  341.    (struct ncp_objectname_ioctl*)arg,
  342.    sizeof(user))) return -EFAULT;
  343. user.auth_type = server->auth.auth_type;
  344. outl = user.object_name_len;
  345. user.object_name_len = server->auth.object_name_len;
  346. if (outl > user.object_name_len)
  347. outl = user.object_name_len;
  348. if (outl) {
  349. if (copy_to_user(user.object_name,
  350.  server->auth.object_name,
  351.  outl)) return -EFAULT;
  352. }
  353. if (copy_to_user((struct ncp_objectname_ioctl*)arg,
  354.  &user,
  355.  sizeof(user))) return -EFAULT;
  356. return 0;
  357. }
  358. case NCP_IOC_SETOBJECTNAME:
  359. if (current->uid != server->m.mounted_uid) {
  360. return -EACCES;
  361. }
  362. {
  363. struct ncp_objectname_ioctl user;
  364. void* newname;
  365. void* oldname;
  366. size_t oldnamelen;
  367. void* oldprivate;
  368. size_t oldprivatelen;
  369. if (copy_from_user(&user, 
  370.    (struct ncp_objectname_ioctl*)arg,
  371.    sizeof(user))) return -EFAULT;
  372. if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN)
  373. return -ENOMEM;
  374. if (user.object_name_len) {
  375. newname = ncp_kmalloc(user.object_name_len, GFP_USER);
  376. if (!newname) return -ENOMEM;
  377. if (copy_from_user(newname, user.object_name, sizeof(user))) {
  378. ncp_kfree_s(newname, user.object_name_len);
  379. return -EFAULT;
  380. }
  381. } else {
  382. newname = NULL;
  383. }
  384. /* enter critical section */
  385. /* maybe that kfree can sleep so do that this way */
  386. /* it is at least more SMP friendly (in future...) */
  387. oldname = server->auth.object_name;
  388. oldnamelen = server->auth.object_name_len;
  389. oldprivate = server->priv.data;
  390. oldprivatelen = server->priv.len;
  391. server->auth.auth_type = user.auth_type;
  392. server->auth.object_name_len = user.object_name_len;
  393. server->auth.object_name = user.object_name;
  394. server->priv.len = 0;
  395. server->priv.data = NULL;
  396. /* leave critical section */
  397. if (oldprivate) ncp_kfree_s(oldprivate, oldprivatelen);
  398. if (oldname) ncp_kfree_s(oldname, oldnamelen);
  399. return 0;
  400. }
  401. case NCP_IOC_GETPRIVATEDATA:
  402. if (current->uid != server->m.mounted_uid) {
  403. return -EACCES;
  404. }
  405. {
  406. struct ncp_privatedata_ioctl user;
  407. size_t outl;
  408. if (copy_from_user(&user, 
  409.    (struct ncp_privatedata_ioctl*)arg,
  410.    sizeof(user))) return -EFAULT;
  411. outl = user.len;
  412. user.len = server->priv.len;
  413. if (outl > user.len) outl = user.len;
  414. if (outl) {
  415. if (copy_to_user(user.data,
  416.  server->priv.data,
  417.  outl)) return -EFAULT;
  418. }
  419. if (copy_to_user((struct ncp_privatedata_ioctl*)arg,
  420.  &user,
  421.  sizeof(user))) return -EFAULT;
  422. return 0;
  423. }
  424. case NCP_IOC_SETPRIVATEDATA:
  425. if (current->uid != server->m.mounted_uid) {
  426. return -EACCES;
  427. }
  428. {
  429. struct ncp_privatedata_ioctl user;
  430. void* new;
  431. void* old;
  432. size_t oldlen;
  433. if (copy_from_user(&user, 
  434.    (struct ncp_privatedata_ioctl*)arg,
  435.    sizeof(user))) return -EFAULT;
  436. if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
  437. return -ENOMEM;
  438. if (user.len) {
  439. new = ncp_kmalloc(user.len, GFP_USER);
  440. if (!new) return -ENOMEM;
  441. if (copy_from_user(new, user.data, user.len)) {
  442. ncp_kfree_s(new, user.len);
  443. return -EFAULT;
  444. }
  445. } else {
  446. new = NULL;
  447. }
  448. /* enter critical section */
  449. old = server->priv.data;
  450. oldlen = server->priv.len;
  451. server->priv.len = user.len;
  452. server->priv.data = new;
  453. /* leave critical section */
  454. if (old) ncp_kfree_s(old, oldlen);
  455. return 0;
  456. }
  457. #ifdef CONFIG_NCPFS_NLS
  458. /* Here we are select the iocharset and the codepage for NLS.
  459.  * Thanks Petr Vandrovec for idea and many hints.
  460.  */
  461. case NCP_IOC_SETCHARSETS:
  462. if (!capable(CAP_SYS_ADMIN))
  463. return -EACCES;
  464. if (server->root_setuped)
  465. return -EBUSY;
  466. {
  467. struct ncp_nls_ioctl user;
  468. struct nls_table *codepage;
  469. struct nls_table *iocharset;
  470. struct nls_table *oldset_io;
  471. struct nls_table *oldset_cp;
  472. if (copy_from_user(&user, (struct ncp_nls_ioctl*)arg,
  473. sizeof(user)))
  474. return -EFAULT;
  475. codepage = NULL;
  476. user.codepage[NCP_IOCSNAME_LEN] = 0;
  477. if (!user.codepage[0] ||
  478. !strcmp(user.codepage, "default"))
  479. codepage = load_nls_default();
  480. else {
  481. codepage = load_nls(user.codepage);
  482. if (!codepage) {
  483. return -EBADRQC;
  484. }
  485. }
  486. iocharset = NULL;
  487. user.iocharset[NCP_IOCSNAME_LEN] = 0;
  488. if (!user.iocharset[0] ||
  489. !strcmp(user.iocharset, "default")) {
  490. iocharset = load_nls_default();
  491. NCP_CLR_FLAG(server, NCP_FLAG_UTF8);
  492. } else {
  493. if (!strcmp(user.iocharset, "utf8")) {
  494. iocharset = load_nls_default();
  495. NCP_SET_FLAG(server, NCP_FLAG_UTF8);
  496. } else {
  497. iocharset = load_nls(user.iocharset);
  498. if (!iocharset) {
  499. unload_nls(codepage);
  500. return -EBADRQC;
  501. }
  502. NCP_CLR_FLAG(server, NCP_FLAG_UTF8);
  503. }
  504. }
  505. oldset_cp = server->nls_vol;
  506. server->nls_vol = codepage;
  507. oldset_io = server->nls_io;
  508. server->nls_io = iocharset;
  509. if (oldset_cp)
  510. unload_nls(oldset_cp);
  511. if (oldset_io)
  512. unload_nls(oldset_io);
  513. return 0;
  514. }
  515. case NCP_IOC_GETCHARSETS: /* not tested */
  516. {
  517. struct ncp_nls_ioctl user;
  518. int len;
  519. memset(&user, 0, sizeof(user));
  520. if (server->nls_vol && server->nls_vol->charset) {
  521. len = strlen(server->nls_vol->charset);
  522. if (len > NCP_IOCSNAME_LEN)
  523. len = NCP_IOCSNAME_LEN;
  524. strncpy(user.codepage,
  525. server->nls_vol->charset, len);
  526. user.codepage[len] = 0;
  527. }
  528. if (NCP_IS_FLAG(server, NCP_FLAG_UTF8))
  529. strcpy(user.iocharset, "utf8");
  530. else
  531. if (server->nls_io && server->nls_io->charset) {
  532. len = strlen(server->nls_io->charset);
  533. if (len > NCP_IOCSNAME_LEN)
  534. len = NCP_IOCSNAME_LEN;
  535. strncpy(user.iocharset,
  536. server->nls_io->charset, len);
  537. user.iocharset[len] = 0;
  538. }
  539. if (copy_to_user((struct ncp_nls_ioctl*)arg, &user,
  540. sizeof(user)))
  541. return -EFAULT;
  542. return 0;
  543. }
  544. #endif /* CONFIG_NCPFS_NLS */
  545. case NCP_IOC_SETDENTRYTTL:
  546. if ((permission(inode, MAY_WRITE) != 0) &&
  547.  (current->uid != server->m.mounted_uid))
  548. return -EACCES;
  549. {
  550. u_int32_t user;
  551. if (copy_from_user(&user, (u_int32_t*)arg, sizeof(user)))
  552. return -EFAULT;
  553. /* 20 secs at most... */
  554. if (user > 20000)
  555. return -EINVAL;
  556. user = (user * HZ) / 1000;
  557. server->dentry_ttl = user;
  558. return 0;
  559. }
  560. case NCP_IOC_GETDENTRYTTL:
  561. {
  562. u_int32_t user = (server->dentry_ttl * 1000) / HZ;
  563. if (copy_to_user((u_int32_t*)arg, &user, sizeof(user)))
  564. return -EFAULT;
  565. return 0;
  566. }
  567. }
  568. /* #ifdef CONFIG_UID16 */
  569. /* NCP_IOC_GETMOUNTUID may be same as NCP_IOC_GETMOUNTUID2,
  570.            so we have this out of switch */
  571. if (cmd == NCP_IOC_GETMOUNTUID) {
  572. if ((permission(inode, MAY_READ) != 0)
  573.     && (current->uid != server->m.mounted_uid)) {
  574. return -EACCES;
  575. }
  576. if (put_user(NEW_TO_OLD_UID(server->m.mounted_uid), (__kernel_uid_t *) arg))
  577. return -EFAULT;
  578. return 0;
  579. }
  580. /* #endif */
  581. return -EINVAL;
  582. }