misc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. /*
  2. * fs/cifs/misc.c
  3. *
  4. * Copyright (C) International Business Machines Corp., 2002,2004
  5. * Author(s): Steve French (sfrench@us.ibm.com)
  6. *
  7. * This library is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published
  9. * by the Free Software Foundation; either version 2.1 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  15. * the GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. #include <linux/slab.h>
  22. #include <linux/ctype.h>
  23. #include <linux/mempool.h>
  24. #include "cifspdu.h"
  25. #include "cifsglob.h"
  26. #include "cifsproto.h"
  27. #include "cifs_debug.h"
  28. #include "smberr.h"
  29. #include "nterr.h"
  30. extern mempool_t *cifs_sm_req_poolp;
  31. extern mempool_t *cifs_req_poolp;
  32. extern struct task_struct * oplockThread;
  33. static __u16 GlobalMid; /* multiplex id - rotating counter */
  34. /* The xid serves as a useful identifier for each incoming vfs request,
  35. in a similar way to the mid which is useful to track each sent smb,
  36. and CurrentXid can also provide a running counter (although it
  37. will eventually wrap past zero) of the total vfs operations handled
  38. since the cifs fs was mounted */
  39. unsigned int
  40. _GetXid(void)
  41. {
  42. unsigned int xid;
  43. spin_lock(&GlobalMid_Lock);
  44. GlobalTotalActiveXid++;
  45. if (GlobalTotalActiveXid > GlobalMaxActiveXid)
  46. GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */
  47. xid = GlobalCurrentXid++;
  48. spin_unlock(&GlobalMid_Lock);
  49. return xid;
  50. }
  51. void
  52. _FreeXid(unsigned int xid)
  53. {
  54. spin_lock(&GlobalMid_Lock);
  55. /* if(GlobalTotalActiveXid == 0)
  56. BUG(); */
  57. GlobalTotalActiveXid--;
  58. spin_unlock(&GlobalMid_Lock);
  59. }
  60. struct cifsSesInfo *
  61. sesInfoAlloc(void)
  62. {
  63. struct cifsSesInfo *ret_buf;
  64. ret_buf =
  65. (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo),
  66. GFP_KERNEL);
  67. if (ret_buf) {
  68. memset(ret_buf, 0, sizeof (struct cifsSesInfo));
  69. write_lock(&GlobalSMBSeslock);
  70. atomic_inc(&sesInfoAllocCount);
  71. ret_buf->status = CifsNew;
  72. list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList);
  73. init_MUTEX(&ret_buf->sesSem);
  74. write_unlock(&GlobalSMBSeslock);
  75. }
  76. return ret_buf;
  77. }
  78. void
  79. sesInfoFree(struct cifsSesInfo *buf_to_free)
  80. {
  81. if (buf_to_free == NULL) {
  82. cFYI(1, ("Null buffer passed to sesInfoFree"));
  83. return;
  84. }
  85. write_lock(&GlobalSMBSeslock);
  86. atomic_dec(&sesInfoAllocCount);
  87. list_del(&buf_to_free->cifsSessionList);
  88. write_unlock(&GlobalSMBSeslock);
  89. if (buf_to_free->serverOS)
  90. kfree(buf_to_free->serverOS);
  91. if (buf_to_free->serverDomain)
  92. kfree(buf_to_free->serverDomain);
  93. if (buf_to_free->serverNOS)
  94. kfree(buf_to_free->serverNOS);
  95. if (buf_to_free->password)
  96. kfree(buf_to_free->password);
  97. kfree(buf_to_free);
  98. }
  99. struct cifsTconInfo *
  100. tconInfoAlloc(void)
  101. {
  102. struct cifsTconInfo *ret_buf;
  103. ret_buf =
  104. (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo),
  105. GFP_KERNEL);
  106. if (ret_buf) {
  107. memset(ret_buf, 0, sizeof (struct cifsTconInfo));
  108. write_lock(&GlobalSMBSeslock);
  109. atomic_inc(&tconInfoAllocCount);
  110. list_add(&ret_buf->cifsConnectionList,
  111. &GlobalTreeConnectionList);
  112. ret_buf->tidStatus = CifsNew;
  113. INIT_LIST_HEAD(&ret_buf->openFileList);
  114. init_MUTEX(&ret_buf->tconSem);
  115. #ifdef CONFIG_CIFS_STATS
  116. spin_lock_init(&ret_buf->stat_lock);
  117. #endif
  118. write_unlock(&GlobalSMBSeslock);
  119. }
  120. return ret_buf;
  121. }
  122. void
  123. tconInfoFree(struct cifsTconInfo *buf_to_free)
  124. {
  125. if (buf_to_free == NULL) {
  126. cFYI(1, ("Null buffer passed to tconInfoFree"));
  127. return;
  128. }
  129. write_lock(&GlobalSMBSeslock);
  130. atomic_dec(&tconInfoAllocCount);
  131. list_del(&buf_to_free->cifsConnectionList);
  132. write_unlock(&GlobalSMBSeslock);
  133. if (buf_to_free->nativeFileSystem)
  134. kfree(buf_to_free->nativeFileSystem);
  135. kfree(buf_to_free);
  136. }
  137. struct smb_hdr *
  138. cifs_buf_get(void)
  139. {
  140. struct smb_hdr *ret_buf = NULL;
  141. /* We could use negotiated size instead of max_msgsize -
  142. but it may be more efficient to always alloc same size
  143. albeit slightly larger than necessary and maxbuffersize
  144. defaults to this and can not be bigger */
  145. ret_buf =
  146. (struct smb_hdr *) mempool_alloc(cifs_req_poolp, SLAB_KERNEL | SLAB_NOFS);
  147. /* clear the first few header bytes */
  148. /* for most paths, more is cleared in header_assemble */
  149. if (ret_buf) {
  150. memset(ret_buf, 0, sizeof(struct smb_hdr) + 3);
  151. atomic_inc(&bufAllocCount);
  152. }
  153. return ret_buf;
  154. }
  155. void
  156. cifs_buf_release(void *buf_to_free)
  157. {
  158. if (buf_to_free == NULL) {
  159. /* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/
  160. return;
  161. }
  162. mempool_free(buf_to_free,cifs_req_poolp);
  163. atomic_dec(&bufAllocCount);
  164. return;
  165. }
  166. struct smb_hdr *
  167. cifs_small_buf_get(void)
  168. {
  169. struct smb_hdr *ret_buf = NULL;
  170. /* We could use negotiated size instead of max_msgsize -
  171. but it may be more efficient to always alloc same size
  172. albeit slightly larger than necessary and maxbuffersize
  173. defaults to this and can not be bigger */
  174. ret_buf =
  175. (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, SLAB_KERNEL | SLAB_NOFS);
  176. if (ret_buf) {
  177. /* No need to clear memory here, cleared in header assemble */
  178. /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
  179. atomic_inc(&smBufAllocCount);
  180. }
  181. return ret_buf;
  182. }
  183. void
  184. cifs_small_buf_release(void *buf_to_free)
  185. {
  186. if (buf_to_free == NULL) {
  187. cFYI(1, ("Null buffer passed to cifs_small_buf_release"));
  188. return;
  189. }
  190. mempool_free(buf_to_free,cifs_sm_req_poolp);
  191. atomic_dec(&smBufAllocCount);
  192. return;
  193. }
  194. void
  195. header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
  196. const struct cifsTconInfo *treeCon, int word_count
  197. /* length of fixed section (word count) in two byte units */)
  198. {
  199. struct list_head* temp_item;
  200. struct cifsSesInfo * ses;
  201. char *temp = (char *) buffer;
  202. memset(temp,0,MAX_CIFS_HDR_SIZE);
  203. buffer->smb_buf_length =
  204. (2 * word_count) + sizeof (struct smb_hdr) -
  205. 4 /* RFC 1001 length field does not count */ +
  206. 2 /* for bcc field itself */ ;
  207. /* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */
  208. buffer->Protocol[0] = 0xFF;
  209. buffer->Protocol[1] = 'S';
  210. buffer->Protocol[2] = 'M';
  211. buffer->Protocol[3] = 'B';
  212. buffer->Command = smb_command;
  213. buffer->Flags = 0x00; /* case sensitive */
  214. buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
  215. buffer->Pid = cpu_to_le16((__u16)current->tgid);
  216. buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
  217. spin_lock(&GlobalMid_Lock);
  218. GlobalMid++;
  219. buffer->Mid = GlobalMid;
  220. spin_unlock(&GlobalMid_Lock);
  221. if (treeCon) {
  222. buffer->Tid = treeCon->tid;
  223. if (treeCon->ses) {
  224. if (treeCon->ses->capabilities & CAP_UNICODE)
  225. buffer->Flags2 |= SMBFLG2_UNICODE;
  226. if (treeCon->ses->capabilities & CAP_STATUS32) {
  227. buffer->Flags2 |= SMBFLG2_ERR_STATUS;
  228. }
  229. buffer->Uid = treeCon->ses->Suid; /* always in LE format */
  230. if(multiuser_mount != 0) {
  231. /* For the multiuser case, there are few obvious technically */
  232. /* possible mechanisms to match the local linux user (uid) */
  233. /* to a valid remote smb user (smb_uid): */
  234. /* 1) Query Winbind (or other local pam/nss daemon */
  235. /* for userid/password/logon_domain or credential */
  236. /* 2) Query Winbind for uid to sid to username mapping */
  237. /* and see if we have a matching password for existing*/
  238. /* session for that user perhas getting password by */
  239. /* adding a new pam_cifs module that stores passwords */
  240. /* so that the cifs vfs can get at that for all logged*/
  241. /* on users */
  242. /* 3) (Which is the mechanism we have chosen) */
  243. /* Search through sessions to the same server for a */
  244. /* a match on the uid that was passed in on mount */
  245. /* with the current processes uid (or euid?) and use */
  246. /* that smb uid. If no existing smb session for */
  247. /* that uid found, use the default smb session ie */
  248. /* the smb session for the volume mounted which is */
  249. /* the same as would be used if the multiuser mount */
  250. /* flag were disabled. */
  251. /* BB Add support for establishing new tCon and SMB Session */
  252. /* with userid/password pairs found on the smb session */
  253. /* for other target tcp/ip addresses BB */
  254. if(current->uid != treeCon->ses->linux_uid) {
  255. cFYI(1,("Multiuser mode and UID did not match tcon uid "));
  256. read_lock(&GlobalSMBSeslock);
  257. list_for_each(temp_item, &GlobalSMBSessionList) {
  258. ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
  259. if(ses->linux_uid == current->uid) {
  260. if(ses->server == treeCon->ses->server) {
  261. cFYI(1,("found matching uid substitute right smb_uid"));
  262. buffer->Uid = ses->Suid;
  263. break;
  264. } else {
  265. /* BB eventually call cifs_setup_session here */
  266. cFYI(1,("local UID found but smb sess with this server does not exist"));
  267. }
  268. }
  269. }
  270. read_unlock(&GlobalSMBSeslock);
  271. }
  272. }
  273. }
  274. if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
  275. buffer->Flags2 |= SMBFLG2_DFS;
  276. if((treeCon->ses) && (treeCon->ses->server))
  277. if(treeCon->ses->server->secMode &
  278. (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
  279. buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
  280. }
  281. /* endian conversion of flags is now done just before sending */
  282. buffer->WordCount = (char) word_count;
  283. return;
  284. }
  285. int
  286. checkSMBhdr(struct smb_hdr *smb, __u16 mid)
  287. {
  288. /* Make sure that this really is an SMB, that it is a response,
  289. and that the message ids match */
  290. if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
  291. (mid == smb->Mid)) {
  292. if(smb->Flags & SMBFLG_RESPONSE)
  293. return 0;
  294. else {
  295. /* only one valid case where server sends us request */
  296. if(smb->Command == SMB_COM_LOCKING_ANDX)
  297. return 0;
  298. else
  299. cERROR(1, ("Rcvd Request not response "));
  300. }
  301. } else { /* bad signature or mid */
  302. if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
  303. cERROR(1,
  304. ("Bad protocol string signature header %x ",
  305. *(unsigned int *) smb->Protocol));
  306. if (mid != smb->Mid)
  307. cERROR(1, ("Mids do not match"));
  308. }
  309. cERROR(1, ("bad smb detected. The Mid=%d", smb->Mid));
  310. return 1;
  311. }
  312. int
  313. checkSMB(struct smb_hdr *smb, __u16 mid, int length)
  314. {
  315. __u32 len = be32_to_cpu(smb->smb_buf_length);
  316. cFYI(0,
  317. ("Entering checkSMB with Length: %x, smb_buf_length: %x ",
  318. length, len));
  319. if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
  320. (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
  321. if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
  322. if (((unsigned int)length >=
  323. sizeof (struct smb_hdr) - 1)
  324. && (smb->Status.CifsError != 0)) {
  325. smb->WordCount = 0;
  326. return 0; /* some error cases do not return wct and bcc */
  327. } else {
  328. cERROR(1, ("Length less than smb header size"));
  329. }
  330. }
  331. if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
  332. cERROR(1,
  333. ("smb_buf_length greater than MaxBufSize"));
  334. cERROR(1,
  335. ("bad smb detected. Illegal length. The mid=%d",
  336. smb->Mid));
  337. return 1;
  338. }
  339. if (checkSMBhdr(smb, mid))
  340. return 1;
  341. if ((4 + len != smbCalcSize(smb))
  342. || (4 + len != (unsigned int)length)) {
  343. return 0;
  344. } else {
  345. cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
  346. cERROR(1,
  347. ("bad smb size detected. The Mid=%d", smb->Mid));
  348. return 1;
  349. }
  350. }
  351. int
  352. is_valid_oplock_break(struct smb_hdr *buf)
  353. {
  354. struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf;
  355. struct list_head *tmp;
  356. struct list_head *tmp1;
  357. struct cifsTconInfo *tcon;
  358. struct cifsFileInfo *netfile;
  359. cFYI(1,("Checking for oplock break or dnotify response"));
  360. if((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
  361. (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
  362. struct smb_com_transaction_change_notify_rsp * pSMBr =
  363. (struct smb_com_transaction_change_notify_rsp *)buf;
  364. struct file_notify_information * pnotify;
  365. __u32 data_offset = 0;
  366. if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
  367. data_offset = le32_to_cpu(pSMBr->DataOffset);
  368. pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol
  369. + data_offset);
  370. cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName,
  371. pnotify->Action)); /* BB removeme BB */
  372. /* cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */
  373. return TRUE;
  374. }
  375. if(pSMBr->hdr.Status.CifsError) {
  376. cFYI(1,("notify err 0x%d",pSMBr->hdr.Status.CifsError));
  377. return TRUE;
  378. }
  379. return FALSE;
  380. }
  381. if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
  382. return FALSE;
  383. if(pSMB->hdr.Flags & SMBFLG_RESPONSE) {
  384. /* no sense logging error on invalid handle on oplock
  385. break - harmless race between close request and oplock
  386. break response is expected from time to time writing out
  387. large dirty files cached on the client */
  388. if ((NT_STATUS_INVALID_HANDLE) ==
  389. le32_to_cpu(pSMB->hdr.Status.CifsError)) {
  390. cFYI(1,("invalid handle on oplock break"));
  391. return TRUE;
  392. } else if (ERRbadfid ==
  393. le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
  394. return TRUE;
  395. } else {
  396. return FALSE; /* on valid oplock brk we get "request" */
  397. }
  398. }
  399. if(pSMB->hdr.WordCount != 8)
  400. return FALSE;
  401. cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel));
  402. if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
  403. return FALSE;
  404. /* look up tcon based on tid & uid */
  405. read_lock(&GlobalSMBSeslock);
  406. list_for_each(tmp, &GlobalTreeConnectionList) {
  407. tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
  408. if (tcon->tid == buf->Tid) {
  409. #ifdef CONFIG_CIFS_STATS
  410. atomic_inc(&tcon->num_oplock_brks);
  411. #endif
  412. list_for_each(tmp1,&tcon->openFileList){
  413. netfile = list_entry(tmp1,struct cifsFileInfo,tlist);
  414. if(pSMB->Fid == netfile->netfid) {
  415. struct cifsInodeInfo *pCifsInode;
  416. read_unlock(&GlobalSMBSeslock);
  417. cFYI(1,("Matching file id, processing oplock break"));
  418. pCifsInode =
  419. CIFS_I(netfile->pInode);
  420. pCifsInode->clientCanCacheAll = FALSE;
  421. if(pSMB->OplockLevel == 0)
  422. pCifsInode->clientCanCacheRead = FALSE;
  423. pCifsInode->oplockPending = TRUE;
  424. AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon);
  425. cFYI(1,("about to wake up oplock thd"));
  426. wake_up_process(oplockThread);
  427. return TRUE;
  428. }
  429. }
  430. read_unlock(&GlobalSMBSeslock);
  431. cFYI(1,("No matching file for oplock break on connection"));
  432. return TRUE;
  433. }
  434. }
  435. read_unlock(&GlobalSMBSeslock);
  436. cFYI(1,("Can not process oplock break for non-existent connection"));
  437. return TRUE;
  438. }
  439. void
  440. dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
  441. {
  442. int i, j;
  443. char debug_line[17];
  444. unsigned char *buffer;
  445. if (traceSMB == 0)
  446. return;
  447. buffer = (unsigned char *) smb_buf;
  448. for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
  449. if (i % 8 == 0) { /* we have reached the beginning of line */
  450. printk(KERN_DEBUG "| ");
  451. j = 0;
  452. }
  453. printk("%0#4x ", buffer[i]);
  454. debug_line[2 * j] = ' ';
  455. if (isprint(buffer[i]))
  456. debug_line[1 + (2 * j)] = buffer[i];
  457. else
  458. debug_line[1 + (2 * j)] = '_';
  459. if (i % 8 == 7) { /* we have reached end of line, time to print ascii */
  460. debug_line[16] = 0;
  461. printk(" | %s\n", debug_line);
  462. }
  463. }
  464. for (; j < 8; j++) {
  465. printk(" ");
  466. debug_line[2 * j] = ' ';
  467. debug_line[1 + (2 * j)] = ' ';
  468. }
  469. printk( " | %s\n", debug_line);
  470. return;
  471. }