diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/cifs |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/cifs')
42 files changed, 24587 insertions, 0 deletions
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS new file mode 100644 index 000000000000..acce36e25d2e --- /dev/null +++ b/fs/cifs/AUTHORS | |||
@@ -0,0 +1,42 @@ | |||
1 | Original Author | ||
2 | =============== | ||
3 | Steve French (sfrench@samba.org) | ||
4 | |||
5 | The author wishes to express his appreciation and thanks to: | ||
6 | Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS | ||
7 | improvements. Thanks to IBM for allowing me the time and test resources to pursue | ||
8 | this project. Jim McDonough from IBM (and the Samba Team) for his help. | ||
9 | The IBM Linux JFS team for explaining many esoteric Linux filesystem features. | ||
10 | Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client) | ||
11 | for proving years ago that a very good smb/cifs client could be done on a Unix like | ||
12 | operating system. Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin | ||
13 | and others for their work on the Linux smbfs module over the years. Thanks to | ||
14 | the other members of the Storage Network Industry Association CIFS Technical | ||
15 | Workgroup for their work specifying this highly complex protocol and finally | ||
16 | thanks to the Samba team for their technical advice and encouragement. | ||
17 | |||
18 | Patch Contributors | ||
19 | ------------------ | ||
20 | Zwane Mwaikambo | ||
21 | Andi Kleen | ||
22 | Amrut Joshi | ||
23 | Shobhit Dayal | ||
24 | Sergey Vlasov | ||
25 | Richard Hughes | ||
26 | Yury Umanets | ||
27 | Mark Hamzy | ||
28 | Domen Puncer | ||
29 | Jesper Juhl | ||
30 | |||
31 | Test case and Bug Report contributors | ||
32 | ------------------------------------- | ||
33 | Thanks to those in the community who have submitted detailed bug reports | ||
34 | and debug of problems they have found: Jochen Dolze, David Blaine, | ||
35 | Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori, | ||
36 | Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen, | ||
37 | Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special | ||
38 | mention to the Stanford Checker (SWAT) which pointed out many minor | ||
39 | bugs in error paths. | ||
40 | |||
41 | And thanks to the IBM LTC and Power test teams and SuSE testers for | ||
42 | finding multiple bugs during excellent stress test runs. | ||
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES new file mode 100644 index 000000000000..5316c8dd6bff --- /dev/null +++ b/fs/cifs/CHANGES | |||
@@ -0,0 +1,671 @@ | |||
1 | Version 1.31 | ||
2 | ------------ | ||
3 | Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one | ||
4 | transact response for an SMB request and search entry split across two frames. | ||
5 | Fix updates of DOS attributes and time fields so that files on NT4 servers | ||
6 | do not get marked delete on close. Display sizes of cifs buffer pools in | ||
7 | cifs stats. Fix oops in unmount when cifsd thread being killed by | ||
8 | shutdown. Add generic readv/writev and aio support. Report inode numbers | ||
9 | consistently in readdir and lookup (when serverino mount option is | ||
10 | specified use the inode number that the server reports - for both lookup | ||
11 | and readdir, otherwise by default the locally generated inode number is used | ||
12 | for inodes created in either path since servers are not always able to | ||
13 | provide unique inode numbers when exporting multiple volumes from under one | ||
14 | sharename). | ||
15 | |||
16 | Version 1.30 | ||
17 | ------------ | ||
18 | Allow new nouser_xattr mount parm to disable xattr support for user namespace. | ||
19 | Do not flag user_xattr mount parm in dmesg. Retry failures setting file time | ||
20 | (mostly affects NT4 servers) by retry with handle based network operation. | ||
21 | Add new POSIX Query FS Info for returning statfs info more accurately. | ||
22 | Handle passwords with multiple commas in them. | ||
23 | |||
24 | Version 1.29 | ||
25 | ------------ | ||
26 | Fix default mode in sysfs of cifs module parms. Remove old readdir routine. | ||
27 | Fix capabilities flags for large readx so as to allow reads larger than 64K. | ||
28 | |||
29 | Version 1.28 | ||
30 | ------------ | ||
31 | Add module init parm for large SMB buffer size (to allow it to be changed | ||
32 | from its default of 16K) which is especially useful for large file copy | ||
33 | when mounting with the directio mount option. Fix oops after | ||
34 | returning from mount when experimental ExtendedSecurity enabled and | ||
35 | SpnegoNegotiated returning invalid error. Fix case to retry better when | ||
36 | peek returns from 1 to 3 bytes on socket which should have more data. | ||
37 | Fixed path based calls (such as cifs lookup) to handle path names | ||
38 | longer than 530 (now can handle PATH_MAX). Fix pass through authentication | ||
39 | from Samba server to DC (Samba required dummy LM password). | ||
40 | |||
41 | Version 1.27 | ||
42 | ------------ | ||
43 | Turn off DNOTIFY (directory change notification support) by default | ||
44 | (unless built with the experimental flag) to fix hang with KDE | ||
45 | file browser. Fix DNOTIFY flag mappings. Fix hang (in wait_event | ||
46 | waiting on an SMB response) in SendReceive when session dies but | ||
47 | reconnects quickly from another task. Add module init parms for | ||
48 | minimum number of large and small network buffers in the buffer pools, | ||
49 | and for the maximum number of simultaneous requests. | ||
50 | |||
51 | Version 1.26 | ||
52 | ------------ | ||
53 | Add setfacl support to allow setting of ACLs remotely to Samba 3.10 and later | ||
54 | and other POSIX CIFS compliant servers. Fix error mapping for getfacl | ||
55 | to EOPNOTSUPP when server does not support posix acls on the wire. Fix | ||
56 | improperly zeroed buffer in CIFS Unix extensions set times call. | ||
57 | |||
58 | Version 1.25 | ||
59 | ------------ | ||
60 | Fix internationlization problem in cifs readdir with filenames that map to | ||
61 | longer UTF8 strings than the string on the wire was in Unicode. Add workaround | ||
62 | for readdir to netapp servers. Fix search rewind (seek into readdir to return | ||
63 | non-consecutive entries). Do not do readdir when server negotiates | ||
64 | buffer size to small to fit filename. Add support for reading POSIX ACLs from | ||
65 | the server (add also acl and noacl mount options). | ||
66 | |||
67 | Version 1.24 | ||
68 | ------------ | ||
69 | Optionally allow using server side inode numbers, rather than client generated | ||
70 | ones by specifying mount option "serverino" - this is required for some apps | ||
71 | to work which double check hardlinked files and have persistent inode numbers. | ||
72 | |||
73 | Version 1.23 | ||
74 | ------------ | ||
75 | Multiple bigendian fixes. On little endian systems (for reconnect after | ||
76 | network failure) fix tcp session reconnect code so we do not try first | ||
77 | to reconnect on reverse of port 445. Treat reparse points (NTFS junctions) | ||
78 | as directories rather than symlinks because we can do follow link on them. | ||
79 | |||
80 | Version 1.22 | ||
81 | ------------ | ||
82 | Add config option to enable XATTR (extended attribute) support, mapping | ||
83 | xattr names in the "user." namespace space to SMB/CIFS EAs. Lots of | ||
84 | minor fixes pointed out by the Stanford SWAT checker (mostly missing | ||
85 | or out of order NULL pointer checks in little used error paths). | ||
86 | |||
87 | Version 1.21 | ||
88 | ------------ | ||
89 | Add new mount parm to control whether mode check (generic_permission) is done | ||
90 | on the client. If Unix extensions are enabled and the uids on the client | ||
91 | and server do not match, client permission checks are meaningless on | ||
92 | server uids that do not exist on the client (this does not affect the | ||
93 | normal ACL check which occurs on the server). Fix default uid | ||
94 | on mknod to match create and mkdir. Add optional mount parm to allow | ||
95 | override of the default uid behavior (in which the server sets the uid | ||
96 | and gid of newly created files). Normally for network filesystem mounts | ||
97 | user want the server to set the uid/gid on newly created files (rather than | ||
98 | using uid of the client processes you would in a local filesystem). | ||
99 | |||
100 | Version 1.20 | ||
101 | ------------ | ||
102 | Make transaction counts more consistent. Merge /proc/fs/cifs/SimultaneousOps | ||
103 | info into /proc/fs/cifs/DebugData. Fix oops in rare oops in readdir | ||
104 | (in build_wildcard_path_from_dentry). Fix mknod to pass type field | ||
105 | (block/char/fifo) properly. Remove spurious mount warning log entry when | ||
106 | credentials passed as mount argument. Set major/minor device number in | ||
107 | inode for block and char devices when unix extensions enabled. | ||
108 | |||
109 | Version 1.19 | ||
110 | ------------ | ||
111 | Fix /proc/fs/cifs/Stats and DebugData display to handle larger | ||
112 | amounts of return data. Properly limit requests to MAX_REQ (50 | ||
113 | is the usual maximum active multiplex SMB/CIFS requests per server). | ||
114 | Do not kill cifsd (and thus hurt the other SMB session) when more than one | ||
115 | session to the same server (but with different userids) exists and one | ||
116 | of the two user's smb sessions is being removed while leaving the other. | ||
117 | Do not loop reconnecting in cifsd demultiplex thread when admin | ||
118 | kills the thread without going through unmount. | ||
119 | |||
120 | Version 1.18 | ||
121 | ------------ | ||
122 | Do not rename hardlinked files (since that should be a noop). Flush | ||
123 | cached write behind data when reopening a file after session abend, | ||
124 | except when already in write. Grab per socket sem during reconnect | ||
125 | to avoid oops in sendmsg if overlapping with reconnect. Do not | ||
126 | reset cached inode file size on readdir for files open for write on | ||
127 | client. | ||
128 | |||
129 | |||
130 | Version 1.17 | ||
131 | ------------ | ||
132 | Update number of blocks in file so du command is happier (in Linux a fake | ||
133 | blocksize of 512 is required for calculating number of blocks in inode). | ||
134 | Fix prepare write of partial pages to read in data from server if possible. | ||
135 | Fix race on tcpStatus field between unmount and reconnection code, causing | ||
136 | cifsd process sometimes to hang around forever. Improve out of memory | ||
137 | checks in cifs_filldir | ||
138 | |||
139 | Version 1.16 | ||
140 | ------------ | ||
141 | Fix incorrect file size in file handle based setattr on big endian hardware. | ||
142 | Fix oops in build_path_from_dentry when out of memory. Add checks for invalid | ||
143 | and closing file structs in writepage/partialpagewrite. Add statistics | ||
144 | for each mounted share (new menuconfig option). Fix endianness problem in | ||
145 | volume information displayed in /proc/fs/cifs/DebugData (only affects | ||
146 | affects big endian architectures). Prevent renames while constructing | ||
147 | path names for open, mkdir and rmdir. | ||
148 | |||
149 | Version 1.15 | ||
150 | ------------ | ||
151 | Change to mempools for alloc smb request buffers and multiplex structs | ||
152 | to better handle low memory problems (and potential deadlocks). | ||
153 | |||
154 | Version 1.14 | ||
155 | ------------ | ||
156 | Fix incomplete listings of large directories on Samba servers when Unix | ||
157 | extensions enabled. Fix oops when smb_buffer can not be allocated. Fix | ||
158 | rename deadlock when writing out dirty pages at same time. | ||
159 | |||
160 | Version 1.13 | ||
161 | ------------ | ||
162 | Fix open of files in which O_CREATE can cause the mode to change in | ||
163 | some cases. Fix case in which retry of write overlaps file close. | ||
164 | Fix PPC64 build error. Reduce excessive stack usage in smb password | ||
165 | hashing. Fix overwrite of Linux user's view of file mode to Windows servers. | ||
166 | |||
167 | Version 1.12 | ||
168 | ------------ | ||
169 | Fixes for large file copy, signal handling, socket retry, buffer | ||
170 | allocation and low memory situations. | ||
171 | |||
172 | Version 1.11 | ||
173 | ------------ | ||
174 | Better port 139 support to Windows servers (RFC1001/RFC1002 Session_Initialize) | ||
175 | also now allowing support for specifying client netbiosname. NT4 support added. | ||
176 | |||
177 | Version 1.10 | ||
178 | ------------ | ||
179 | Fix reconnection (and certain failed mounts) to properly wake up the | ||
180 | blocked users thread so it does not seem hung (in some cases was blocked | ||
181 | until the cifs receive timeout expired). Fix spurious error logging | ||
182 | to kernel log when application with open network files killed. | ||
183 | |||
184 | Version 1.09 | ||
185 | ------------ | ||
186 | Fix /proc/fs module unload warning message (that could be logged | ||
187 | to the kernel log). Fix intermittent failure in connectathon | ||
188 | test7 (hardlink count not immediately refreshed in case in which | ||
189 | inode metadata can be incorrectly kept cached when time near zero) | ||
190 | |||
191 | Version 1.08 | ||
192 | ------------ | ||
193 | Allow file_mode and dir_mode (specified at mount time) to be enforced | ||
194 | locally (the server already enforced its own ACLs too) for servers | ||
195 | that do not report the correct mode (do not support the | ||
196 | CIFS Unix Extensions). | ||
197 | |||
198 | Version 1.07 | ||
199 | ------------ | ||
200 | Fix some small memory leaks in some unmount error paths. Fix major leak | ||
201 | of cache pages in readpages causing multiple read oriented stress | ||
202 | testcases (including fsx, and even large file copy) to fail over time. | ||
203 | |||
204 | Version 1.06 | ||
205 | ------------ | ||
206 | Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated with server. | ||
207 | This allows files that differ only in case and improves performance of file | ||
208 | creation and file open to such servers. Fix semaphore conflict which causes | ||
209 | slow delete of open file to Samba (which unfortunately can cause an oplock | ||
210 | break to self while vfs_unlink held i_sem) which can hang for 20 seconds. | ||
211 | |||
212 | Version 1.05 | ||
213 | ------------ | ||
214 | fixes to cifs_readpages for fsx test case | ||
215 | |||
216 | Version 1.04 | ||
217 | ------------ | ||
218 | Fix caching data integrity bug when extending file size especially when no | ||
219 | oplock on file. Fix spurious logging of valid already parsed mount options | ||
220 | that are parsed outside of the cifs vfs such as nosuid. | ||
221 | |||
222 | |||
223 | Version 1.03 | ||
224 | ------------ | ||
225 | Connect to server when port number override not specified, and tcp port | ||
226 | unitialized. Reset search to restart at correct file when kernel routine | ||
227 | filldir returns error during large directory searches (readdir). | ||
228 | |||
229 | Version 1.02 | ||
230 | ------------ | ||
231 | Fix caching problem when files opened by multiple clients in which | ||
232 | page cache could contain stale data, and write through did | ||
233 | not occur often enough while file was still open when read ahead | ||
234 | (read oplock) not allowed. Treat "sep=" when first mount option | ||
235 | as an overrride of comma as the default separator between mount | ||
236 | options. | ||
237 | |||
238 | Version 1.01 | ||
239 | ------------ | ||
240 | Allow passwords longer than 16 bytes. Allow null password string. | ||
241 | |||
242 | Version 1.00 | ||
243 | ------------ | ||
244 | Gracefully clean up failed mounts when attempting to mount to servers such as | ||
245 | Windows 98 that terminate tcp sessions during prototocol negotiation. Handle | ||
246 | embedded commas in mount parsing of passwords. | ||
247 | |||
248 | Version 0.99 | ||
249 | ------------ | ||
250 | Invalidate local inode cached pages on oplock break and when last file | ||
251 | instance is closed so that the client does not continue using stale local | ||
252 | copy rather than later modified server copy of file. Do not reconnect | ||
253 | when server drops the tcp session prematurely before negotiate | ||
254 | protocol response. Fix oops in roepen_file when dentry freed. Allow | ||
255 | the support for CIFS Unix Extensions to be disabled via proc interface. | ||
256 | |||
257 | Version 0.98 | ||
258 | ------------ | ||
259 | Fix hang in commit_write during reconnection of open files under heavy load. | ||
260 | Fix unload_nls oops in a mount failure path. Serialize writes to same socket | ||
261 | which also fixes any possible races when cifs signatures are enabled in SMBs | ||
262 | being sent out of signature sequence number order. | ||
263 | |||
264 | Version 0.97 | ||
265 | ------------ | ||
266 | Fix byte range locking bug (endian problem) causing bad offset and | ||
267 | length. | ||
268 | |||
269 | Version 0.96 | ||
270 | ------------ | ||
271 | Fix oops (in send_sig) caused by CIFS unmount code trying to | ||
272 | wake up the demultiplex thread after it had exited. Do not log | ||
273 | error on harmless oplock release of closed handle. | ||
274 | |||
275 | Version 0.95 | ||
276 | ------------ | ||
277 | Fix unsafe global variable usage and password hash failure on gcc 3.3.1 | ||
278 | Fix problem reconnecting secondary mounts to same server after session | ||
279 | failure. Fix invalid dentry - race in mkdir when directory gets created | ||
280 | by another client between the lookup and mkdir. | ||
281 | |||
282 | Version 0.94 | ||
283 | ------------ | ||
284 | Fix to list processing in reopen_files. Fix reconnection when server hung | ||
285 | but tcpip session still alive. Set proper timeout on socket read. | ||
286 | |||
287 | Version 0.93 | ||
288 | ------------ | ||
289 | Add missing mount options including iocharset. SMP fixes in write and open. | ||
290 | Fix errors in reconnecting after TCP session failure. Fix module unloading | ||
291 | of default nls codepage | ||
292 | |||
293 | Version 0.92 | ||
294 | ------------ | ||
295 | Active smb transactions should never go negative (fix double FreeXid). Fix | ||
296 | list processing in file routines. Check return code on kmalloc in open. | ||
297 | Fix spinlock usage for SMP. | ||
298 | |||
299 | Version 0.91 | ||
300 | ------------ | ||
301 | Fix oops in reopen_files when invalid dentry. drop dentry on server rename | ||
302 | and on revalidate errors. Fix cases where pid is now tgid. Fix return code | ||
303 | on create hard link when server does not support them. | ||
304 | |||
305 | Version 0.90 | ||
306 | ------------ | ||
307 | Fix scheduling while atomic error in getting inode info on newly created file. | ||
308 | Fix truncate of existing files opened with O_CREAT but not O_TRUNC set. | ||
309 | |||
310 | Version 0.89 | ||
311 | ------------ | ||
312 | Fix oops on write to dead tcp session. Remove error log write for case when file open | ||
313 | O_CREAT but not O_EXCL | ||
314 | |||
315 | Version 0.88 | ||
316 | ------------ | ||
317 | Fix non-POSIX behavior on rename of open file and delete of open file by taking | ||
318 | advantage of trans2 SetFileInfo rename facility if available on target server. | ||
319 | Retry on ENOSPC and EAGAIN socket errors. | ||
320 | |||
321 | Version 0.87 | ||
322 | ------------ | ||
323 | Fix oops on big endian readdir. Set blksize to be even power of two (2**blkbits) to fix | ||
324 | allocation size miscalculation. After oplock token lost do not read through | ||
325 | cache. | ||
326 | |||
327 | Version 0.86 | ||
328 | ------------ | ||
329 | Fix oops on empty file readahead. Fix for file size handling for locally cached files. | ||
330 | |||
331 | Version 0.85 | ||
332 | ------------ | ||
333 | Fix oops in mkdir when server fails to return inode info. Fix oops in reopen_files | ||
334 | during auto reconnection to server after server recovered from failure. | ||
335 | |||
336 | Version 0.84 | ||
337 | ------------ | ||
338 | Finish support for Linux 2.5 open/create changes, which removes the | ||
339 | redundant NTCreate/QPathInfo/close that was sent during file create. | ||
340 | Enable oplock by default. Enable packet signing by default (needed to | ||
341 | access many recent Windows servers) | ||
342 | |||
343 | Version 0.83 | ||
344 | ------------ | ||
345 | Fix oops when mounting to long server names caused by inverted parms to kmalloc. | ||
346 | Fix MultiuserMount (/proc/fs/cifs configuration setting) so that when enabled | ||
347 | we will choose a cifs user session (smb uid) that better matches the local | ||
348 | uid if a) the mount uid does not match the current uid and b) we have another | ||
349 | session to the same server (ip address) for a different mount which | ||
350 | matches the current local uid. | ||
351 | |||
352 | Version 0.82 | ||
353 | ------------ | ||
354 | Add support for mknod of block or character devices. Fix oplock | ||
355 | code (distributed caching) to properly send response to oplock | ||
356 | break from server. | ||
357 | |||
358 | Version 0.81 | ||
359 | ------------ | ||
360 | Finish up CIFS packet digital signing for the default | ||
361 | NTLM security case. This should help Windows 2003 | ||
362 | network interoperability since it is common for | ||
363 | packet signing to be required now. Fix statfs (stat -f) | ||
364 | which recently started returning errors due to | ||
365 | invalid value (-1 instead of 0) being set in the | ||
366 | struct kstatfs f_ffiles field. | ||
367 | |||
368 | Version 0.80 | ||
369 | ----------- | ||
370 | Fix oops on stopping oplock thread when removing cifs when | ||
371 | built as module. | ||
372 | |||
373 | Version 0.79 | ||
374 | ------------ | ||
375 | Fix mount options for ro (readonly), uid, gid and file and directory mode. | ||
376 | |||
377 | Version 0.78 | ||
378 | ------------ | ||
379 | Fix errors displayed on failed mounts to be more understandable. | ||
380 | Fixed various incorrect or misleading smb to posix error code mappings. | ||
381 | |||
382 | Version 0.77 | ||
383 | ------------ | ||
384 | Fix display of NTFS DFS junctions to display as symlinks. | ||
385 | They are the network equivalent. Fix oops in | ||
386 | cifs_partialpagewrite caused by missing spinlock protection | ||
387 | of openfile linked list. Allow writebehind caching errors to | ||
388 | be returned to the application at file close. | ||
389 | |||
390 | Version 0.76 | ||
391 | ------------ | ||
392 | Clean up options displayed in /proc/mounts by show_options to | ||
393 | be more consistent with other filesystems. | ||
394 | |||
395 | Version 0.75 | ||
396 | ------------ | ||
397 | Fix delete of readonly file to Windows servers. Reflect | ||
398 | presence or absence of read only dos attribute in mode | ||
399 | bits for servers that do not support CIFS Unix extensions. | ||
400 | Fix shortened results on readdir of large directories to | ||
401 | servers supporting CIFS Unix extensions (caused by | ||
402 | incorrect resume key). | ||
403 | |||
404 | Version 0.74 | ||
405 | ------------ | ||
406 | Fix truncate bug (set file size) that could cause hangs e.g. running fsx | ||
407 | |||
408 | Version 0.73 | ||
409 | ------------ | ||
410 | unload nls if mount fails. | ||
411 | |||
412 | Version 0.72 | ||
413 | ------------ | ||
414 | Add resume key support to search (readdir) code to workaround | ||
415 | Windows bug. Add /proc/fs/cifs/LookupCacheEnable which | ||
416 | allows disabling caching of attribute information for | ||
417 | lookups. | ||
418 | |||
419 | Version 0.71 | ||
420 | ------------ | ||
421 | Add more oplock handling (distributed caching code). Remove | ||
422 | dead code. Remove excessive stack space utilization from | ||
423 | symlink routines. | ||
424 | |||
425 | Version 0.70 | ||
426 | ------------ | ||
427 | Fix oops in get dfs referral (triggered when null path sent in to | ||
428 | mount). Add support for overriding rsize at mount time. | ||
429 | |||
430 | Version 0.69 | ||
431 | ------------ | ||
432 | Fix buffer overrun in readdir which caused intermittent kernel oopses. | ||
433 | Fix writepage code to release kmap on write data. Allow "-ip=" new | ||
434 | mount option to be passed in on parameter distinct from the first part | ||
435 | (server name portion of) the UNC name. Allow override of the | ||
436 | tcp port of the target server via new mount option "-port=" | ||
437 | |||
438 | Version 0.68 | ||
439 | ------------ | ||
440 | Fix search handle leak on rewind. Fix setuid and gid so that they are | ||
441 | reflected in the local inode immediately. Cleanup of whitespace | ||
442 | to make 2.4 and 2.5 versions more consistent. | ||
443 | |||
444 | |||
445 | Version 0.67 | ||
446 | ------------ | ||
447 | Fix signal sending so that captive thread (cifsd) exits on umount | ||
448 | (which was causing the warning in kmem_cache_free of the request buffers | ||
449 | at rmmod time). This had broken as a sideeffect of the recent global | ||
450 | kernel change to daemonize. Fix memory leak in readdir code which | ||
451 | showed up in "ls -R" (and applications that did search rewinding). | ||
452 | |||
453 | Version 0.66 | ||
454 | ------------ | ||
455 | Reconnect tids and fids after session reconnection (still do not | ||
456 | reconnect byte range locks though). Fix problem caching | ||
457 | lookup information for directory inodes, improving performance, | ||
458 | especially in deep directory trees. Fix various build warnings. | ||
459 | |||
460 | Version 0.65 | ||
461 | ------------ | ||
462 | Finish fixes to commit write for caching/readahead consistency. fsx | ||
463 | now works to Samba servers. Fix oops caused when readahead | ||
464 | was interrupted by a signal. | ||
465 | |||
466 | Version 0.64 | ||
467 | ------------ | ||
468 | Fix data corruption (in partial page after truncate) that caused fsx to | ||
469 | fail to Windows servers. Cleaned up some extraneous error logging in | ||
470 | common error paths. Add generic sendfile support. | ||
471 | |||
472 | Version 0.63 | ||
473 | ------------ | ||
474 | Fix memory leak in AllocMidQEntry. | ||
475 | Finish reconnection logic, so connection with server can be dropped | ||
476 | (or server rebooted) and the cifs client will reconnect. | ||
477 | |||
478 | Version 0.62 | ||
479 | ------------ | ||
480 | Fix temporary socket leak when bad userid or password specified | ||
481 | (or other SMBSessSetup failure). Increase maximum buffer size to slightly | ||
482 | over 16K to allow negotiation of up to Samba and Windows server default read | ||
483 | sizes. Add support for readpages | ||
484 | |||
485 | Version 0.61 | ||
486 | ------------ | ||
487 | Fix oops when username not passed in on mount. Extensive fixes and improvements | ||
488 | to error logging (strip redundant newlines, change debug macros to ensure newline | ||
489 | passed in and to be more consistent). Fix writepage wrong file handle problem, | ||
490 | a readonly file handle could be incorrectly used to attempt to write out | ||
491 | file updates through the page cache to multiply open files. This could cause | ||
492 | the iozone benchmark to fail on the fwrite test. Fix bug mounting two different | ||
493 | shares to the same Windows server when using different usernames | ||
494 | (doing this to Samba servers worked but Windows was rejecting it) - now it is | ||
495 | possible to use different userids when connecting to the same server from a | ||
496 | Linux client. Fix oops when treeDisconnect called during unmount on | ||
497 | previously freed socket. | ||
498 | |||
499 | Version 0.60 | ||
500 | ------------ | ||
501 | Fix oops in readpages caused by not setting address space operations in inode in | ||
502 | rare code path. | ||
503 | |||
504 | Version 0.59 | ||
505 | ------------ | ||
506 | Includes support for deleting of open files and renaming over existing files (per POSIX | ||
507 | requirement). Add readlink support for Windows junction points (directory symlinks). | ||
508 | |||
509 | Version 0.58 | ||
510 | ------------ | ||
511 | Changed read and write to go through pagecache. Added additional address space operations. | ||
512 | Memory mapped operations now working. | ||
513 | |||
514 | Version 0.57 | ||
515 | ------------ | ||
516 | Added writepage code for additional memory mapping support. Fixed leak in xids causing | ||
517 | the simultaneous operations counter (/proc/fs/cifs/SimultaneousOps) to increase on | ||
518 | every stat call. Additional formatting cleanup. | ||
519 | |||
520 | Version 0.56 | ||
521 | ------------ | ||
522 | Fix bigendian bug in order of time conversion. Merge 2.5 to 2.4 version. Formatting cleanup. | ||
523 | |||
524 | Version 0.55 | ||
525 | ------------ | ||
526 | Fixes from Zwane Mwaikambo for adding missing return code checking in a few places. | ||
527 | Also included a modified version of his fix to protect global list manipulation of | ||
528 | the smb session and tree connection and mid related global variables. | ||
529 | |||
530 | Version 0.54 | ||
531 | ------------ | ||
532 | Fix problem with captive thread hanging around at unmount time. Adjust to 2.5.42-pre | ||
533 | changes to superblock layout. Remove wasteful allocation of smb buffers (now the send | ||
534 | buffer is reused for responses). Add more oplock handling. Additional minor cleanup. | ||
535 | |||
536 | Version 0.53 | ||
537 | ------------ | ||
538 | More stylistic updates to better match kernel style. Add additional statistics | ||
539 | for filesystem which can be viewed via /proc/fs/cifs. Add more pieces of NTLMv2 | ||
540 | and CIFS Packet Signing enablement. | ||
541 | |||
542 | Version 0.52 | ||
543 | ------------ | ||
544 | Replace call to sleep_on with safer wait_on_event. | ||
545 | Make stylistic changes to better match kernel style recommendations. | ||
546 | Remove most typedef usage (except for the PDUs themselves). | ||
547 | |||
548 | Version 0.51 | ||
549 | ------------ | ||
550 | Update mount so the -unc mount option is no longer required (the ip address can be specified | ||
551 | in a UNC style device name. Implementation of readpage/writepage started. | ||
552 | |||
553 | Version 0.50 | ||
554 | ------------ | ||
555 | Fix intermittent problem with incorrect smb header checking on badly | ||
556 | fragmented tcp responses | ||
557 | |||
558 | Version 0.49 | ||
559 | ------------ | ||
560 | Fixes to setting of allocation size and file size. | ||
561 | |||
562 | Version 0.48 | ||
563 | ------------ | ||
564 | Various 2.5.38 fixes. Now works on 2.5.38 | ||
565 | |||
566 | Version 0.47 | ||
567 | ------------ | ||
568 | Prepare for 2.5 kernel merge. Remove ifdefs. | ||
569 | |||
570 | Version 0.46 | ||
571 | ------------ | ||
572 | Socket buffer management fixes. Fix dual free. | ||
573 | |||
574 | Version 0.45 | ||
575 | ------------ | ||
576 | Various big endian fixes for hardlinks and symlinks and also for dfs. | ||
577 | |||
578 | Version 0.44 | ||
579 | ------------ | ||
580 | Various big endian fixes for servers with Unix extensions such as Samba | ||
581 | |||
582 | Version 0.43 | ||
583 | ------------ | ||
584 | Various FindNext fixes for incorrect filenames on large directory searches on big endian | ||
585 | clients. basic posix file i/o tests now work on big endian machines, not just le | ||
586 | |||
587 | Version 0.42 | ||
588 | ------------ | ||
589 | SessionSetup and NegotiateProtocol now work from Big Endian machines. | ||
590 | Various Big Endian fixes found during testing on the Linux on 390. Various fixes for compatibility with older | ||
591 | versions of 2.4 kernel (now builds and works again on kernels at least as early as 2.4.7). | ||
592 | |||
593 | Version 0.41 | ||
594 | ------------ | ||
595 | Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked | ||
596 | files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked. | ||
597 | |||
598 | Version 0.40 | ||
599 | ------------ | ||
600 | Implemented "Raw" (i.e. not encapsulated in SPNEGO) NTLMSSP (i.e. the Security Provider Interface used to negotiate | ||
601 | session advanced session authentication). Raw NTLMSSP is preferred by Windows 2000 Professional and Windows XP. | ||
602 | Began implementing support for SPNEGO encapsulation of NTLMSSP based session authentication blobs | ||
603 | (which is the mechanism preferred by Windows 2000 server in the absence of Kerberos). | ||
604 | |||
605 | Version 0.38 | ||
606 | ------------ | ||
607 | Introduced optional mount helper utility mount.cifs and made coreq changes to cifs vfs to enable | ||
608 | it. Fixed a few bugs in the DFS code (e.g. bcc two bytes too short and incorrect uid in PDU). | ||
609 | |||
610 | Version 0.37 | ||
611 | ------------ | ||
612 | Rewrote much of connection and mount/unmount logic to handle bugs with | ||
613 | multiple uses to same share, multiple users to same server etc. | ||
614 | |||
615 | Version 0.36 | ||
616 | ------------ | ||
617 | Fixed major problem with dentry corruption (missing call to dput) | ||
618 | |||
619 | Version 0.35 | ||
620 | ------------ | ||
621 | Rewrite of readdir code to fix bug. Various fixes for bigendian machines. | ||
622 | Begin adding oplock support. Multiusermount and oplockEnabled flags added to /proc/fs/cifs | ||
623 | although corresponding function not fully implemented in the vfs yet | ||
624 | |||
625 | Version 0.34 | ||
626 | ------------ | ||
627 | Fixed dentry caching bug, misc. cleanup | ||
628 | |||
629 | Version 0.33 | ||
630 | ------------ | ||
631 | Fixed 2.5 support to handle build and configure changes as well as misc. 2.5 changes. Now can build | ||
632 | on current 2.5 beta version (2.5.24) of the Linux kernel as well as on 2.4 Linux kernels. | ||
633 | Support for STATUS codes (newer 32 bit NT error codes) added. DFS support begun to be added. | ||
634 | |||
635 | Version 0.32 | ||
636 | ------------ | ||
637 | Unix extensions (symlink, readlink, hardlink, chmod and some chgrp and chown) implemented | ||
638 | and tested against Samba 2.2.5 | ||
639 | |||
640 | |||
641 | Version 0.31 | ||
642 | ------------ | ||
643 | 1) Fixed lockrange to be correct (it was one byte too short) | ||
644 | |||
645 | 2) Fixed GETLK (i.e. the fcntl call to test a range of bytes in a file to see if locked) to correctly | ||
646 | show range as locked when there is a conflict with an existing lock. | ||
647 | |||
648 | 3) default file perms are now 2767 (indicating support for mandatory locks) instead of 777 for directories | ||
649 | in most cases. Eventually will offer optional ability to query server for the correct perms. | ||
650 | |||
651 | 3) Fixed eventual trap when mounting twice to different shares on the same server when the first succeeded | ||
652 | but the second one was invalid and failed (the second one was incorrectly disconnecting the tcp and smb | ||
653 | session) | ||
654 | |||
655 | 4) Fixed error logging of valid mount options | ||
656 | |||
657 | 5) Removed logging of password field. | ||
658 | |||
659 | 6) Moved negotiate, treeDisconnect and uloggoffX (only tConx and SessSetup remain in connect.c) to cifssmb.c | ||
660 | and cleaned them up and made them more consistent with other cifs functions. | ||
661 | |||
662 | 7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways | ||
663 | (with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed, | ||
664 | nor is the symlink support using the Unix extensions | ||
665 | |||
666 | 8) Started adding the readlink and follow_link code | ||
667 | |||
668 | Version 0.3 | ||
669 | ----------- | ||
670 | Initial drop | ||
671 | |||
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile new file mode 100644 index 000000000000..7384947a0f93 --- /dev/null +++ b/fs/cifs/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for Linux CIFS VFS client | ||
3 | # | ||
4 | obj-$(CONFIG_CIFS) += cifs.o | ||
5 | |||
6 | cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o | ||
diff --git a/fs/cifs/README b/fs/cifs/README new file mode 100644 index 000000000000..0f20edc935b5 --- /dev/null +++ b/fs/cifs/README | |||
@@ -0,0 +1,475 @@ | |||
1 | The CIFS VFS support for Linux supports many advanced network filesystem | ||
2 | features such as heirarchical dfs like namespace, hardlinks, locking and more. | ||
3 | It was designed to comply with the SNIA CIFS Technical Reference (which | ||
4 | supersedes the 1992 X/Open SMB Standard) as well as to perform best practice | ||
5 | practical interoperability with Windows 2000, Windows XP, Samba and equivalent | ||
6 | servers. | ||
7 | |||
8 | For questions or bug reports please contact: | ||
9 | sfrench@samba.org (sfrench@us.ibm.com) | ||
10 | |||
11 | Build instructions: | ||
12 | ================== | ||
13 | For Linux 2.4: | ||
14 | 1) Get the kernel source (e.g.from http://www.kernel.org) | ||
15 | and download the cifs vfs source (see the project page | ||
16 | at http://us1.samba.org/samba/Linux_CIFS_client.html) | ||
17 | and change directory into the top of the kernel directory | ||
18 | then patch the kernel (e.g. "patch -p1 < cifs_24.patch") | ||
19 | to add the cifs vfs to your kernel configure options if | ||
20 | it has not already been added (e.g. current SuSE and UL | ||
21 | users do not need to apply the cifs_24.patch since the cifs vfs is | ||
22 | already in the kernel configure menu) and then | ||
23 | mkdir linux/fs/cifs and then copy the current cifs vfs files from | ||
24 | the cifs download to your kernel build directory e.g. | ||
25 | |||
26 | cp <cifs_download_dir>/fs/cifs/* to <kernel_download_dir>/fs/cifs | ||
27 | |||
28 | 2) make menuconfig (or make xconfig) | ||
29 | 3) select cifs from within the network filesystem choices | ||
30 | 4) save and exit | ||
31 | 5) make dep | ||
32 | 6) make modules (or "make" if CIFS VFS not to be built as a module) | ||
33 | |||
34 | For Linux 2.6: | ||
35 | 1) Download the kernel (e.g. from http://www.kernel.org or from bitkeeper | ||
36 | at bk://linux.bkbits.net/linux-2.5) and change directory into the top | ||
37 | of the kernel directory tree (e.g. /usr/src/linux-2.5.73) | ||
38 | 2) make menuconfig (or make xconfig) | ||
39 | 3) select cifs from within the network filesystem choices | ||
40 | 4) save and exit | ||
41 | 5) make | ||
42 | |||
43 | |||
44 | Installation instructions: | ||
45 | ========================= | ||
46 | If you have built the CIFS vfs as module (successfully) simply | ||
47 | type "make modules_install" (or if you prefer, manually copy the file to | ||
48 | the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o). | ||
49 | |||
50 | If you have built the CIFS vfs into the kernel itself, follow the instructions | ||
51 | for your distribution on how to install a new kernel (usually you | ||
52 | would simply type "make install"). | ||
53 | |||
54 | If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on | ||
55 | the CIFS VFS web site) copy it to the same directory in which mount.smbfs and | ||
56 | similar files reside (usually /sbin). Although the helper software is not | ||
57 | required, mount.cifs is recommended. Eventually the Samba 3.0 utility program | ||
58 | "net" may also be helpful since it may someday provide easier mount syntax for | ||
59 | users who are used to Windows e.g. net use <mount point> <UNC name or cifs URL> | ||
60 | Note that running the Winbind pam/nss module (logon service) on all of your | ||
61 | Linux clients is useful in mapping Uids and Gids consistently across the | ||
62 | domain to the proper network user. The mount.cifs mount helper can be | ||
63 | trivially built from Samba 3.0 or later source e.g. by executing: | ||
64 | |||
65 | gcc samba/source/client/mount.cifs.c -o mount.cifs | ||
66 | |||
67 | If cifs is built as a module, then the size and number of network buffers | ||
68 | and maximum number of simultaneous requests to one server can be configured. | ||
69 | Changing these from their defaults is not recommended. By executing modinfo | ||
70 | modinfo kernel/fs/cifs/cifs.ko | ||
71 | on kernel/fs/cifs/cifs.ko the list of configuration changes that can be made | ||
72 | at module initialization time (by running insmod cifs.ko) can be seen. | ||
73 | |||
74 | Allowing User Mounts | ||
75 | ==================== | ||
76 | To permit users to mount and unmount over directories they own is possible | ||
77 | with the cifs vfs. A way to enable such mounting is to mark the mount.cifs | ||
78 | utility as suid (e.g. "chmod +s /sbin/mount/cifs). To enable users to | ||
79 | umount shares they mount requires | ||
80 | 1) mount.cifs version 1.4 or later | ||
81 | 2) an entry for the share in /etc/fstab indicating that a user may | ||
82 | unmount it e.g. | ||
83 | //server/usersharename /mnt/username cifs user 0 0 | ||
84 | |||
85 | Note that when the mount.cifs utility is run suid (allowing user mounts), | ||
86 | in order to reduce risks, the "nosuid" mount flag is passed in on mount to | ||
87 | disallow execution of an suid program mounted on the remote target. | ||
88 | When mount is executed as root, nosuid is not passed in by default, | ||
89 | and execution of suid programs on the remote target would be enabled | ||
90 | by default. This can be changed, as with nfs and other filesystems, | ||
91 | by simply specifying "nosuid" among the mount options. For user mounts | ||
92 | though to be able to pass the suid flag to mount requires rebuilding | ||
93 | mount.cifs with the following flag: | ||
94 | |||
95 | gcc samba/source/client/mount.cifs.c -DCIFS_ALLOW_USR_SUID -o mount.cifs | ||
96 | |||
97 | There is a corresponding manual page for cifs mounting in the Samba 3.0 and | ||
98 | later source tree in docs/manpages/mount.cifs.8 | ||
99 | |||
100 | Samba Considerations | ||
101 | ==================== | ||
102 | To get the maximum benefit from the CIFS VFS, we recommend using a server that | ||
103 | supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or | ||
104 | Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. | ||
105 | Note that uid, gid and file permissions will display default values if you do | ||
106 | not have a server that supports the Unix extensions for CIFS (such as Samba | ||
107 | 2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add | ||
108 | the line: | ||
109 | |||
110 | unix extensions = yes | ||
111 | |||
112 | to your smb.conf file on the server. Note that the following smb.conf settings | ||
113 | are also useful (on the Samba server) when the majority of clients are Unix or | ||
114 | Linux: | ||
115 | |||
116 | case sensitive = yes | ||
117 | delete readonly = yes | ||
118 | ea support = yes | ||
119 | |||
120 | Note that server ea support is required for supporting xattrs from the Linux | ||
121 | cifs client, and that EA support is present in later versions of Samba (e.g. | ||
122 | 3.0.6 and later (also EA support works in all versions of Windows, at least to | ||
123 | shares on NTFS filesystems). Extended Attribute (xattr) support is an optional | ||
124 | feature of most Linux filesystems which may require enabling via | ||
125 | make menuconfig. Client support for extended attributes (user xattr) can be | ||
126 | disabled on a per-mount basis by specifying "nouser_xattr" on mount. | ||
127 | |||
128 | The CIFS client can get and set POSIX ACLs (getfacl, setfacl) to Samba servers | ||
129 | version 3.10 and later. Setting POSIX ACLs requires enabling both XATTR and | ||
130 | then POSIX support in the CIFS configuration options when building the cifs | ||
131 | module. POSIX ACL support can be disabled on a per mount basic by specifying | ||
132 | "noacl" on mount. | ||
133 | |||
134 | Some administrators may want to change Samba's smb.conf "map archive" and | ||
135 | "create mask" parameters from the default. Unless the create mask is changed | ||
136 | newly created files can end up with an unnecessarily restrictive default mode, | ||
137 | which may not be what you want, although if the CIFS Unix extensions are | ||
138 | enabled on the server and client, subsequent setattr calls (e.g. chmod) can | ||
139 | fix the mode. Note that creating special devices (mknod) remotely | ||
140 | may require specifying a mkdev function to Samba if you are not using | ||
141 | Samba 3.0.6 or later. For more information on these see the manual pages | ||
142 | ("man smb.conf") on the Samba server system. Note that the cifs vfs, | ||
143 | unlike the smbfs vfs, does not read the smb.conf on the client system | ||
144 | (the few optional settings are passed in on mount via -o parameters instead). | ||
145 | Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete | ||
146 | open files (required for strict POSIX compliance). Windows Servers already | ||
147 | supported this feature. Samba server does not allow symlinks that refer to files | ||
148 | outside of the share, so in Samba versions prior to 3.0.6, most symlinks to | ||
149 | files with absolute paths (ie beginning with slash) such as: | ||
150 | ln -s /mnt/foo bar | ||
151 | would be forbidden. Samba 3.0.6 server or later includes the ability to create | ||
152 | such symlinks safely by converting unsafe symlinks (ie symlinks to server | ||
153 | files that are outside of the share) to a samba specific format on the server | ||
154 | that is ignored by local server applications and non-cifs clients and that will | ||
155 | not be traversed by the Samba server). This is opaque to the Linux client | ||
156 | application using the cifs vfs. Absolute symlinks will work to Samba 3.0.5 or | ||
157 | later, but only for remote clients using the CIFS Unix extensions, and will | ||
158 | be invisbile to Windows clients and typically will not affect local | ||
159 | applications running on the same server as Samba. | ||
160 | |||
161 | Use instructions: | ||
162 | ================ | ||
163 | Once the CIFS VFS support is built into the kernel or installed as a module | ||
164 | (cifs.o), you can use mount syntax like the following to access Samba or Windows | ||
165 | servers: | ||
166 | |||
167 | mount -t cifs //9.53.216.11/e$ /mnt -o user=myname,pass=mypassword | ||
168 | |||
169 | Before -o the option -v may be specified to make the mount.cifs | ||
170 | mount helper display the mount steps more verbosely. | ||
171 | After -o the following commonly used cifs vfs specific options | ||
172 | are supported: | ||
173 | |||
174 | user=<username> | ||
175 | pass=<password> | ||
176 | domain=<domain name> | ||
177 | |||
178 | Other cifs mount options are described below. Use of TCP names (in addition to | ||
179 | ip addresses) is available if the mount helper (mount.cifs) is installed. If | ||
180 | you do not trust the server to which are mounted, or if you do not have | ||
181 | cifs signing enabled (and the physical network is insecure), consider use | ||
182 | of the standard mount options "noexec" and "nosuid" to reduce the risk of | ||
183 | running an altered binary on your local system (downloaded from a hostile server | ||
184 | or altered by a hostile router). | ||
185 | |||
186 | Although mounting using format corresponding to the CIFS URL specification is | ||
187 | not possible in mount.cifs yet, it is possible to use an alternate format | ||
188 | for the server and sharename (which is somewhat similar to NFS style mount | ||
189 | syntax) instead of the more widely used UNC format (i.e. \\server\share): | ||
190 | mount -t cifs tcp_name_of_server:share_name /mnt -o user=myname,pass=mypasswd | ||
191 | |||
192 | When using the mount helper mount.cifs, passwords may be specified via alternate | ||
193 | mechanisms, instead of specifying it after -o using the normal "pass=" syntax | ||
194 | on the command line: | ||
195 | 1) By including it in a credential file. Specify credentials=filename as one | ||
196 | of the mount options. Credential files contain two lines | ||
197 | username=someuser | ||
198 | password=your_password | ||
199 | 2) By specifying the password in the PASSWD environment variable (similarly | ||
200 | the user name can be taken from the USER environment variable). | ||
201 | 3) By specifying the password in a file by name via PASSWD_FILE | ||
202 | 4) By specifying the password in a file by file descriptor via PASSWD_FD | ||
203 | |||
204 | If no password is provided, mount.cifs will prompt for password entry | ||
205 | |||
206 | Restrictions | ||
207 | ============ | ||
208 | Servers must support the NTLM SMB dialect (which is the most recent, supported | ||
209 | by Samba and Windows NT version 4, 2000 and XP and many other SMB/CIFS servers) | ||
210 | Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC | ||
211 | 1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a | ||
212 | problem as most servers support this. IPv6 support is planned for the future, | ||
213 | and is almost complete. | ||
214 | |||
215 | Valid filenames differ between Windows and Linux. Windows typically restricts | ||
216 | filenames which contain certain reserved characters (e.g.the character : | ||
217 | which is used to delimit the beginning of a stream name by Windows), while | ||
218 | Linux allows a slightly wider set of valid characters in filenames. Windows | ||
219 | servers can remap such characters when an explicit mapping is specified in | ||
220 | the Server's registry. Samba starting with version 3.10 will allow such | ||
221 | filenames (ie those which contain valid Linux characters, which normally | ||
222 | would be forbidden for Windows/CIFS semantics) as long as the server is | ||
223 | configured for Unix Extensions (and the client has not disabled | ||
224 | /proc/fs/cifs/LinuxExtensionsEnabled). | ||
225 | |||
226 | |||
227 | CIFS VFS Mount Options | ||
228 | ====================== | ||
229 | A partial list of the supported mount options follows: | ||
230 | user The user name to use when trying to establish | ||
231 | the CIFS session. | ||
232 | password The user password. If the mount helper is | ||
233 | installed, the user will be prompted for password | ||
234 | if it is not supplied. | ||
235 | ip The ip address of the target server | ||
236 | unc The target server Universal Network Name (export) to | ||
237 | mount. | ||
238 | domain Set the SMB/CIFS workgroup name prepended to the | ||
239 | username during CIFS session establishment | ||
240 | uid If CIFS Unix extensions are not supported by the server | ||
241 | this overrides the default uid for inodes. For mounts to | ||
242 | servers which do support the CIFS Unix extensions, such | ||
243 | as a properly configured Samba server, the server provides | ||
244 | the uid, gid and mode. For servers which do not support | ||
245 | the Unix extensions, the default uid (and gid) returned on | ||
246 | lookup of existing files is the uid (gid) of the person | ||
247 | who executed the mount (root, except when mount.cifs | ||
248 | is configured setuid for user mounts) unless the "uid=" | ||
249 | (gid) mount option is specified. For the uid (gid) of newly | ||
250 | created files and directories, ie files created since | ||
251 | the last mount of the server share, the expected uid | ||
252 | (gid) is cached as as long as the inode remains in | ||
253 | memory on the client. Also note that permission | ||
254 | checks (authorization checks) on accesses to a file occur | ||
255 | at the server, but there are cases in which an administrator | ||
256 | may want to restrict at the client as well. For those | ||
257 | servers which do not report a uid/gid owner | ||
258 | (such as Windows), permissions can also be checked at the | ||
259 | client, and a crude form of client side permission checking | ||
260 | can be enabled by specifying file_mode and dir_mode on | ||
261 | the client | ||
262 | gid If CIFS Unix extensions are not supported by the server | ||
263 | this overrides the default gid for inodes. | ||
264 | file_mode If CIFS Unix extensions are not supported by the server | ||
265 | this overrides the default mode for file inodes. | ||
266 | dir_mode If CIFS Unix extensions are not supported by the server | ||
267 | this overrides the default mode for directory inodes. | ||
268 | port attempt to contact the server on this tcp port, before | ||
269 | trying the usual ports (port 445, then 139). | ||
270 | iocharset Codepage used to convert local path names to and from | ||
271 | Unicode. Unicode is used by default for network path | ||
272 | names if the server supports it. If iocharset is | ||
273 | not specified then the nls_default specified | ||
274 | during the local client kernel build will be used. | ||
275 | If server does not support Unicode, this parameter is | ||
276 | unused. | ||
277 | rsize default read size | ||
278 | wsize default write size | ||
279 | rw mount the network share read-write (note that the | ||
280 | server may still consider the share read-only) | ||
281 | ro mount network share read-only | ||
282 | version used to distinguish different versions of the | ||
283 | mount helper utility (not typically needed) | ||
284 | sep if first mount option (after the -o), overrides | ||
285 | the comma as the separator between the mount | ||
286 | parms. e.g. | ||
287 | -o user=myname,password=mypassword,domain=mydom | ||
288 | could be passed instead with period as the separator by | ||
289 | -o sep=.user=myname.password=mypassword.domain=mydom | ||
290 | this might be useful when comma is contained within username | ||
291 | or password or domain. This option is less important | ||
292 | when the cifs mount helper cifs.mount (version 1.1 or later) | ||
293 | is used. | ||
294 | nosuid Do not allow remote executables with the suid bit | ||
295 | program to be executed. This is only meaningful for mounts | ||
296 | to servers such as Samba which support the CIFS Unix Extensions. | ||
297 | If you do not trust the servers in your network (your mount | ||
298 | targets) it is recommended that you specify this option for | ||
299 | greater security. | ||
300 | exec Permit execution of binaries on the mount. | ||
301 | noexec Do not permit execution of binaries on the mount. | ||
302 | dev Recognize block devices on the remote mount. | ||
303 | nodev Do not recognize devices on the remote mount. | ||
304 | suid Allow remote files on this mountpoint with suid enabled to | ||
305 | be executed (default for mounts when executed as root, | ||
306 | nosuid is default for user mounts). | ||
307 | credentials Although ignored by the cifs kernel component, it is used by | ||
308 | the mount helper, mount.cifs. When mount.cifs is installed it | ||
309 | opens and reads the credential file specified in order | ||
310 | to obtain the userid and password arguments which are passed to | ||
311 | the cifs vfs. | ||
312 | guest Although ignored by the kernel component, the mount.cifs | ||
313 | mount helper will not prompt the user for a password | ||
314 | if guest is specified on the mount options. If no | ||
315 | password is specified a null password will be used. | ||
316 | perm Client does permission checks (vfs_permission check of uid | ||
317 | and gid of the file against the mode and desired operation), | ||
318 | Note that this is in addition to the normal ACL check on the | ||
319 | target machine done by the server software. | ||
320 | Client permission checking is enabled by default. | ||
321 | noperm Client does not do permission checks. This can expose | ||
322 | files on this mount to access by other users on the local | ||
323 | client system. It is typically only needed when the server | ||
324 | supports the CIFS Unix Extensions but the UIDs/GIDs on the | ||
325 | client and server system do not match closely enough to allow | ||
326 | access by the user doing the mount. | ||
327 | Note that this does not affect the normal ACL check on the | ||
328 | target machine done by the server software (of the server | ||
329 | ACL against the user name provided at mount time). | ||
330 | serverino Use servers inode numbers instead of generating automatically | ||
331 | incrementing inode numbers on the client. Although this will | ||
332 | make it easier to spot hardlinked files (as they will have | ||
333 | the same inode numbers) and inode numbers may be persistent, | ||
334 | note that the server does not guarantee that the inode numbers | ||
335 | are unique if multiple server side mounts are exported under a | ||
336 | single share (since inode numbers on the servers might not | ||
337 | be unique if multiple filesystems are mounted under the same | ||
338 | shared higher level directory). Note that this requires that | ||
339 | the server support the CIFS Unix Extensions as other servers | ||
340 | do not return a unique IndexNumber on SMB FindFirst (most | ||
341 | servers return zero as the IndexNumber). Parameter has no | ||
342 | effect to Windows servers and others which do not support the | ||
343 | CIFS Unix Extensions. | ||
344 | noserverino Client generates inode numbers (rather than using the actual one | ||
345 | from the server) by default. | ||
346 | setuids If the CIFS Unix extensions are negotiated with the server | ||
347 | the client will attempt to set the effective uid and gid of | ||
348 | the local process on newly created files, directories, and | ||
349 | devices (create, mkdir, mknod). | ||
350 | nosetuids The client will not attempt to set the uid and gid on | ||
351 | on newly created files, directories, and devices (create, | ||
352 | mkdir, mknod) which will result in the server setting the | ||
353 | uid and gid to the default (usually the server uid of the | ||
354 | usern who mounted the share). Letting the server (rather than | ||
355 | the client) set the uid and gid is the default. This | ||
356 | parameter has no effect if the CIFS Unix Extensions are not | ||
357 | negotiated. | ||
358 | netbiosname When mounting to servers via port 139, specifies the RFC1001 | ||
359 | source name to use to represent the client netbios machine | ||
360 | name when doing the RFC1001 netbios session initialize. | ||
361 | direct Do not do inode data caching on files opened on this mount. | ||
362 | This precludes mmaping files on this mount. In some cases | ||
363 | with fast networks and little or no caching benefits on the | ||
364 | client (e.g. when the application is doing large sequential | ||
365 | reads bigger than page size without rereading the same data) | ||
366 | this can provide better performance than the default | ||
367 | behavior which caches reads (reaadahead) and writes | ||
368 | (writebehind) through the local Linux client pagecache | ||
369 | if oplock (caching token) is granted and held. Note that | ||
370 | direct allows write operations larger than page size | ||
371 | to be sent to the server. | ||
372 | acl Allow setfacl and getfacl to manage posix ACLs if server | ||
373 | supports them. (default) | ||
374 | noacl Do not allow setfacl and getfacl calls on this mount | ||
375 | user_xattr Allow getting and setting user xattrs as OS/2 EAs (extended | ||
376 | attributes) to the server (default) e.g. via setfattr | ||
377 | and getfattr utilities. | ||
378 | nouser_xattr Do not allow getfattr/setfattr to get/set xattrs | ||
379 | |||
380 | The mount.cifs mount helper also accepts a few mount options before -o | ||
381 | including: | ||
382 | |||
383 | -S take password from stdin (equivalent to setting the environment | ||
384 | variable "PASSWD_FD=0" | ||
385 | -V print mount.cifs version | ||
386 | -? display simple usage information | ||
387 | |||
388 | With recent 2.6 kernel versions of modutils, the version of the cifs kernel | ||
389 | module can be displayed via modinfo. | ||
390 | |||
391 | Misc /proc/fs/cifs Flags and Debug Info | ||
392 | ======================================= | ||
393 | Informational pseudo-files: | ||
394 | DebugData Displays information about active CIFS sessions | ||
395 | and shares. | ||
396 | Stats Lists summary resource usage information as well as per | ||
397 | share statistics, if CONFIG_CIFS_STATS in enabled | ||
398 | in the kernel configuration. | ||
399 | |||
400 | Configuration pseudo-files: | ||
401 | MultiuserMount If set to one, more than one CIFS session to | ||
402 | the same server ip address can be established | ||
403 | if more than one uid accesses the same mount | ||
404 | point and if the uids user/password mapping | ||
405 | information is available. (default is 0) | ||
406 | PacketSigningEnabled If set to one, cifs packet signing is enabled | ||
407 | and will be used if the server requires | ||
408 | it. If set to two, cifs packet signing is | ||
409 | required even if the server considers packet | ||
410 | signing optional. (default 1) | ||
411 | cifsFYI If set to one, additional debug information is | ||
412 | logged to the system error log. (default 0) | ||
413 | ExtendedSecurity If set to one, SPNEGO session establishment | ||
414 | is allowed which enables more advanced | ||
415 | secure CIFS session establishment (default 0) | ||
416 | NTLMV2Enabled If set to one, more secure password hashes | ||
417 | are used when the server supports them and | ||
418 | when kerberos is not negotiated (default 0) | ||
419 | traceSMB If set to one, debug information is logged to the | ||
420 | system error log with the start of smb requests | ||
421 | and responses (default 0) | ||
422 | LookupCacheEnable If set to one, inode information is kept cached | ||
423 | for one second improving performance of lookups | ||
424 | (default 1) | ||
425 | OplockEnabled If set to one, safe distributed caching enabled. | ||
426 | (default 1) | ||
427 | LinuxExtensionsEnabled If set to one then the client will attempt to | ||
428 | use the CIFS "UNIX" extensions which are optional | ||
429 | protocol enhancements that allow CIFS servers | ||
430 | to return accurate UID/GID information as well | ||
431 | as support symbolic links. If you use servers | ||
432 | such as Samba that support the CIFS Unix | ||
433 | extensions but do not want to use symbolic link | ||
434 | support and want to map the uid and gid fields | ||
435 | to values supplied at mount (rather than the | ||
436 | actual values, then set this to zero. (default 1) | ||
437 | |||
438 | These experimental features and tracing can be enabled by changing flags in | ||
439 | /proc/fs/cifs (after the cifs module has been installed or built into the | ||
440 | kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable | ||
441 | tracing to the kernel message log type: | ||
442 | |||
443 | echo 1 > /proc/fs/cifs/cifsFYI | ||
444 | |||
445 | and for more extensive tracing including the start of smb requests and responses | ||
446 | |||
447 | echo 1 > /proc/fs/cifs/traceSMB | ||
448 | |||
449 | Two other experimental features are under development and to test | ||
450 | require enabling CONFIG_CIFS_EXPERIMENTAL | ||
451 | |||
452 | More efficient write operations and SMB buffer handling | ||
453 | |||
454 | DNOTIFY fcntl: needed for support of directory change | ||
455 | notification and perhaps later for file leases) | ||
456 | |||
457 | Per share (per client mount) statistics are available in /proc/fs/cifs/Stats | ||
458 | if the kernel was configured with cifs statistics enabled. The statistics | ||
459 | represent the number of successful (ie non-zero return code from the server) | ||
460 | SMB responses to some of the more common commands (open, delete, mkdir etc.). | ||
461 | Also recorded is the total bytes read and bytes written to the server for | ||
462 | that share. Note that due to client caching effects this can be less than the | ||
463 | number of bytes read and written by the application running on the client. | ||
464 | The statistics for the number of total SMBs and oplock breaks are different in | ||
465 | that they represent all for that share, not just those for which the server | ||
466 | returned success. | ||
467 | |||
468 | Also note that "cat /proc/fs/cifs/DebugData" will display information about | ||
469 | the active sessions and the shares that are mounted. Note: NTLMv2 enablement | ||
470 | will not work since they its implementation is not quite complete yet. | ||
471 | Do not alter these configuration values unless you are doing specific testing. | ||
472 | Enabling extended security works to Windows 2000 Workstations and XP but not to | ||
473 | Windows 2000 server or Samba since it does not usually send "raw NTLMSSP" | ||
474 | (instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not | ||
475 | complete in the CIFS VFS yet). | ||
diff --git a/fs/cifs/TODO b/fs/cifs/TODO new file mode 100644 index 000000000000..f4e3e1f67ee4 --- /dev/null +++ b/fs/cifs/TODO | |||
@@ -0,0 +1,104 @@ | |||
1 | version 1.22 July 30, 2004 | ||
2 | |||
3 | A Partial List of Missing Features | ||
4 | ================================== | ||
5 | |||
6 | Contributions are welcome. There are plenty of opportunities | ||
7 | for visible, important contributions to this module. Here | ||
8 | is a partial list of the known problems and missing features: | ||
9 | |||
10 | a) Support for SecurityDescriptors for chmod/chgrp/chown so | ||
11 | these can be supported for Windows servers | ||
12 | |||
13 | b) Better pam/winbind integration (e.g. to handle uid mapping | ||
14 | better) | ||
15 | |||
16 | c) multi-user mounts - multiplexed sessionsetups over single vc | ||
17 | (ie tcp session) - prettying up needed, and more testing needed | ||
18 | |||
19 | d) Kerberos/SPNEGO session setup support - (started) | ||
20 | |||
21 | e) NTLMv2 authentication (mostly implemented) | ||
22 | |||
23 | f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup | ||
24 | used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM | ||
25 | and raw NTLMSSP already. This is important when enabling | ||
26 | extended security and mounting to Windows 2003 Servers | ||
27 | |||
28 | f) Directory entry caching relies on a 1 second timer, rather than | ||
29 | using FindNotify or equivalent. - (started) | ||
30 | |||
31 | g) A few byte range testcases fail due to POSIX vs. Windows/CIFS | ||
32 | style byte range lock differences | ||
33 | |||
34 | h) quota support | ||
35 | |||
36 | j) finish writepages support (multi-page write behind for improved | ||
37 | performance) and syncpage | ||
38 | |||
39 | k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the | ||
40 | extra copy in/out of the socket buffers in some cases. | ||
41 | |||
42 | l) finish support for IPv6. This is mostly complete but | ||
43 | needs a simple conversion of ipv6 to sin6_addr from the | ||
44 | address in string representation. | ||
45 | |||
46 | m) Better optimize open (and pathbased setfilesize) to reduce the | ||
47 | oplock breaks coming from windows srv. Piggyback identical file | ||
48 | opens on top of each other by incrementing reference count rather | ||
49 | than resending (helps reduce server resource utilization and avoid | ||
50 | spurious oplock breaks). | ||
51 | |||
52 | o) Improve performance of readpages by sending more than one read | ||
53 | at a time when 8 pages or more are requested. In conjuntion | ||
54 | add support for async_cifs_readpages. | ||
55 | |||
56 | p) Add support for storing symlink and fifo info to Windows servers | ||
57 | in the Extended Attribute format their SFU clients would recognize. | ||
58 | |||
59 | q) Finish fcntl D_NOTIFY support so kde and gnome file list windows | ||
60 | will autorefresh (started) | ||
61 | |||
62 | r) Add GUI tool to configure /proc/fs/cifs settings and for display of | ||
63 | the CIFS statistics (started) | ||
64 | |||
65 | q) implement support for security and trusted categories of xattrs | ||
66 | (requires minor protocol extension) to enable better support for SELINUX | ||
67 | |||
68 | r) Implement O_DIRECT flag on open (already supported on mount) | ||
69 | |||
70 | KNOWN BUGS (updated December 10, 2004) | ||
71 | ==================================== | ||
72 | 1) existing symbolic links (Windows reparse points) are recognized but | ||
73 | can not be created remotely. They are implemented for Samba and those that | ||
74 | support the CIFS Unix extensions but Samba has a bug currently handling | ||
75 | symlink text beginning with slash | ||
76 | 2) follow_link and readdir code does not follow dfs junctions | ||
77 | but recognizes them | ||
78 | 3) create of new files to FAT partitions on Windows servers can | ||
79 | succeed but still return access denied (appears to be Windows | ||
80 | server not cifs client problem) and has not been reproduced recently. | ||
81 | NTFS partitions do not have this problem. | ||
82 | 4) debug connectathon lock test case 10 which fails against | ||
83 | Samba (may be unmappable due to POSIX to Windows lock model | ||
84 | differences but worth investigating). Also debug Samba to | ||
85 | see why lock test case 7 takes longer to complete to Samba | ||
86 | than to Windows. | ||
87 | |||
88 | Misc testing to do | ||
89 | ================== | ||
90 | 1) check out max path names and max path name components against various server | ||
91 | types. Try nested symlinks (8 deep). Return max path name in stat -f information | ||
92 | |||
93 | 2) Modify file portion of ltp so it can run against a mounted network | ||
94 | share and run it against cifs vfs. | ||
95 | |||
96 | 3) Additional performance testing and optimization using iozone and similar - | ||
97 | there are some easy changes that can be done to parallelize sequential writes, | ||
98 | and when signing is disabled to request larger read sizes (larger than | ||
99 | negotiated size) and send larger write sizes to modern servers. | ||
100 | |||
101 | 4) More exhaustively test the recently added NT4 support against various | ||
102 | NT4 service pack levels, and fix cifs_setattr for setting file times and | ||
103 | size to fall back to level 1 when error invalid level returned. | ||
104 | |||
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c new file mode 100644 index 000000000000..e02010dd73ec --- /dev/null +++ b/fs/cifs/asn1.c | |||
@@ -0,0 +1,618 @@ | |||
1 | /* | ||
2 | * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in | ||
3 | * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich | ||
4 | * | ||
5 | * Copyright (c) 2000 RP Internet (www.rpi.net.au). | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/config.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include "cifspdu.h" | ||
27 | #include "cifsglob.h" | ||
28 | #include "cifs_debug.h" | ||
29 | #include "cifsproto.h" | ||
30 | |||
31 | /***************************************************************************** | ||
32 | * | ||
33 | * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse) | ||
34 | * | ||
35 | *****************************************************************************/ | ||
36 | |||
37 | /* Class */ | ||
38 | #define ASN1_UNI 0 /* Universal */ | ||
39 | #define ASN1_APL 1 /* Application */ | ||
40 | #define ASN1_CTX 2 /* Context */ | ||
41 | #define ASN1_PRV 3 /* Private */ | ||
42 | |||
43 | /* Tag */ | ||
44 | #define ASN1_EOC 0 /* End Of Contents or N/A */ | ||
45 | #define ASN1_BOL 1 /* Boolean */ | ||
46 | #define ASN1_INT 2 /* Integer */ | ||
47 | #define ASN1_BTS 3 /* Bit String */ | ||
48 | #define ASN1_OTS 4 /* Octet String */ | ||
49 | #define ASN1_NUL 5 /* Null */ | ||
50 | #define ASN1_OJI 6 /* Object Identifier */ | ||
51 | #define ASN1_OJD 7 /* Object Description */ | ||
52 | #define ASN1_EXT 8 /* External */ | ||
53 | #define ASN1_SEQ 16 /* Sequence */ | ||
54 | #define ASN1_SET 17 /* Set */ | ||
55 | #define ASN1_NUMSTR 18 /* Numerical String */ | ||
56 | #define ASN1_PRNSTR 19 /* Printable String */ | ||
57 | #define ASN1_TEXSTR 20 /* Teletext String */ | ||
58 | #define ASN1_VIDSTR 21 /* Video String */ | ||
59 | #define ASN1_IA5STR 22 /* IA5 String */ | ||
60 | #define ASN1_UNITIM 23 /* Universal Time */ | ||
61 | #define ASN1_GENTIM 24 /* General Time */ | ||
62 | #define ASN1_GRASTR 25 /* Graphical String */ | ||
63 | #define ASN1_VISSTR 26 /* Visible String */ | ||
64 | #define ASN1_GENSTR 27 /* General String */ | ||
65 | |||
66 | /* Primitive / Constructed methods*/ | ||
67 | #define ASN1_PRI 0 /* Primitive */ | ||
68 | #define ASN1_CON 1 /* Constructed */ | ||
69 | |||
70 | /* | ||
71 | * Error codes. | ||
72 | */ | ||
73 | #define ASN1_ERR_NOERROR 0 | ||
74 | #define ASN1_ERR_DEC_EMPTY 2 | ||
75 | #define ASN1_ERR_DEC_EOC_MISMATCH 3 | ||
76 | #define ASN1_ERR_DEC_LENGTH_MISMATCH 4 | ||
77 | #define ASN1_ERR_DEC_BADVALUE 5 | ||
78 | |||
79 | #define SPNEGO_OID_LEN 7 | ||
80 | #define NTLMSSP_OID_LEN 10 | ||
81 | static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; | ||
82 | static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; | ||
83 | |||
84 | /* | ||
85 | * ASN.1 context. | ||
86 | */ | ||
87 | struct asn1_ctx { | ||
88 | int error; /* Error condition */ | ||
89 | unsigned char *pointer; /* Octet just to be decoded */ | ||
90 | unsigned char *begin; /* First octet */ | ||
91 | unsigned char *end; /* Octet after last octet */ | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * Octet string (not null terminated) | ||
96 | */ | ||
97 | struct asn1_octstr { | ||
98 | unsigned char *data; | ||
99 | unsigned int len; | ||
100 | }; | ||
101 | |||
102 | static void | ||
103 | asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len) | ||
104 | { | ||
105 | ctx->begin = buf; | ||
106 | ctx->end = buf + len; | ||
107 | ctx->pointer = buf; | ||
108 | ctx->error = ASN1_ERR_NOERROR; | ||
109 | } | ||
110 | |||
111 | static unsigned char | ||
112 | asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch) | ||
113 | { | ||
114 | if (ctx->pointer >= ctx->end) { | ||
115 | ctx->error = ASN1_ERR_DEC_EMPTY; | ||
116 | return 0; | ||
117 | } | ||
118 | *ch = *(ctx->pointer)++; | ||
119 | return 1; | ||
120 | } | ||
121 | |||
122 | static unsigned char | ||
123 | asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) | ||
124 | { | ||
125 | unsigned char ch; | ||
126 | |||
127 | *tag = 0; | ||
128 | |||
129 | do { | ||
130 | if (!asn1_octet_decode(ctx, &ch)) | ||
131 | return 0; | ||
132 | *tag <<= 7; | ||
133 | *tag |= ch & 0x7F; | ||
134 | } while ((ch & 0x80) == 0x80); | ||
135 | return 1; | ||
136 | } | ||
137 | |||
138 | static unsigned char | ||
139 | asn1_id_decode(struct asn1_ctx *ctx, | ||
140 | unsigned int *cls, unsigned int *con, unsigned int *tag) | ||
141 | { | ||
142 | unsigned char ch; | ||
143 | |||
144 | if (!asn1_octet_decode(ctx, &ch)) | ||
145 | return 0; | ||
146 | |||
147 | *cls = (ch & 0xC0) >> 6; | ||
148 | *con = (ch & 0x20) >> 5; | ||
149 | *tag = (ch & 0x1F); | ||
150 | |||
151 | if (*tag == 0x1F) { | ||
152 | if (!asn1_tag_decode(ctx, tag)) | ||
153 | return 0; | ||
154 | } | ||
155 | return 1; | ||
156 | } | ||
157 | |||
158 | static unsigned char | ||
159 | asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len) | ||
160 | { | ||
161 | unsigned char ch, cnt; | ||
162 | |||
163 | if (!asn1_octet_decode(ctx, &ch)) | ||
164 | return 0; | ||
165 | |||
166 | if (ch == 0x80) | ||
167 | *def = 0; | ||
168 | else { | ||
169 | *def = 1; | ||
170 | |||
171 | if (ch < 0x80) | ||
172 | *len = ch; | ||
173 | else { | ||
174 | cnt = (unsigned char) (ch & 0x7F); | ||
175 | *len = 0; | ||
176 | |||
177 | while (cnt > 0) { | ||
178 | if (!asn1_octet_decode(ctx, &ch)) | ||
179 | return 0; | ||
180 | *len <<= 8; | ||
181 | *len |= ch; | ||
182 | cnt--; | ||
183 | } | ||
184 | } | ||
185 | } | ||
186 | return 1; | ||
187 | } | ||
188 | |||
189 | static unsigned char | ||
190 | asn1_header_decode(struct asn1_ctx *ctx, | ||
191 | unsigned char **eoc, | ||
192 | unsigned int *cls, unsigned int *con, unsigned int *tag) | ||
193 | { | ||
194 | unsigned int def, len; | ||
195 | |||
196 | if (!asn1_id_decode(ctx, cls, con, tag)) | ||
197 | return 0; | ||
198 | |||
199 | if (!asn1_length_decode(ctx, &def, &len)) | ||
200 | return 0; | ||
201 | |||
202 | if (def) | ||
203 | *eoc = ctx->pointer + len; | ||
204 | else | ||
205 | *eoc = NULL; | ||
206 | return 1; | ||
207 | } | ||
208 | |||
209 | static unsigned char | ||
210 | asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc) | ||
211 | { | ||
212 | unsigned char ch; | ||
213 | |||
214 | if (eoc == NULL) { | ||
215 | if (!asn1_octet_decode(ctx, &ch)) | ||
216 | return 0; | ||
217 | |||
218 | if (ch != 0x00) { | ||
219 | ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | if (!asn1_octet_decode(ctx, &ch)) | ||
224 | return 0; | ||
225 | |||
226 | if (ch != 0x00) { | ||
227 | ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; | ||
228 | return 0; | ||
229 | } | ||
230 | return 1; | ||
231 | } else { | ||
232 | if (ctx->pointer != eoc) { | ||
233 | ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH; | ||
234 | return 0; | ||
235 | } | ||
236 | return 1; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | /* static unsigned char asn1_null_decode(struct asn1_ctx *ctx, | ||
241 | unsigned char *eoc) | ||
242 | { | ||
243 | ctx->pointer = eoc; | ||
244 | return 1; | ||
245 | } | ||
246 | |||
247 | static unsigned char asn1_long_decode(struct asn1_ctx *ctx, | ||
248 | unsigned char *eoc, long *integer) | ||
249 | { | ||
250 | unsigned char ch; | ||
251 | unsigned int len; | ||
252 | |||
253 | if (!asn1_octet_decode(ctx, &ch)) | ||
254 | return 0; | ||
255 | |||
256 | *integer = (signed char) ch; | ||
257 | len = 1; | ||
258 | |||
259 | while (ctx->pointer < eoc) { | ||
260 | if (++len > sizeof(long)) { | ||
261 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | if (!asn1_octet_decode(ctx, &ch)) | ||
266 | return 0; | ||
267 | |||
268 | *integer <<= 8; | ||
269 | *integer |= ch; | ||
270 | } | ||
271 | return 1; | ||
272 | } | ||
273 | |||
274 | static unsigned char asn1_uint_decode(struct asn1_ctx *ctx, | ||
275 | unsigned char *eoc, | ||
276 | unsigned int *integer) | ||
277 | { | ||
278 | unsigned char ch; | ||
279 | unsigned int len; | ||
280 | |||
281 | if (!asn1_octet_decode(ctx, &ch)) | ||
282 | return 0; | ||
283 | |||
284 | *integer = ch; | ||
285 | if (ch == 0) | ||
286 | len = 0; | ||
287 | else | ||
288 | len = 1; | ||
289 | |||
290 | while (ctx->pointer < eoc) { | ||
291 | if (++len > sizeof(unsigned int)) { | ||
292 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | if (!asn1_octet_decode(ctx, &ch)) | ||
297 | return 0; | ||
298 | |||
299 | *integer <<= 8; | ||
300 | *integer |= ch; | ||
301 | } | ||
302 | return 1; | ||
303 | } | ||
304 | |||
305 | static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx, | ||
306 | unsigned char *eoc, | ||
307 | unsigned long *integer) | ||
308 | { | ||
309 | unsigned char ch; | ||
310 | unsigned int len; | ||
311 | |||
312 | if (!asn1_octet_decode(ctx, &ch)) | ||
313 | return 0; | ||
314 | |||
315 | *integer = ch; | ||
316 | if (ch == 0) | ||
317 | len = 0; | ||
318 | else | ||
319 | len = 1; | ||
320 | |||
321 | while (ctx->pointer < eoc) { | ||
322 | if (++len > sizeof(unsigned long)) { | ||
323 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | if (!asn1_octet_decode(ctx, &ch)) | ||
328 | return 0; | ||
329 | |||
330 | *integer <<= 8; | ||
331 | *integer |= ch; | ||
332 | } | ||
333 | return 1; | ||
334 | } | ||
335 | |||
336 | static unsigned char | ||
337 | asn1_octets_decode(struct asn1_ctx *ctx, | ||
338 | unsigned char *eoc, | ||
339 | unsigned char **octets, unsigned int *len) | ||
340 | { | ||
341 | unsigned char *ptr; | ||
342 | |||
343 | *len = 0; | ||
344 | |||
345 | *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC); | ||
346 | if (*octets == NULL) { | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | ptr = *octets; | ||
351 | while (ctx->pointer < eoc) { | ||
352 | if (!asn1_octet_decode(ctx, (unsigned char *) ptr++)) { | ||
353 | kfree(*octets); | ||
354 | *octets = NULL; | ||
355 | return 0; | ||
356 | } | ||
357 | (*len)++; | ||
358 | } | ||
359 | return 1; | ||
360 | } */ | ||
361 | |||
362 | static unsigned char | ||
363 | asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid) | ||
364 | { | ||
365 | unsigned char ch; | ||
366 | |||
367 | *subid = 0; | ||
368 | |||
369 | do { | ||
370 | if (!asn1_octet_decode(ctx, &ch)) | ||
371 | return 0; | ||
372 | |||
373 | *subid <<= 7; | ||
374 | *subid |= ch & 0x7F; | ||
375 | } while ((ch & 0x80) == 0x80); | ||
376 | return 1; | ||
377 | } | ||
378 | |||
379 | static int | ||
380 | asn1_oid_decode(struct asn1_ctx *ctx, | ||
381 | unsigned char *eoc, unsigned long **oid, unsigned int *len) | ||
382 | { | ||
383 | unsigned long subid; | ||
384 | unsigned int size; | ||
385 | unsigned long *optr; | ||
386 | |||
387 | size = eoc - ctx->pointer + 1; | ||
388 | *oid = kmalloc(size * sizeof (unsigned long), GFP_ATOMIC); | ||
389 | if (*oid == NULL) { | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | optr = *oid; | ||
394 | |||
395 | if (!asn1_subid_decode(ctx, &subid)) { | ||
396 | kfree(*oid); | ||
397 | *oid = NULL; | ||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | if (subid < 40) { | ||
402 | optr[0] = 0; | ||
403 | optr[1] = subid; | ||
404 | } else if (subid < 80) { | ||
405 | optr[0] = 1; | ||
406 | optr[1] = subid - 40; | ||
407 | } else { | ||
408 | optr[0] = 2; | ||
409 | optr[1] = subid - 80; | ||
410 | } | ||
411 | |||
412 | *len = 2; | ||
413 | optr += 2; | ||
414 | |||
415 | while (ctx->pointer < eoc) { | ||
416 | if (++(*len) > size) { | ||
417 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
418 | kfree(*oid); | ||
419 | *oid = NULL; | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | if (!asn1_subid_decode(ctx, optr++)) { | ||
424 | kfree(*oid); | ||
425 | *oid = NULL; | ||
426 | return 0; | ||
427 | } | ||
428 | } | ||
429 | return 1; | ||
430 | } | ||
431 | |||
432 | static int | ||
433 | compare_oid(unsigned long *oid1, unsigned int oid1len, | ||
434 | unsigned long *oid2, unsigned int oid2len) | ||
435 | { | ||
436 | unsigned int i; | ||
437 | |||
438 | if (oid1len != oid2len) | ||
439 | return 0; | ||
440 | else { | ||
441 | for (i = 0; i < oid1len; i++) { | ||
442 | if (oid1[i] != oid2[i]) | ||
443 | return 0; | ||
444 | } | ||
445 | return 1; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | /* BB check for endian conversion issues here */ | ||
450 | |||
451 | int | ||
452 | decode_negTokenInit(unsigned char *security_blob, int length, | ||
453 | enum securityEnum *secType) | ||
454 | { | ||
455 | struct asn1_ctx ctx; | ||
456 | unsigned char *end; | ||
457 | unsigned char *sequence_end; | ||
458 | unsigned long *oid = NULL; | ||
459 | unsigned int cls, con, tag, oidlen, rc; | ||
460 | int use_ntlmssp = FALSE; | ||
461 | |||
462 | *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default */ | ||
463 | |||
464 | /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */ | ||
465 | |||
466 | asn1_open(&ctx, security_blob, length); | ||
467 | |||
468 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | ||
469 | cFYI(1, ("Error decoding negTokenInit header ")); | ||
470 | return 0; | ||
471 | } else if ((cls != ASN1_APL) || (con != ASN1_CON) | ||
472 | || (tag != ASN1_EOC)) { | ||
473 | cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag)); | ||
474 | return 0; | ||
475 | } else { | ||
476 | /* remember to free obj->oid */ | ||
477 | rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); | ||
478 | if (rc) { | ||
479 | if ((tag == ASN1_OJI) && (cls == ASN1_PRI)) { | ||
480 | rc = asn1_oid_decode(&ctx, end, &oid, &oidlen); | ||
481 | if (rc) { | ||
482 | rc = compare_oid(oid, oidlen, | ||
483 | SPNEGO_OID, | ||
484 | SPNEGO_OID_LEN); | ||
485 | kfree(oid); | ||
486 | } | ||
487 | } else | ||
488 | rc = 0; | ||
489 | } | ||
490 | |||
491 | if (!rc) { | ||
492 | cFYI(1, ("Error decoding negTokenInit header")); | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | ||
497 | cFYI(1, ("Error decoding negTokenInit ")); | ||
498 | return 0; | ||
499 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON) | ||
500 | || (tag != ASN1_EOC)) { | ||
501 | cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 0", | ||
502 | cls, con, tag, end, *end)); | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | ||
507 | cFYI(1, ("Error decoding negTokenInit ")); | ||
508 | return 0; | ||
509 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) | ||
510 | || (tag != ASN1_SEQ)) { | ||
511 | cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 1", | ||
512 | cls, con, tag, end, *end)); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | ||
517 | cFYI(1, ("Error decoding 2nd part of negTokenInit ")); | ||
518 | return 0; | ||
519 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON) | ||
520 | || (tag != ASN1_EOC)) { | ||
521 | cFYI(1, | ||
522 | ("cls = %d con = %d tag = %d end = %p (%d) exit 0", | ||
523 | cls, con, tag, end, *end)); | ||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | if (asn1_header_decode | ||
528 | (&ctx, &sequence_end, &cls, &con, &tag) == 0) { | ||
529 | cFYI(1, ("Error decoding 2nd part of negTokenInit ")); | ||
530 | return 0; | ||
531 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) | ||
532 | || (tag != ASN1_SEQ)) { | ||
533 | cFYI(1, | ||
534 | ("cls = %d con = %d tag = %d end = %p (%d) exit 1", | ||
535 | cls, con, tag, end, *end)); | ||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | while (!asn1_eoc_decode(&ctx, sequence_end)) { | ||
540 | rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); | ||
541 | if (!rc) { | ||
542 | cFYI(1, | ||
543 | ("Error 1 decoding negTokenInit header exit 2")); | ||
544 | return 0; | ||
545 | } | ||
546 | if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { | ||
547 | rc = asn1_oid_decode(&ctx, end, &oid, &oidlen); | ||
548 | if(rc) { | ||
549 | cFYI(1, | ||
550 | ("OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx", | ||
551 | oidlen, *oid, *(oid + 1), *(oid + 2), | ||
552 | *(oid + 3))); | ||
553 | rc = compare_oid(oid, oidlen, NTLMSSP_OID, | ||
554 | NTLMSSP_OID_LEN); | ||
555 | if(oid) | ||
556 | kfree(oid); | ||
557 | if (rc) | ||
558 | use_ntlmssp = TRUE; | ||
559 | } | ||
560 | } else { | ||
561 | cFYI(1,("This should be an oid what is going on? ")); | ||
562 | } | ||
563 | } | ||
564 | |||
565 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | ||
566 | cFYI(1, | ||
567 | ("Error decoding last part of negTokenInit exit 3")); | ||
568 | return 0; | ||
569 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { /* tag = 3 indicating mechListMIC */ | ||
570 | cFYI(1, | ||
571 | ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)", | ||
572 | cls, con, tag, end, *end)); | ||
573 | return 0; | ||
574 | } | ||
575 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | ||
576 | cFYI(1, | ||
577 | ("Error decoding last part of negTokenInit exit 5")); | ||
578 | return 0; | ||
579 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) | ||
580 | || (tag != ASN1_SEQ)) { | ||
581 | cFYI(1, | ||
582 | ("Exit 6 cls = %d con = %d tag = %d end = %p (%d)", | ||
583 | cls, con, tag, end, *end)); | ||
584 | } | ||
585 | |||
586 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | ||
587 | cFYI(1, | ||
588 | ("Error decoding last part of negTokenInit exit 7")); | ||
589 | return 0; | ||
590 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { | ||
591 | cFYI(1, | ||
592 | ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)", | ||
593 | cls, con, tag, end, *end)); | ||
594 | return 0; | ||
595 | } | ||
596 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | ||
597 | cFYI(1, | ||
598 | ("Error decoding last part of negTokenInit exit 9")); | ||
599 | return 0; | ||
600 | } else if ((cls != ASN1_UNI) || (con != ASN1_PRI) | ||
601 | || (tag != ASN1_GENSTR)) { | ||
602 | cFYI(1, | ||
603 | ("Exit 10 cls = %d con = %d tag = %d end = %p (%d)", | ||
604 | cls, con, tag, end, *end)); | ||
605 | return 0; | ||
606 | } | ||
607 | cFYI(1, ("Need to call asn1_octets_decode() function for this %s", ctx.pointer)); /* is this UTF-8 or ASCII? */ | ||
608 | } | ||
609 | |||
610 | /* if (use_kerberos) | ||
611 | *secType = Kerberos | ||
612 | else */ | ||
613 | if (use_ntlmssp) { | ||
614 | *secType = NTLMSSP; | ||
615 | } | ||
616 | |||
617 | return 1; | ||
618 | } | ||
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c new file mode 100644 index 000000000000..db28b561cd4b --- /dev/null +++ b/fs/cifs/cifs_debug.c | |||
@@ -0,0 +1,805 @@ | |||
1 | /* | ||
2 | * fs/cifs_debug.c | ||
3 | * | ||
4 | * Copyright (C) International Business Machines Corp., 2000,2003 | ||
5 | * | ||
6 | * Modified by Steve French (sfrench@us.ibm.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
16 | * the GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | #include <linux/fs.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/ctype.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/proc_fs.h> | ||
27 | #include <asm/uaccess.h> | ||
28 | #include "cifspdu.h" | ||
29 | #include "cifsglob.h" | ||
30 | #include "cifsproto.h" | ||
31 | #include "cifs_debug.h" | ||
32 | |||
33 | void | ||
34 | cifs_dump_mem(char *label, void *data, int length) | ||
35 | { | ||
36 | int i, j; | ||
37 | int *intptr = data; | ||
38 | char *charptr = data; | ||
39 | char buf[10], line[80]; | ||
40 | |||
41 | printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n", | ||
42 | label, length, data); | ||
43 | for (i = 0; i < length; i += 16) { | ||
44 | line[0] = 0; | ||
45 | for (j = 0; (j < 4) && (i + j * 4 < length); j++) { | ||
46 | sprintf(buf, " %08x", intptr[i / 4 + j]); | ||
47 | strcat(line, buf); | ||
48 | } | ||
49 | buf[0] = ' '; | ||
50 | buf[2] = 0; | ||
51 | for (j = 0; (j < 16) && (i + j < length); j++) { | ||
52 | buf[1] = isprint(charptr[i + j]) ? charptr[i + j] : '.'; | ||
53 | strcat(line, buf); | ||
54 | } | ||
55 | printk(KERN_DEBUG "%s\n", line); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | #ifdef CONFIG_PROC_FS | ||
60 | static int | ||
61 | cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | ||
62 | int count, int *eof, void *data) | ||
63 | { | ||
64 | struct list_head *tmp; | ||
65 | struct list_head *tmp1; | ||
66 | struct mid_q_entry * mid_entry; | ||
67 | struct cifsSesInfo *ses; | ||
68 | struct cifsTconInfo *tcon; | ||
69 | int i; | ||
70 | int length = 0; | ||
71 | char * original_buf = buf; | ||
72 | |||
73 | *beginBuffer = buf + offset; | ||
74 | |||
75 | |||
76 | length = | ||
77 | sprintf(buf, | ||
78 | "Display Internal CIFS Data Structures for Debugging\n" | ||
79 | "---------------------------------------------------\n"); | ||
80 | buf += length; | ||
81 | |||
82 | length = sprintf(buf, "Servers:\n"); | ||
83 | buf += length; | ||
84 | |||
85 | i = 0; | ||
86 | read_lock(&GlobalSMBSeslock); | ||
87 | list_for_each(tmp, &GlobalSMBSessionList) { | ||
88 | i++; | ||
89 | ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); | ||
90 | length = | ||
91 | sprintf(buf, | ||
92 | "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", | ||
93 | i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), | ||
94 | ses->serverOS, ses->serverNOS, ses->capabilities,ses->status); | ||
95 | buf += length; | ||
96 | if(ses->server) { | ||
97 | buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", | ||
98 | ses->server->tcpStatus, | ||
99 | atomic_read(&ses->server->socketUseCount), | ||
100 | ses->server->secMode, | ||
101 | atomic_read(&ses->server->inFlight)); | ||
102 | |||
103 | length = sprintf(buf, "\nMIDs: \n"); | ||
104 | buf += length; | ||
105 | |||
106 | spin_lock(&GlobalMid_Lock); | ||
107 | list_for_each(tmp1, &ses->server->pending_mid_q) { | ||
108 | mid_entry = list_entry(tmp1, struct | ||
109 | mid_q_entry, | ||
110 | qhead); | ||
111 | if(mid_entry) { | ||
112 | length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk,mid_entry->mid); | ||
113 | buf += length; | ||
114 | } | ||
115 | } | ||
116 | spin_unlock(&GlobalMid_Lock); | ||
117 | } | ||
118 | |||
119 | } | ||
120 | read_unlock(&GlobalSMBSeslock); | ||
121 | sprintf(buf, "\n"); | ||
122 | buf++; | ||
123 | |||
124 | length = sprintf(buf, "\nShares:\n"); | ||
125 | buf += length; | ||
126 | |||
127 | i = 0; | ||
128 | read_lock(&GlobalSMBSeslock); | ||
129 | list_for_each(tmp, &GlobalTreeConnectionList) { | ||
130 | __u32 dev_type; | ||
131 | i++; | ||
132 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | ||
133 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); | ||
134 | length = | ||
135 | sprintf(buf, | ||
136 | "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", | ||
137 | i, tcon->treeName, | ||
138 | atomic_read(&tcon->useCount), | ||
139 | tcon->nativeFileSystem, | ||
140 | le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), | ||
141 | le32_to_cpu(tcon->fsAttrInfo.Attributes), | ||
142 | le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), | ||
143 | tcon->tidStatus); | ||
144 | buf += length; | ||
145 | if (dev_type == FILE_DEVICE_DISK) | ||
146 | length = sprintf(buf, " type: DISK "); | ||
147 | else if (dev_type == FILE_DEVICE_CD_ROM) | ||
148 | length = sprintf(buf, " type: CDROM "); | ||
149 | else | ||
150 | length = | ||
151 | sprintf(buf, " type: %d ", dev_type); | ||
152 | buf += length; | ||
153 | if(tcon->tidStatus == CifsNeedReconnect) { | ||
154 | buf += sprintf(buf, "\tDISCONNECTED "); | ||
155 | length += 14; | ||
156 | } | ||
157 | } | ||
158 | read_unlock(&GlobalSMBSeslock); | ||
159 | |||
160 | length = sprintf(buf, "\n"); | ||
161 | buf += length; | ||
162 | |||
163 | /* BB add code to dump additional info such as TCP session info now */ | ||
164 | /* Now calculate total size of returned data */ | ||
165 | length = buf - original_buf; | ||
166 | |||
167 | if(offset + count >= length) | ||
168 | *eof = 1; | ||
169 | if(length < offset) { | ||
170 | *eof = 1; | ||
171 | return 0; | ||
172 | } else { | ||
173 | length = length - offset; | ||
174 | } | ||
175 | if (length > count) | ||
176 | length = count; | ||
177 | |||
178 | return length; | ||
179 | } | ||
180 | |||
181 | #ifdef CONFIG_CIFS_STATS | ||
182 | static int | ||
183 | cifs_stats_read(char *buf, char **beginBuffer, off_t offset, | ||
184 | int count, int *eof, void *data) | ||
185 | { | ||
186 | int item_length,i,length; | ||
187 | struct list_head *tmp; | ||
188 | struct cifsTconInfo *tcon; | ||
189 | |||
190 | *beginBuffer = buf + offset; | ||
191 | |||
192 | length = sprintf(buf, | ||
193 | "Resources in use\nCIFS Session: %d\n", | ||
194 | sesInfoAllocCount.counter); | ||
195 | buf += length; | ||
196 | item_length = | ||
197 | sprintf(buf,"Share (unique mount targets): %d\n", | ||
198 | tconInfoAllocCount.counter); | ||
199 | length += item_length; | ||
200 | buf += item_length; | ||
201 | item_length = | ||
202 | sprintf(buf,"SMB Request/Response Buffer: %d Pool size: %d\n", | ||
203 | bufAllocCount.counter,cifs_min_rcv + tcpSesAllocCount.counter); | ||
204 | length += item_length; | ||
205 | buf += item_length; | ||
206 | item_length = | ||
207 | sprintf(buf,"SMB Small Req/Resp Buffer: %d Pool size: %d\n", | ||
208 | smBufAllocCount.counter,cifs_min_small); | ||
209 | length += item_length; | ||
210 | buf += item_length; | ||
211 | item_length = | ||
212 | sprintf(buf,"Operations (MIDs): %d\n", | ||
213 | midCount.counter); | ||
214 | length += item_length; | ||
215 | buf += item_length; | ||
216 | item_length = sprintf(buf, | ||
217 | "\n%d session %d share reconnects\n", | ||
218 | tcpSesReconnectCount.counter,tconInfoReconnectCount.counter); | ||
219 | length += item_length; | ||
220 | buf += item_length; | ||
221 | |||
222 | item_length = sprintf(buf, | ||
223 | "Total vfs operations: %d maximum at one time: %d\n", | ||
224 | GlobalCurrentXid,GlobalMaxActiveXid); | ||
225 | length += item_length; | ||
226 | buf += item_length; | ||
227 | |||
228 | i = 0; | ||
229 | read_lock(&GlobalSMBSeslock); | ||
230 | list_for_each(tmp, &GlobalTreeConnectionList) { | ||
231 | i++; | ||
232 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | ||
233 | item_length = sprintf(buf,"\n%d) %s",i, tcon->treeName); | ||
234 | buf += item_length; | ||
235 | length += item_length; | ||
236 | if(tcon->tidStatus == CifsNeedReconnect) { | ||
237 | buf += sprintf(buf, "\tDISCONNECTED "); | ||
238 | length += 14; | ||
239 | } | ||
240 | item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d", | ||
241 | atomic_read(&tcon->num_smbs_sent), | ||
242 | atomic_read(&tcon->num_oplock_brks)); | ||
243 | buf += item_length; | ||
244 | length += item_length; | ||
245 | item_length = sprintf(buf,"\nReads: %d Bytes %lld", | ||
246 | atomic_read(&tcon->num_reads), | ||
247 | (long long)(tcon->bytes_read)); | ||
248 | buf += item_length; | ||
249 | length += item_length; | ||
250 | item_length = sprintf(buf,"\nWrites: %d Bytes: %lld", | ||
251 | atomic_read(&tcon->num_writes), | ||
252 | (long long)(tcon->bytes_written)); | ||
253 | buf += item_length; | ||
254 | length += item_length; | ||
255 | item_length = sprintf(buf, | ||
256 | "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d", | ||
257 | atomic_read(&tcon->num_opens), | ||
258 | atomic_read(&tcon->num_deletes), | ||
259 | atomic_read(&tcon->num_mkdirs), | ||
260 | atomic_read(&tcon->num_rmdirs)); | ||
261 | buf += item_length; | ||
262 | length += item_length; | ||
263 | item_length = sprintf(buf, | ||
264 | "\nRenames: %d T2 Renames %d", | ||
265 | atomic_read(&tcon->num_renames), | ||
266 | atomic_read(&tcon->num_t2renames)); | ||
267 | buf += item_length; | ||
268 | length += item_length; | ||
269 | } | ||
270 | read_unlock(&GlobalSMBSeslock); | ||
271 | |||
272 | buf += sprintf(buf,"\n"); | ||
273 | length++; | ||
274 | |||
275 | if(offset + count >= length) | ||
276 | *eof = 1; | ||
277 | if(length < offset) { | ||
278 | *eof = 1; | ||
279 | return 0; | ||
280 | } else { | ||
281 | length = length - offset; | ||
282 | } | ||
283 | if (length > count) | ||
284 | length = count; | ||
285 | |||
286 | return length; | ||
287 | } | ||
288 | #endif | ||
289 | |||
290 | static struct proc_dir_entry *proc_fs_cifs; | ||
291 | read_proc_t cifs_txanchor_read; | ||
292 | static read_proc_t cifsFYI_read; | ||
293 | static write_proc_t cifsFYI_write; | ||
294 | static read_proc_t oplockEnabled_read; | ||
295 | static write_proc_t oplockEnabled_write; | ||
296 | static read_proc_t lookupFlag_read; | ||
297 | static write_proc_t lookupFlag_write; | ||
298 | static read_proc_t traceSMB_read; | ||
299 | static write_proc_t traceSMB_write; | ||
300 | static read_proc_t multiuser_mount_read; | ||
301 | static write_proc_t multiuser_mount_write; | ||
302 | static read_proc_t extended_security_read; | ||
303 | static write_proc_t extended_security_write; | ||
304 | static read_proc_t ntlmv2_enabled_read; | ||
305 | static write_proc_t ntlmv2_enabled_write; | ||
306 | static read_proc_t packet_signing_enabled_read; | ||
307 | static write_proc_t packet_signing_enabled_write; | ||
308 | static read_proc_t quotaEnabled_read; | ||
309 | static write_proc_t quotaEnabled_write; | ||
310 | static read_proc_t linuxExtensionsEnabled_read; | ||
311 | static write_proc_t linuxExtensionsEnabled_write; | ||
312 | |||
313 | void | ||
314 | cifs_proc_init(void) | ||
315 | { | ||
316 | struct proc_dir_entry *pde; | ||
317 | |||
318 | proc_fs_cifs = proc_mkdir("cifs", proc_root_fs); | ||
319 | if (proc_fs_cifs == NULL) | ||
320 | return; | ||
321 | |||
322 | proc_fs_cifs->owner = THIS_MODULE; | ||
323 | create_proc_read_entry("DebugData", 0, proc_fs_cifs, | ||
324 | cifs_debug_data_read, NULL); | ||
325 | |||
326 | #ifdef CONFIG_CIFS_STATS | ||
327 | create_proc_read_entry("Stats", 0, proc_fs_cifs, | ||
328 | cifs_stats_read, NULL); | ||
329 | #endif | ||
330 | pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, | ||
331 | cifsFYI_read, NULL); | ||
332 | if (pde) | ||
333 | pde->write_proc = cifsFYI_write; | ||
334 | |||
335 | pde = | ||
336 | create_proc_read_entry("traceSMB", 0, proc_fs_cifs, | ||
337 | traceSMB_read, NULL); | ||
338 | if (pde) | ||
339 | pde->write_proc = traceSMB_write; | ||
340 | |||
341 | pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs, | ||
342 | oplockEnabled_read, NULL); | ||
343 | if (pde) | ||
344 | pde->write_proc = oplockEnabled_write; | ||
345 | |||
346 | pde = create_proc_read_entry("ReenableOldCifsReaddirCode", 0, proc_fs_cifs, | ||
347 | quotaEnabled_read, NULL); | ||
348 | if (pde) | ||
349 | pde->write_proc = quotaEnabled_write; | ||
350 | |||
351 | pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, | ||
352 | linuxExtensionsEnabled_read, NULL); | ||
353 | if (pde) | ||
354 | pde->write_proc = linuxExtensionsEnabled_write; | ||
355 | |||
356 | pde = | ||
357 | create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs, | ||
358 | multiuser_mount_read, NULL); | ||
359 | if (pde) | ||
360 | pde->write_proc = multiuser_mount_write; | ||
361 | |||
362 | pde = | ||
363 | create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, | ||
364 | extended_security_read, NULL); | ||
365 | if (pde) | ||
366 | pde->write_proc = extended_security_write; | ||
367 | |||
368 | pde = | ||
369 | create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, | ||
370 | lookupFlag_read, NULL); | ||
371 | if (pde) | ||
372 | pde->write_proc = lookupFlag_write; | ||
373 | |||
374 | pde = | ||
375 | create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, | ||
376 | ntlmv2_enabled_read, NULL); | ||
377 | if (pde) | ||
378 | pde->write_proc = ntlmv2_enabled_write; | ||
379 | |||
380 | pde = | ||
381 | create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, | ||
382 | packet_signing_enabled_read, NULL); | ||
383 | if (pde) | ||
384 | pde->write_proc = packet_signing_enabled_write; | ||
385 | } | ||
386 | |||
387 | void | ||
388 | cifs_proc_clean(void) | ||
389 | { | ||
390 | if (proc_fs_cifs == NULL) | ||
391 | return; | ||
392 | |||
393 | remove_proc_entry("DebugData", proc_fs_cifs); | ||
394 | remove_proc_entry("cifsFYI", proc_fs_cifs); | ||
395 | remove_proc_entry("traceSMB", proc_fs_cifs); | ||
396 | #ifdef CONFIG_CIFS_STATS | ||
397 | remove_proc_entry("Stats", proc_fs_cifs); | ||
398 | #endif | ||
399 | remove_proc_entry("MultiuserMount", proc_fs_cifs); | ||
400 | remove_proc_entry("OplockEnabled", proc_fs_cifs); | ||
401 | remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); | ||
402 | remove_proc_entry("ExtendedSecurity",proc_fs_cifs); | ||
403 | remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); | ||
404 | remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); | ||
405 | remove_proc_entry("ReenableOldCifsReaddirCode",proc_fs_cifs); | ||
406 | remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); | ||
407 | remove_proc_entry("cifs", proc_root_fs); | ||
408 | } | ||
409 | |||
410 | static int | ||
411 | cifsFYI_read(char *page, char **start, off_t off, int count, | ||
412 | int *eof, void *data) | ||
413 | { | ||
414 | int len; | ||
415 | |||
416 | len = sprintf(page, "%d\n", cifsFYI); | ||
417 | |||
418 | len -= off; | ||
419 | *start = page + off; | ||
420 | |||
421 | if (len > count) | ||
422 | len = count; | ||
423 | else | ||
424 | *eof = 1; | ||
425 | |||
426 | if (len < 0) | ||
427 | len = 0; | ||
428 | |||
429 | return len; | ||
430 | } | ||
431 | static int | ||
432 | cifsFYI_write(struct file *file, const char __user *buffer, | ||
433 | unsigned long count, void *data) | ||
434 | { | ||
435 | char c; | ||
436 | int rc; | ||
437 | |||
438 | rc = get_user(c, buffer); | ||
439 | if (rc) | ||
440 | return rc; | ||
441 | if (c == '0' || c == 'n' || c == 'N') | ||
442 | cifsFYI = 0; | ||
443 | else if (c == '1' || c == 'y' || c == 'Y') | ||
444 | cifsFYI = 1; | ||
445 | |||
446 | return count; | ||
447 | } | ||
448 | |||
449 | static int | ||
450 | oplockEnabled_read(char *page, char **start, off_t off, | ||
451 | int count, int *eof, void *data) | ||
452 | { | ||
453 | int len; | ||
454 | |||
455 | len = sprintf(page, "%d\n", oplockEnabled); | ||
456 | |||
457 | len -= off; | ||
458 | *start = page + off; | ||
459 | |||
460 | if (len > count) | ||
461 | len = count; | ||
462 | else | ||
463 | *eof = 1; | ||
464 | |||
465 | if (len < 0) | ||
466 | len = 0; | ||
467 | |||
468 | return len; | ||
469 | } | ||
470 | static int | ||
471 | oplockEnabled_write(struct file *file, const char __user *buffer, | ||
472 | unsigned long count, void *data) | ||
473 | { | ||
474 | char c; | ||
475 | int rc; | ||
476 | |||
477 | rc = get_user(c, buffer); | ||
478 | if (rc) | ||
479 | return rc; | ||
480 | if (c == '0' || c == 'n' || c == 'N') | ||
481 | oplockEnabled = 0; | ||
482 | else if (c == '1' || c == 'y' || c == 'Y') | ||
483 | oplockEnabled = 1; | ||
484 | |||
485 | return count; | ||
486 | } | ||
487 | |||
488 | static int | ||
489 | quotaEnabled_read(char *page, char **start, off_t off, | ||
490 | int count, int *eof, void *data) | ||
491 | { | ||
492 | int len; | ||
493 | |||
494 | len = sprintf(page, "%d\n", experimEnabled); | ||
495 | /* could also check if quotas are enabled in kernel | ||
496 | as a whole first */ | ||
497 | len -= off; | ||
498 | *start = page + off; | ||
499 | |||
500 | if (len > count) | ||
501 | len = count; | ||
502 | else | ||
503 | *eof = 1; | ||
504 | |||
505 | if (len < 0) | ||
506 | len = 0; | ||
507 | |||
508 | return len; | ||
509 | } | ||
510 | static int | ||
511 | quotaEnabled_write(struct file *file, const char __user *buffer, | ||
512 | unsigned long count, void *data) | ||
513 | { | ||
514 | char c; | ||
515 | int rc; | ||
516 | |||
517 | rc = get_user(c, buffer); | ||
518 | if (rc) | ||
519 | return rc; | ||
520 | if (c == '0' || c == 'n' || c == 'N') | ||
521 | experimEnabled = 0; | ||
522 | else if (c == '1' || c == 'y' || c == 'Y') | ||
523 | experimEnabled = 1; | ||
524 | |||
525 | return count; | ||
526 | } | ||
527 | |||
528 | static int | ||
529 | linuxExtensionsEnabled_read(char *page, char **start, off_t off, | ||
530 | int count, int *eof, void *data) | ||
531 | { | ||
532 | int len; | ||
533 | |||
534 | len = sprintf(page, "%d\n", linuxExtEnabled); | ||
535 | /* could also check if quotas are enabled in kernel | ||
536 | as a whole first */ | ||
537 | len -= off; | ||
538 | *start = page + off; | ||
539 | |||
540 | if (len > count) | ||
541 | len = count; | ||
542 | else | ||
543 | *eof = 1; | ||
544 | |||
545 | if (len < 0) | ||
546 | len = 0; | ||
547 | |||
548 | return len; | ||
549 | } | ||
550 | static int | ||
551 | linuxExtensionsEnabled_write(struct file *file, const char __user *buffer, | ||
552 | unsigned long count, void *data) | ||
553 | { | ||
554 | char c; | ||
555 | int rc; | ||
556 | |||
557 | rc = get_user(c, buffer); | ||
558 | if (rc) | ||
559 | return rc; | ||
560 | if (c == '0' || c == 'n' || c == 'N') | ||
561 | linuxExtEnabled = 0; | ||
562 | else if (c == '1' || c == 'y' || c == 'Y') | ||
563 | linuxExtEnabled = 1; | ||
564 | |||
565 | return count; | ||
566 | } | ||
567 | |||
568 | |||
569 | static int | ||
570 | lookupFlag_read(char *page, char **start, off_t off, | ||
571 | int count, int *eof, void *data) | ||
572 | { | ||
573 | int len; | ||
574 | |||
575 | len = sprintf(page, "%d\n", lookupCacheEnabled); | ||
576 | |||
577 | len -= off; | ||
578 | *start = page + off; | ||
579 | |||
580 | if (len > count) | ||
581 | len = count; | ||
582 | else | ||
583 | *eof = 1; | ||
584 | |||
585 | if (len < 0) | ||
586 | len = 0; | ||
587 | |||
588 | return len; | ||
589 | } | ||
590 | static int | ||
591 | lookupFlag_write(struct file *file, const char __user *buffer, | ||
592 | unsigned long count, void *data) | ||
593 | { | ||
594 | char c; | ||
595 | int rc; | ||
596 | |||
597 | rc = get_user(c, buffer); | ||
598 | if (rc) | ||
599 | return rc; | ||
600 | if (c == '0' || c == 'n' || c == 'N') | ||
601 | lookupCacheEnabled = 0; | ||
602 | else if (c == '1' || c == 'y' || c == 'Y') | ||
603 | lookupCacheEnabled = 1; | ||
604 | |||
605 | return count; | ||
606 | } | ||
607 | static int | ||
608 | traceSMB_read(char *page, char **start, off_t off, int count, | ||
609 | int *eof, void *data) | ||
610 | { | ||
611 | int len; | ||
612 | |||
613 | len = sprintf(page, "%d\n", traceSMB); | ||
614 | |||
615 | len -= off; | ||
616 | *start = page + off; | ||
617 | |||
618 | if (len > count) | ||
619 | len = count; | ||
620 | else | ||
621 | *eof = 1; | ||
622 | |||
623 | if (len < 0) | ||
624 | len = 0; | ||
625 | |||
626 | return len; | ||
627 | } | ||
628 | static int | ||
629 | traceSMB_write(struct file *file, const char __user *buffer, | ||
630 | unsigned long count, void *data) | ||
631 | { | ||
632 | char c; | ||
633 | int rc; | ||
634 | |||
635 | rc = get_user(c, buffer); | ||
636 | if (rc) | ||
637 | return rc; | ||
638 | if (c == '0' || c == 'n' || c == 'N') | ||
639 | traceSMB = 0; | ||
640 | else if (c == '1' || c == 'y' || c == 'Y') | ||
641 | traceSMB = 1; | ||
642 | |||
643 | return count; | ||
644 | } | ||
645 | |||
646 | static int | ||
647 | multiuser_mount_read(char *page, char **start, off_t off, | ||
648 | int count, int *eof, void *data) | ||
649 | { | ||
650 | int len; | ||
651 | |||
652 | len = sprintf(page, "%d\n", multiuser_mount); | ||
653 | |||
654 | len -= off; | ||
655 | *start = page + off; | ||
656 | |||
657 | if (len > count) | ||
658 | len = count; | ||
659 | else | ||
660 | *eof = 1; | ||
661 | |||
662 | if (len < 0) | ||
663 | len = 0; | ||
664 | |||
665 | return len; | ||
666 | } | ||
667 | static int | ||
668 | multiuser_mount_write(struct file *file, const char __user *buffer, | ||
669 | unsigned long count, void *data) | ||
670 | { | ||
671 | char c; | ||
672 | int rc; | ||
673 | |||
674 | rc = get_user(c, buffer); | ||
675 | if (rc) | ||
676 | return rc; | ||
677 | if (c == '0' || c == 'n' || c == 'N') | ||
678 | multiuser_mount = 0; | ||
679 | else if (c == '1' || c == 'y' || c == 'Y') | ||
680 | multiuser_mount = 1; | ||
681 | |||
682 | return count; | ||
683 | } | ||
684 | |||
685 | static int | ||
686 | extended_security_read(char *page, char **start, off_t off, | ||
687 | int count, int *eof, void *data) | ||
688 | { | ||
689 | int len; | ||
690 | |||
691 | len = sprintf(page, "%d\n", extended_security); | ||
692 | |||
693 | len -= off; | ||
694 | *start = page + off; | ||
695 | |||
696 | if (len > count) | ||
697 | len = count; | ||
698 | else | ||
699 | *eof = 1; | ||
700 | |||
701 | if (len < 0) | ||
702 | len = 0; | ||
703 | |||
704 | return len; | ||
705 | } | ||
706 | static int | ||
707 | extended_security_write(struct file *file, const char __user *buffer, | ||
708 | unsigned long count, void *data) | ||
709 | { | ||
710 | char c; | ||
711 | int rc; | ||
712 | |||
713 | rc = get_user(c, buffer); | ||
714 | if (rc) | ||
715 | return rc; | ||
716 | if (c == '0' || c == 'n' || c == 'N') | ||
717 | extended_security = 0; | ||
718 | else if (c == '1' || c == 'y' || c == 'Y') | ||
719 | extended_security = 1; | ||
720 | |||
721 | return count; | ||
722 | } | ||
723 | |||
724 | static int | ||
725 | ntlmv2_enabled_read(char *page, char **start, off_t off, | ||
726 | int count, int *eof, void *data) | ||
727 | { | ||
728 | int len; | ||
729 | |||
730 | len = sprintf(page, "%d\n", ntlmv2_support); | ||
731 | |||
732 | len -= off; | ||
733 | *start = page + off; | ||
734 | |||
735 | if (len > count) | ||
736 | len = count; | ||
737 | else | ||
738 | *eof = 1; | ||
739 | |||
740 | if (len < 0) | ||
741 | len = 0; | ||
742 | |||
743 | return len; | ||
744 | } | ||
745 | static int | ||
746 | ntlmv2_enabled_write(struct file *file, const char __user *buffer, | ||
747 | unsigned long count, void *data) | ||
748 | { | ||
749 | char c; | ||
750 | int rc; | ||
751 | |||
752 | rc = get_user(c, buffer); | ||
753 | if (rc) | ||
754 | return rc; | ||
755 | if (c == '0' || c == 'n' || c == 'N') | ||
756 | ntlmv2_support = 0; | ||
757 | else if (c == '1' || c == 'y' || c == 'Y') | ||
758 | ntlmv2_support = 1; | ||
759 | |||
760 | return count; | ||
761 | } | ||
762 | |||
763 | static int | ||
764 | packet_signing_enabled_read(char *page, char **start, off_t off, | ||
765 | int count, int *eof, void *data) | ||
766 | { | ||
767 | int len; | ||
768 | |||
769 | len = sprintf(page, "%d\n", sign_CIFS_PDUs); | ||
770 | |||
771 | len -= off; | ||
772 | *start = page + off; | ||
773 | |||
774 | if (len > count) | ||
775 | len = count; | ||
776 | else | ||
777 | *eof = 1; | ||
778 | |||
779 | if (len < 0) | ||
780 | len = 0; | ||
781 | |||
782 | return len; | ||
783 | } | ||
784 | static int | ||
785 | packet_signing_enabled_write(struct file *file, const char __user *buffer, | ||
786 | unsigned long count, void *data) | ||
787 | { | ||
788 | char c; | ||
789 | int rc; | ||
790 | |||
791 | rc = get_user(c, buffer); | ||
792 | if (rc) | ||
793 | return rc; | ||
794 | if (c == '0' || c == 'n' || c == 'N') | ||
795 | sign_CIFS_PDUs = 0; | ||
796 | else if (c == '1' || c == 'y' || c == 'Y') | ||
797 | sign_CIFS_PDUs = 1; | ||
798 | else if (c == '2') | ||
799 | sign_CIFS_PDUs = 2; | ||
800 | |||
801 | return count; | ||
802 | } | ||
803 | |||
804 | |||
805 | #endif | ||
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h new file mode 100644 index 000000000000..bf24d2828f68 --- /dev/null +++ b/fs/cifs/cifs_debug.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) International Business Machines Corp., 2000,2002 | ||
4 | * Modified by Steve French (sfrench@us.ibm.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
14 | * the GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #define CIFS_DEBUG /* BB temporary */ | ||
22 | |||
23 | #ifndef _H_CIFS_DEBUG | ||
24 | #define _H_CIFS_DEBUG | ||
25 | |||
26 | void cifs_dump_mem(char *label, void *data, int length); | ||
27 | extern int traceSMB; /* flag which enables the function below */ | ||
28 | void dump_smb(struct smb_hdr *, int); | ||
29 | |||
30 | /* | ||
31 | * debug ON | ||
32 | * -------- | ||
33 | */ | ||
34 | #ifdef CIFS_DEBUG | ||
35 | |||
36 | |||
37 | /* information message: e.g., configuration, major event */ | ||
38 | extern int cifsFYI; | ||
39 | #define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg) | ||
40 | |||
41 | #define cFYI(button,prspec) if (button) cifsfyi prspec | ||
42 | |||
43 | #define cifswarn(format, arg...) printk(KERN_WARNING ": " format "\n" , ## arg) | ||
44 | |||
45 | /* debug event message: */ | ||
46 | extern int cifsERROR; | ||
47 | |||
48 | #define cEVENT(format,arg...) if (cifsERROR) printk(KERN_EVENT __FILE__ ": " format "\n" , ## arg) | ||
49 | |||
50 | /* error event message: e.g., i/o error */ | ||
51 | #define cifserror(format,arg...) if (cifsERROR) printk(KERN_ERR " CIFS VFS: " format "\n" "" , ## arg) | ||
52 | |||
53 | #define cERROR(button, prspec) if (button) cifserror prspec | ||
54 | |||
55 | /* | ||
56 | * debug OFF | ||
57 | * --------- | ||
58 | */ | ||
59 | #else /* _CIFS_DEBUG */ | ||
60 | #define cERROR(button,prspec) | ||
61 | #define cEVENT(format,arg...) | ||
62 | #define cFYI(button, prspec) | ||
63 | #define cifserror(format,arg...) | ||
64 | #endif /* _CIFS_DEBUG */ | ||
65 | |||
66 | #endif /* _H_CIFS_DEBUG */ | ||
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h new file mode 100644 index 000000000000..77da902d8f32 --- /dev/null +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifs_fs_sb.h | ||
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 | */ | ||
18 | #ifndef _CIFS_FS_SB_H | ||
19 | #define _CIFS_FS_SB_H | ||
20 | |||
21 | #define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */ | ||
22 | #define CIFS_MOUNT_SET_UID 2 /* set current->euid in create etc. */ | ||
23 | #define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */ | ||
24 | #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ | ||
25 | #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ | ||
26 | |||
27 | struct cifs_sb_info { | ||
28 | struct cifsTconInfo *tcon; /* primary mount */ | ||
29 | struct list_head nested_tcon_q; | ||
30 | struct nls_table *local_nls; | ||
31 | unsigned int rsize; | ||
32 | unsigned int wsize; | ||
33 | uid_t mnt_uid; | ||
34 | gid_t mnt_gid; | ||
35 | mode_t mnt_file_mode; | ||
36 | mode_t mnt_dir_mode; | ||
37 | int mnt_cifs_flags; | ||
38 | }; | ||
39 | #endif /* _CIFS_FS_SB_H */ | ||
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c new file mode 100644 index 000000000000..a17adf4cb9ba --- /dev/null +++ b/fs/cifs/cifs_unicode.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifs_unicode.c | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2000,2002 | ||
5 | * Modified by Steve French (sfrench@us.ibm.com) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program 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 General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #include <linux/fs.h> | ||
22 | #include "cifs_unicode.h" | ||
23 | #include "cifs_uniupr.h" | ||
24 | #include "cifspdu.h" | ||
25 | #include "cifs_debug.h" | ||
26 | |||
27 | /* | ||
28 | * NAME: cifs_strfromUCS() | ||
29 | * | ||
30 | * FUNCTION: Convert little-endian unicode string to character string | ||
31 | * | ||
32 | */ | ||
33 | int | ||
34 | cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */ | ||
35 | int len, const struct nls_table *codepage) | ||
36 | { | ||
37 | int i; | ||
38 | int outlen = 0; | ||
39 | |||
40 | for (i = 0; (i < len) && from[i]; i++) { | ||
41 | int charlen; | ||
42 | /* 2.4.0 kernel or greater */ | ||
43 | charlen = | ||
44 | codepage->uni2char(le16_to_cpu(from[i]), &to[outlen], | ||
45 | NLS_MAX_CHARSET_SIZE); | ||
46 | if (charlen > 0) { | ||
47 | outlen += charlen; | ||
48 | } else { | ||
49 | to[outlen++] = '?'; | ||
50 | } | ||
51 | } | ||
52 | to[outlen] = 0; | ||
53 | return outlen; | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * NAME: cifs_strtoUCS() | ||
58 | * | ||
59 | * FUNCTION: Convert character string to unicode string | ||
60 | * | ||
61 | */ | ||
62 | int | ||
63 | cifs_strtoUCS(wchar_t * to, const char *from, int len, | ||
64 | const struct nls_table *codepage) | ||
65 | { | ||
66 | int charlen; | ||
67 | int i; | ||
68 | |||
69 | for (i = 0; len && *from; i++, from += charlen, len -= charlen) { | ||
70 | |||
71 | /* works for 2.4.0 kernel or later */ | ||
72 | charlen = codepage->char2uni(from, len, &to[i]); | ||
73 | if (charlen < 1) { | ||
74 | cERROR(1, | ||
75 | ("cifs_strtoUCS: char2uni returned %d", | ||
76 | charlen)); | ||
77 | to[i] = cpu_to_le16(0x003f); /* a question mark */ | ||
78 | charlen = 1; | ||
79 | } | ||
80 | to[i] = cpu_to_le16(to[i]); | ||
81 | |||
82 | } | ||
83 | |||
84 | to[i] = 0; | ||
85 | return i; | ||
86 | } | ||
87 | |||
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h new file mode 100644 index 000000000000..da8dde965275 --- /dev/null +++ b/fs/cifs/cifs_unicode.h | |||
@@ -0,0 +1,353 @@ | |||
1 | /* | ||
2 | * cifs_unicode: Unicode kernel case support | ||
3 | * | ||
4 | * Function: | ||
5 | * Convert a unicode character to upper or lower case using | ||
6 | * compressed tables. | ||
7 | * | ||
8 | * Copyright (c) International Business Machines Corp., 2000,2002 | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
18 | * the GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * | ||
25 | * Notes: | ||
26 | * These APIs are based on the C library functions. The semantics | ||
27 | * should match the C functions but with expanded size operands. | ||
28 | * | ||
29 | * The upper/lower functions are based on a table created by mkupr. | ||
30 | * This is a compressed table of upper and lower case conversion. | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include <asm/byteorder.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/nls.h> | ||
37 | |||
38 | #define UNIUPR_NOLOWER /* Example to not expand lower case tables */ | ||
39 | |||
40 | /* Just define what we want from uniupr.h. We don't want to define the tables | ||
41 | * in each source file. | ||
42 | */ | ||
43 | #ifndef UNICASERANGE_DEFINED | ||
44 | struct UniCaseRange { | ||
45 | wchar_t start; | ||
46 | wchar_t end; | ||
47 | signed char *table; | ||
48 | }; | ||
49 | #endif /* UNICASERANGE_DEFINED */ | ||
50 | |||
51 | #ifndef UNIUPR_NOUPPER | ||
52 | extern signed char CifsUniUpperTable[512]; | ||
53 | extern const struct UniCaseRange CifsUniUpperRange[]; | ||
54 | #endif /* UNIUPR_NOUPPER */ | ||
55 | |||
56 | #ifndef UNIUPR_NOLOWER | ||
57 | extern signed char UniLowerTable[512]; | ||
58 | extern struct UniCaseRange UniLowerRange[]; | ||
59 | #endif /* UNIUPR_NOLOWER */ | ||
60 | |||
61 | #ifdef __KERNEL__ | ||
62 | int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *); | ||
63 | int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *); | ||
64 | #endif | ||
65 | |||
66 | /* | ||
67 | * UniStrcat: Concatenate the second string to the first | ||
68 | * | ||
69 | * Returns: | ||
70 | * Address of the first string | ||
71 | */ | ||
72 | static inline wchar_t * | ||
73 | UniStrcat(wchar_t * ucs1, const wchar_t * ucs2) | ||
74 | { | ||
75 | wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */ | ||
76 | |||
77 | while (*ucs1++) ; /* To end of first string */ | ||
78 | ucs1--; /* Return to the null */ | ||
79 | while ((*ucs1++ = *ucs2++)) ; /* copy string 2 over */ | ||
80 | return anchor; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * UniStrchr: Find a character in a string | ||
85 | * | ||
86 | * Returns: | ||
87 | * Address of first occurrence of character in string | ||
88 | * or NULL if the character is not in the string | ||
89 | */ | ||
90 | static inline wchar_t * | ||
91 | UniStrchr(const wchar_t * ucs, wchar_t uc) | ||
92 | { | ||
93 | while ((*ucs != uc) && *ucs) | ||
94 | ucs++; | ||
95 | |||
96 | if (*ucs == uc) | ||
97 | return (wchar_t *) ucs; | ||
98 | return NULL; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * UniStrcmp: Compare two strings | ||
103 | * | ||
104 | * Returns: | ||
105 | * < 0: First string is less than second | ||
106 | * = 0: Strings are equal | ||
107 | * > 0: First string is greater than second | ||
108 | */ | ||
109 | static inline int | ||
110 | UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2) | ||
111 | { | ||
112 | while ((*ucs1 == *ucs2) && *ucs1) { | ||
113 | ucs1++; | ||
114 | ucs2++; | ||
115 | } | ||
116 | return (int) *ucs1 - (int) *ucs2; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * UniStrcpy: Copy a string | ||
121 | */ | ||
122 | static inline wchar_t * | ||
123 | UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2) | ||
124 | { | ||
125 | wchar_t *anchor = ucs1; /* save the start of result string */ | ||
126 | |||
127 | while ((*ucs1++ = *ucs2++)) ; | ||
128 | return anchor; | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes) | ||
133 | */ | ||
134 | static inline size_t | ||
135 | UniStrlen(const wchar_t * ucs1) | ||
136 | { | ||
137 | int i = 0; | ||
138 | |||
139 | while (*ucs1++) | ||
140 | i++; | ||
141 | return i; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a string (length limited) | ||
146 | */ | ||
147 | static inline size_t | ||
148 | UniStrnlen(const wchar_t * ucs1, int maxlen) | ||
149 | { | ||
150 | int i = 0; | ||
151 | |||
152 | while (*ucs1++) { | ||
153 | i++; | ||
154 | if (i >= maxlen) | ||
155 | break; | ||
156 | } | ||
157 | return i; | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * UniStrncat: Concatenate length limited string | ||
162 | */ | ||
163 | static inline wchar_t * | ||
164 | UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n) | ||
165 | { | ||
166 | wchar_t *anchor = ucs1; /* save pointer to string 1 */ | ||
167 | |||
168 | while (*ucs1++) ; | ||
169 | ucs1--; /* point to null terminator of s1 */ | ||
170 | while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */ | ||
171 | ucs1++; | ||
172 | ucs2++; | ||
173 | } | ||
174 | *ucs1 = 0; /* Null terminate the result */ | ||
175 | return (anchor); | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * UniStrncmp: Compare length limited string | ||
180 | */ | ||
181 | static inline int | ||
182 | UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) | ||
183 | { | ||
184 | if (!n) | ||
185 | return 0; /* Null strings are equal */ | ||
186 | while ((*ucs1 == *ucs2) && *ucs1 && --n) { | ||
187 | ucs1++; | ||
188 | ucs2++; | ||
189 | } | ||
190 | return (int) *ucs1 - (int) *ucs2; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * UniStrncmp_le: Compare length limited string - native to little-endian | ||
195 | */ | ||
196 | static inline int | ||
197 | UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) | ||
198 | { | ||
199 | if (!n) | ||
200 | return 0; /* Null strings are equal */ | ||
201 | while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) { | ||
202 | ucs1++; | ||
203 | ucs2++; | ||
204 | } | ||
205 | return (int) *ucs1 - (int) __le16_to_cpu(*ucs2); | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * UniStrncpy: Copy length limited string with pad | ||
210 | */ | ||
211 | static inline wchar_t * | ||
212 | UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n) | ||
213 | { | ||
214 | wchar_t *anchor = ucs1; | ||
215 | |||
216 | while (n-- && *ucs2) /* Copy the strings */ | ||
217 | *ucs1++ = *ucs2++; | ||
218 | |||
219 | n++; | ||
220 | while (n--) /* Pad with nulls */ | ||
221 | *ucs1++ = 0; | ||
222 | return anchor; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * UniStrncpy_le: Copy length limited string with pad to little-endian | ||
227 | */ | ||
228 | static inline wchar_t * | ||
229 | UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n) | ||
230 | { | ||
231 | wchar_t *anchor = ucs1; | ||
232 | |||
233 | while (n-- && *ucs2) /* Copy the strings */ | ||
234 | *ucs1++ = __le16_to_cpu(*ucs2++); | ||
235 | |||
236 | n++; | ||
237 | while (n--) /* Pad with nulls */ | ||
238 | *ucs1++ = 0; | ||
239 | return anchor; | ||
240 | } | ||
241 | |||
242 | /* | ||
243 | * UniStrstr: Find a string in a string | ||
244 | * | ||
245 | * Returns: | ||
246 | * Address of first match found | ||
247 | * NULL if no matching string is found | ||
248 | */ | ||
249 | static inline wchar_t * | ||
250 | UniStrstr(const wchar_t * ucs1, const wchar_t * ucs2) | ||
251 | { | ||
252 | const wchar_t *anchor1 = ucs1; | ||
253 | const wchar_t *anchor2 = ucs2; | ||
254 | |||
255 | while (*ucs1) { | ||
256 | if (*ucs1 == *ucs2) { /* Partial match found */ | ||
257 | ucs1++; | ||
258 | ucs2++; | ||
259 | } else { | ||
260 | if (!*ucs2) /* Match found */ | ||
261 | return (wchar_t *) anchor1; | ||
262 | ucs1 = ++anchor1; /* No match */ | ||
263 | ucs2 = anchor2; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | if (!*ucs2) /* Both end together */ | ||
268 | return (wchar_t *) anchor1; /* Match found */ | ||
269 | return NULL; /* No match */ | ||
270 | } | ||
271 | |||
272 | #ifndef UNIUPR_NOUPPER | ||
273 | /* | ||
274 | * UniToupper: Convert a unicode character to upper case | ||
275 | */ | ||
276 | static inline wchar_t | ||
277 | UniToupper(register wchar_t uc) | ||
278 | { | ||
279 | register const struct UniCaseRange *rp; | ||
280 | |||
281 | if (uc < sizeof (CifsUniUpperTable)) { /* Latin characters */ | ||
282 | return uc + CifsUniUpperTable[uc]; /* Use base tables */ | ||
283 | } else { | ||
284 | rp = CifsUniUpperRange; /* Use range tables */ | ||
285 | while (rp->start) { | ||
286 | if (uc < rp->start) /* Before start of range */ | ||
287 | return uc; /* Uppercase = input */ | ||
288 | if (uc <= rp->end) /* In range */ | ||
289 | return uc + rp->table[uc - rp->start]; | ||
290 | rp++; /* Try next range */ | ||
291 | } | ||
292 | } | ||
293 | return uc; /* Past last range */ | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * UniStrupr: Upper case a unicode string | ||
298 | */ | ||
299 | static inline wchar_t * | ||
300 | UniStrupr(register wchar_t * upin) | ||
301 | { | ||
302 | register wchar_t *up; | ||
303 | |||
304 | up = upin; | ||
305 | while (*up) { /* For all characters */ | ||
306 | *up = UniToupper(*up); | ||
307 | up++; | ||
308 | } | ||
309 | return upin; /* Return input pointer */ | ||
310 | } | ||
311 | #endif /* UNIUPR_NOUPPER */ | ||
312 | |||
313 | #ifndef UNIUPR_NOLOWER | ||
314 | /* | ||
315 | * UniTolower: Convert a unicode character to lower case | ||
316 | */ | ||
317 | static inline wchar_t | ||
318 | UniTolower(wchar_t uc) | ||
319 | { | ||
320 | register struct UniCaseRange *rp; | ||
321 | |||
322 | if (uc < sizeof (UniLowerTable)) { /* Latin characters */ | ||
323 | return uc + UniLowerTable[uc]; /* Use base tables */ | ||
324 | } else { | ||
325 | rp = UniLowerRange; /* Use range tables */ | ||
326 | while (rp->start) { | ||
327 | if (uc < rp->start) /* Before start of range */ | ||
328 | return uc; /* Uppercase = input */ | ||
329 | if (uc <= rp->end) /* In range */ | ||
330 | return uc + rp->table[uc - rp->start]; | ||
331 | rp++; /* Try next range */ | ||
332 | } | ||
333 | } | ||
334 | return uc; /* Past last range */ | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * UniStrlwr: Lower case a unicode string | ||
339 | */ | ||
340 | static inline wchar_t * | ||
341 | UniStrlwr(register wchar_t * upin) | ||
342 | { | ||
343 | register wchar_t *up; | ||
344 | |||
345 | up = upin; | ||
346 | while (*up) { /* For all characters */ | ||
347 | *up = UniTolower(*up); | ||
348 | up++; | ||
349 | } | ||
350 | return upin; /* Return input pointer */ | ||
351 | } | ||
352 | |||
353 | #endif | ||
diff --git a/fs/cifs/cifs_uniupr.h b/fs/cifs/cifs_uniupr.h new file mode 100644 index 000000000000..decd138f14d4 --- /dev/null +++ b/fs/cifs/cifs_uniupr.h | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * Copyright (c) International Business Machines Corp., 2000,2002 | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
12 | * the GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * uniupr.h - Unicode compressed case ranges | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef UNIUPR_NOUPPER | ||
23 | /* | ||
24 | * Latin upper case | ||
25 | */ | ||
26 | signed char CifsUniUpperTable[512] = { | ||
27 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ | ||
28 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ | ||
29 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ | ||
30 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ | ||
31 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */ | ||
32 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */ | ||
33 | 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 060-06f */ | ||
34 | -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 0, 0, 0, 0, 0, /* 070-07f */ | ||
35 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ | ||
36 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ | ||
37 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ | ||
38 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ | ||
39 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */ | ||
40 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */ | ||
41 | -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 0e0-0ef */ | ||
42 | -32, -32, -32, -32, -32, -32, -32, 0, -32, -32, -32, -32, -32, -32, -32, 121, /* 0f0-0ff */ | ||
43 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */ | ||
44 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */ | ||
45 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */ | ||
46 | 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */ | ||
47 | -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */ | ||
48 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */ | ||
49 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */ | ||
50 | 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */ | ||
51 | 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */ | ||
52 | 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */ | ||
53 | 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */ | ||
54 | -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */ | ||
55 | 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */ | ||
56 | -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */ | ||
57 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */ | ||
58 | 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */ | ||
59 | }; | ||
60 | |||
61 | /* Upper case range - Greek */ | ||
62 | static signed char UniCaseRangeU03a0[47] = { | ||
63 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37, /* 3a0-3af */ | ||
64 | 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 3b0-3bf */ | ||
65 | -32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64, | ||
66 | -63, -63, | ||
67 | }; | ||
68 | |||
69 | /* Upper case range - Cyrillic */ | ||
70 | static signed char UniCaseRangeU0430[48] = { | ||
71 | -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 430-43f */ | ||
72 | -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 440-44f */ | ||
73 | 0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, 0, -80, -80, /* 450-45f */ | ||
74 | }; | ||
75 | |||
76 | /* Upper case range - Extended cyrillic */ | ||
77 | static signed char UniCaseRangeU0490[61] = { | ||
78 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */ | ||
79 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */ | ||
80 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */ | ||
81 | 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, | ||
82 | }; | ||
83 | |||
84 | /* Upper case range - Extended latin and greek */ | ||
85 | static signed char UniCaseRangeU1e00[509] = { | ||
86 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */ | ||
87 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */ | ||
88 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */ | ||
89 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */ | ||
90 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */ | ||
91 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */ | ||
92 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */ | ||
93 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */ | ||
94 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */ | ||
95 | 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1, /* 1e90-1e9f */ | ||
96 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */ | ||
97 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */ | ||
98 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */ | ||
99 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */ | ||
100 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */ | ||
101 | 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ | ||
102 | 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */ | ||
103 | 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */ | ||
104 | 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */ | ||
105 | 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */ | ||
106 | 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */ | ||
107 | 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */ | ||
108 | 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */ | ||
109 | 74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, 126, 126, 0, 0, /* 1f70-1f7f */ | ||
110 | 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */ | ||
111 | 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */ | ||
112 | 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */ | ||
113 | 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */ | ||
114 | 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */ | ||
115 | 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */ | ||
116 | 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */ | ||
117 | 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
118 | }; | ||
119 | |||
120 | /* Upper case range - Wide latin */ | ||
121 | static signed char UniCaseRangeUff40[27] = { | ||
122 | 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* ff40-ff4f */ | ||
123 | -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, | ||
124 | }; | ||
125 | |||
126 | /* | ||
127 | * Upper Case Range | ||
128 | */ | ||
129 | const struct UniCaseRange CifsUniUpperRange[] = { | ||
130 | {0x03a0, 0x03ce, UniCaseRangeU03a0}, | ||
131 | {0x0430, 0x045f, UniCaseRangeU0430}, | ||
132 | {0x0490, 0x04cc, UniCaseRangeU0490}, | ||
133 | {0x1e00, 0x1ffc, UniCaseRangeU1e00}, | ||
134 | {0xff40, 0xff5a, UniCaseRangeUff40}, | ||
135 | {0} | ||
136 | }; | ||
137 | #endif | ||
138 | |||
139 | #ifndef UNIUPR_NOLOWER | ||
140 | /* | ||
141 | * Latin lower case | ||
142 | */ | ||
143 | static signed char CifsUniLowerTable[512] = { | ||
144 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ | ||
145 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ | ||
146 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ | ||
147 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ | ||
148 | 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 040-04f */ | ||
149 | 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, /* 050-05f */ | ||
150 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */ | ||
151 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */ | ||
152 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ | ||
153 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ | ||
154 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ | ||
155 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ | ||
156 | 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 0c0-0cf */ | ||
157 | 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0, /* 0d0-0df */ | ||
158 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */ | ||
159 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */ | ||
160 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */ | ||
161 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */ | ||
162 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */ | ||
163 | 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */ | ||
164 | 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */ | ||
165 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */ | ||
166 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */ | ||
167 | 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 0, /* 170-17f */ | ||
168 | 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 0, /* 180-18f */ | ||
169 | 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */ | ||
170 | 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */ | ||
171 | 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */ | ||
172 | 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */ | ||
173 | 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */ | ||
174 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */ | ||
175 | 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */ | ||
176 | }; | ||
177 | |||
178 | /* Lower case range - Greek */ | ||
179 | static signed char UniCaseRangeL0380[44] = { | ||
180 | 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */ | ||
181 | 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 390-39f */ | ||
182 | 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, | ||
183 | }; | ||
184 | |||
185 | /* Lower case range - Cyrillic */ | ||
186 | static signed char UniCaseRangeL0400[48] = { | ||
187 | 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80, /* 400-40f */ | ||
188 | 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 410-41f */ | ||
189 | 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 420-42f */ | ||
190 | }; | ||
191 | |||
192 | /* Lower case range - Extended cyrillic */ | ||
193 | static signed char UniCaseRangeL0490[60] = { | ||
194 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */ | ||
195 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */ | ||
196 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */ | ||
197 | 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, | ||
198 | }; | ||
199 | |||
200 | /* Lower case range - Extended latin and greek */ | ||
201 | static signed char UniCaseRangeL1e00[504] = { | ||
202 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */ | ||
203 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */ | ||
204 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */ | ||
205 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */ | ||
206 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */ | ||
207 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */ | ||
208 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */ | ||
209 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */ | ||
210 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */ | ||
211 | 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */ | ||
212 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */ | ||
213 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */ | ||
214 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */ | ||
215 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */ | ||
216 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */ | ||
217 | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ | ||
218 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */ | ||
219 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */ | ||
220 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */ | ||
221 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */ | ||
222 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */ | ||
223 | 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */ | ||
224 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */ | ||
225 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */ | ||
226 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */ | ||
227 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */ | ||
228 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */ | ||
229 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */ | ||
230 | 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 0, 0, /* 1fc0-1fcf */ | ||
231 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */ | ||
232 | 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 0, 0, /* 1fe0-1fef */ | ||
233 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
234 | }; | ||
235 | |||
236 | /* Lower case range - Wide latin */ | ||
237 | static signed char UniCaseRangeLff20[27] = { | ||
238 | 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* ff20-ff2f */ | ||
239 | 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, | ||
240 | }; | ||
241 | |||
242 | /* | ||
243 | * Lower Case Range | ||
244 | */ | ||
245 | const static struct UniCaseRange CifsUniLowerRange[] = { | ||
246 | 0x0380, 0x03ab, UniCaseRangeL0380, | ||
247 | 0x0400, 0x042f, UniCaseRangeL0400, | ||
248 | 0x0490, 0x04cb, UniCaseRangeL0490, | ||
249 | 0x1e00, 0x1ff7, UniCaseRangeL1e00, | ||
250 | 0xff20, 0xff3a, UniCaseRangeLff20, | ||
251 | 0, 0, 0 | ||
252 | }; | ||
253 | #endif | ||
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c new file mode 100644 index 000000000000..78829e7d8cd0 --- /dev/null +++ b/fs/cifs/cifsencrypt.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifsencrypt.c | ||
3 | * | ||
4 | * Copyright (C) International Business Machines Corp., 2003 | ||
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 | |||
22 | #include <linux/fs.h> | ||
23 | #include "cifspdu.h" | ||
24 | #include "cifsglob.h" | ||
25 | #include "cifs_debug.h" | ||
26 | #include "md5.h" | ||
27 | #include "cifs_unicode.h" | ||
28 | #include "cifsproto.h" | ||
29 | |||
30 | /* Calculate and return the CIFS signature based on the mac key and the smb pdu */ | ||
31 | /* the 16 byte signature must be allocated by the caller */ | ||
32 | /* Note we only use the 1st eight bytes */ | ||
33 | /* Note that the smb header signature field on input contains the | ||
34 | sequence number before this function is called */ | ||
35 | |||
36 | extern void mdfour(unsigned char *out, unsigned char *in, int n); | ||
37 | extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); | ||
38 | |||
39 | static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature) | ||
40 | { | ||
41 | struct MD5Context context; | ||
42 | |||
43 | if((cifs_pdu == NULL) || (signature == NULL)) | ||
44 | return -EINVAL; | ||
45 | |||
46 | MD5Init(&context); | ||
47 | MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); | ||
48 | MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); | ||
49 | MD5Final(signature,&context); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, | ||
54 | __u32 * pexpected_response_sequence_number) | ||
55 | { | ||
56 | int rc = 0; | ||
57 | char smb_signature[20]; | ||
58 | |||
59 | /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */ | ||
60 | /* BB remember to add code to save expected sequence number in midQ entry BB */ | ||
61 | |||
62 | if((cifs_pdu == NULL) || (ses == NULL)) | ||
63 | return -EINVAL; | ||
64 | |||
65 | if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | ||
66 | return rc; | ||
67 | |||
68 | spin_lock(&GlobalMid_Lock); | ||
69 | cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number); | ||
70 | cifs_pdu->Signature.Sequence.Reserved = 0; | ||
71 | |||
72 | *pexpected_response_sequence_number = ses->sequence_number++; | ||
73 | ses->sequence_number++; | ||
74 | spin_unlock(&GlobalMid_Lock); | ||
75 | |||
76 | rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature); | ||
77 | if(rc) | ||
78 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | ||
79 | else | ||
80 | memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); | ||
81 | |||
82 | return rc; | ||
83 | } | ||
84 | |||
85 | int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, | ||
86 | __u32 expected_sequence_number) | ||
87 | { | ||
88 | unsigned int rc; | ||
89 | char server_response_sig[8]; | ||
90 | char what_we_think_sig_should_be[20]; | ||
91 | |||
92 | if((cifs_pdu == NULL) || (mac_key == NULL)) | ||
93 | return -EINVAL; | ||
94 | |||
95 | if (cifs_pdu->Command == SMB_COM_NEGOTIATE) | ||
96 | return 0; | ||
97 | |||
98 | if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { | ||
99 | struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu; | ||
100 | if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | /* BB what if signatures are supposed to be on for session but server does not | ||
105 | send one? BB */ | ||
106 | |||
107 | /* Do not need to verify session setups with signature "BSRSPYL " */ | ||
108 | if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0) | ||
109 | cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command)); | ||
110 | |||
111 | /* save off the origiginal signature so we can modify the smb and check | ||
112 | its signature against what the server sent */ | ||
113 | memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8); | ||
114 | |||
115 | cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(expected_sequence_number); | ||
116 | cifs_pdu->Signature.Sequence.Reserved = 0; | ||
117 | |||
118 | rc = cifs_calculate_signature(cifs_pdu, mac_key, | ||
119 | what_we_think_sig_should_be); | ||
120 | |||
121 | if(rc) | ||
122 | return rc; | ||
123 | |||
124 | |||
125 | /* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */ | ||
126 | |||
127 | if(memcmp(server_response_sig, what_we_think_sig_should_be, 8)) | ||
128 | return -EACCES; | ||
129 | else | ||
130 | return 0; | ||
131 | |||
132 | } | ||
133 | |||
134 | /* We fill in key by putting in 40 byte array which was allocated by caller */ | ||
135 | int cifs_calculate_mac_key(char * key, const char * rn, const char * password) | ||
136 | { | ||
137 | char temp_key[16]; | ||
138 | if ((key == NULL) || (rn == NULL)) | ||
139 | return -EINVAL; | ||
140 | |||
141 | E_md4hash(password, temp_key); | ||
142 | mdfour(key,temp_key,16); | ||
143 | memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE); | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info) | ||
148 | { | ||
149 | char temp_hash[16]; | ||
150 | struct HMACMD5Context ctx; | ||
151 | char * ucase_buf; | ||
152 | wchar_t * unicode_buf; | ||
153 | unsigned int i,user_name_len,dom_name_len; | ||
154 | |||
155 | if(ses == NULL) | ||
156 | return -EINVAL; | ||
157 | |||
158 | E_md4hash(ses->password, temp_hash); | ||
159 | |||
160 | hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); | ||
161 | user_name_len = strlen(ses->userName); | ||
162 | if(user_name_len > MAX_USERNAME_SIZE) | ||
163 | return -EINVAL; | ||
164 | dom_name_len = strlen(ses->domainName); | ||
165 | if(dom_name_len > MAX_USERNAME_SIZE) | ||
166 | return -EINVAL; | ||
167 | |||
168 | ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); | ||
169 | if(ucase_buf == NULL) | ||
170 | return -ENOMEM; | ||
171 | unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); | ||
172 | if(unicode_buf == NULL) { | ||
173 | kfree(ucase_buf); | ||
174 | return -ENOMEM; | ||
175 | } | ||
176 | |||
177 | for(i=0;i<user_name_len;i++) | ||
178 | ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]]; | ||
179 | ucase_buf[i] = 0; | ||
180 | user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); | ||
181 | unicode_buf[user_name_len] = 0; | ||
182 | user_name_len++; | ||
183 | |||
184 | for(i=0;i<dom_name_len;i++) | ||
185 | ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]]; | ||
186 | ucase_buf[i] = 0; | ||
187 | dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); | ||
188 | |||
189 | unicode_buf[user_name_len + dom_name_len] = 0; | ||
190 | hmac_md5_update((const unsigned char *) unicode_buf, | ||
191 | (user_name_len+dom_name_len)*2,&ctx); | ||
192 | |||
193 | hmac_md5_final(ses->mac_signing_key,&ctx); | ||
194 | kfree(ucase_buf); | ||
195 | kfree(unicode_buf); | ||
196 | return 0; | ||
197 | } | ||
198 | void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) | ||
199 | { | ||
200 | struct HMACMD5Context context; | ||
201 | memcpy(v2_session_response + 8, ses->server->cryptKey,8); | ||
202 | /* gen_blob(v2_session_response + 16); */ | ||
203 | hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context); | ||
204 | |||
205 | hmac_md5_update(ses->server->cryptKey,8,&context); | ||
206 | /* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ | ||
207 | |||
208 | hmac_md5_final(v2_session_response,&context); | ||
209 | } | ||
diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h new file mode 100644 index 000000000000..03e359b32861 --- /dev/null +++ b/fs/cifs/cifsencrypt.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifsencrypt.h | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2005 | ||
5 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
6 | * | ||
7 | * Externs for misc. small encryption routines | ||
8 | * so we do not have to put them in cifsproto.h | ||
9 | * | ||
10 | * This library is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU Lesser General Public License as published | ||
12 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This library is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
18 | * the GNU Lesser General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU Lesser General Public License | ||
21 | * along with this library; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | /* md4.c */ | ||
26 | extern void mdfour(unsigned char *out, unsigned char *in, int n); | ||
27 | /* smbdes.c */ | ||
28 | extern void E_P16(unsigned char *p14, unsigned char *p16); | ||
29 | extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24); | ||
30 | extern void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out); | ||
31 | extern void E_old_pw_hash(unsigned char *, unsigned char *, unsigned char *); | ||
32 | |||
33 | |||
34 | |||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c new file mode 100644 index 000000000000..5082fce3c566 --- /dev/null +++ b/fs/cifs/cifsfs.c | |||
@@ -0,0 +1,913 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifsfs.c | ||
3 | * | ||
4 | * Copyright (C) International Business Machines Corp., 2002,2004 | ||
5 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
6 | * | ||
7 | * Common Internet FileSystem (CIFS) client | ||
8 | * | ||
9 | * This library is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU Lesser General Public License as published | ||
11 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This library is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
17 | * the GNU Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public License | ||
20 | * along with this library; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | /* Note that BB means BUGBUG (ie something to fix eventually) */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/fs.h> | ||
28 | #include <linux/mount.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/list.h> | ||
32 | #include <linux/seq_file.h> | ||
33 | #include <linux/vfs.h> | ||
34 | #include <linux/mempool.h> | ||
35 | #include "cifsfs.h" | ||
36 | #include "cifspdu.h" | ||
37 | #define DECLARE_GLOBALS_HERE | ||
38 | #include "cifsglob.h" | ||
39 | #include "cifsproto.h" | ||
40 | #include "cifs_debug.h" | ||
41 | #include "cifs_fs_sb.h" | ||
42 | #include <linux/mm.h> | ||
43 | #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ | ||
44 | |||
45 | #ifdef CONFIG_CIFS_QUOTA | ||
46 | static struct quotactl_ops cifs_quotactl_ops; | ||
47 | #endif | ||
48 | |||
49 | int cifsFYI = 0; | ||
50 | int cifsERROR = 1; | ||
51 | int traceSMB = 0; | ||
52 | unsigned int oplockEnabled = 1; | ||
53 | unsigned int experimEnabled = 0; | ||
54 | unsigned int linuxExtEnabled = 1; | ||
55 | unsigned int lookupCacheEnabled = 1; | ||
56 | unsigned int multiuser_mount = 0; | ||
57 | unsigned int extended_security = 0; | ||
58 | unsigned int ntlmv2_support = 0; | ||
59 | unsigned int sign_CIFS_PDUs = 1; | ||
60 | extern struct task_struct * oplockThread; /* remove sparse warning */ | ||
61 | struct task_struct * oplockThread = NULL; | ||
62 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; | ||
63 | module_param(CIFSMaxBufSize, int, 0); | ||
64 | MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); | ||
65 | unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL; | ||
66 | module_param(cifs_min_rcv, int, 0); | ||
67 | MODULE_PARM_DESC(cifs_min_rcv,"Network buffers in pool. Default: 4 Range: 1 to 64"); | ||
68 | unsigned int cifs_min_small = 30; | ||
69 | module_param(cifs_min_small, int, 0); | ||
70 | MODULE_PARM_DESC(cifs_min_small,"Small network buffers in pool. Default: 30 Range: 2 to 256"); | ||
71 | unsigned int cifs_max_pending = CIFS_MAX_REQ; | ||
72 | module_param(cifs_max_pending, int, 0); | ||
73 | MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); | ||
74 | |||
75 | static DECLARE_COMPLETION(cifs_oplock_exited); | ||
76 | |||
77 | extern mempool_t *cifs_sm_req_poolp; | ||
78 | extern mempool_t *cifs_req_poolp; | ||
79 | extern mempool_t *cifs_mid_poolp; | ||
80 | |||
81 | extern kmem_cache_t *cifs_oplock_cachep; | ||
82 | |||
83 | static int | ||
84 | cifs_read_super(struct super_block *sb, void *data, | ||
85 | const char *devname, int silent) | ||
86 | { | ||
87 | struct inode *inode; | ||
88 | struct cifs_sb_info *cifs_sb; | ||
89 | int rc = 0; | ||
90 | |||
91 | sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */ | ||
92 | sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL); | ||
93 | cifs_sb = CIFS_SB(sb); | ||
94 | if(cifs_sb == NULL) | ||
95 | return -ENOMEM; | ||
96 | else | ||
97 | memset(cifs_sb,0,sizeof(struct cifs_sb_info)); | ||
98 | |||
99 | |||
100 | rc = cifs_mount(sb, cifs_sb, data, devname); | ||
101 | |||
102 | if (rc) { | ||
103 | if (!silent) | ||
104 | cERROR(1, | ||
105 | ("cifs_mount failed w/return code = %d", rc)); | ||
106 | goto out_mount_failed; | ||
107 | } | ||
108 | |||
109 | sb->s_magic = CIFS_MAGIC_NUMBER; | ||
110 | sb->s_op = &cifs_super_ops; | ||
111 | /* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) | ||
112 | sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ | ||
113 | #ifdef CONFIG_CIFS_QUOTA | ||
114 | sb->s_qcop = &cifs_quotactl_ops; | ||
115 | #endif | ||
116 | sb->s_blocksize = CIFS_MAX_MSGSIZE; | ||
117 | sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ | ||
118 | inode = iget(sb, ROOT_I); | ||
119 | |||
120 | if (!inode) { | ||
121 | rc = -ENOMEM; | ||
122 | goto out_no_root; | ||
123 | } | ||
124 | |||
125 | sb->s_root = d_alloc_root(inode); | ||
126 | |||
127 | if (!sb->s_root) { | ||
128 | rc = -ENOMEM; | ||
129 | goto out_no_root; | ||
130 | } | ||
131 | |||
132 | return 0; | ||
133 | |||
134 | out_no_root: | ||
135 | cERROR(1, ("cifs_read_super: get root inode failed")); | ||
136 | if (inode) | ||
137 | iput(inode); | ||
138 | |||
139 | out_mount_failed: | ||
140 | if(cifs_sb) { | ||
141 | if(cifs_sb->local_nls) | ||
142 | unload_nls(cifs_sb->local_nls); | ||
143 | kfree(cifs_sb); | ||
144 | } | ||
145 | return rc; | ||
146 | } | ||
147 | |||
148 | static void | ||
149 | cifs_put_super(struct super_block *sb) | ||
150 | { | ||
151 | int rc = 0; | ||
152 | struct cifs_sb_info *cifs_sb; | ||
153 | |||
154 | cFYI(1, ("In cifs_put_super")); | ||
155 | cifs_sb = CIFS_SB(sb); | ||
156 | if(cifs_sb == NULL) { | ||
157 | cFYI(1,("Empty cifs superblock info passed to unmount")); | ||
158 | return; | ||
159 | } | ||
160 | rc = cifs_umount(sb, cifs_sb); | ||
161 | if (rc) { | ||
162 | cERROR(1, ("cifs_umount failed with return code %d", rc)); | ||
163 | } | ||
164 | unload_nls(cifs_sb->local_nls); | ||
165 | kfree(cifs_sb); | ||
166 | return; | ||
167 | } | ||
168 | |||
169 | static int | ||
170 | cifs_statfs(struct super_block *sb, struct kstatfs *buf) | ||
171 | { | ||
172 | int xid, rc = -EOPNOTSUPP; | ||
173 | struct cifs_sb_info *cifs_sb; | ||
174 | struct cifsTconInfo *pTcon; | ||
175 | |||
176 | xid = GetXid(); | ||
177 | |||
178 | cifs_sb = CIFS_SB(sb); | ||
179 | pTcon = cifs_sb->tcon; | ||
180 | |||
181 | buf->f_type = CIFS_MAGIC_NUMBER; | ||
182 | |||
183 | /* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */ | ||
184 | buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would presumably | ||
185 | be length of total path, note that some servers may be | ||
186 | able to support more than this, but best to be safe | ||
187 | since Win2k and others can not handle very long filenames */ | ||
188 | buf->f_files = 0; /* undefined */ | ||
189 | buf->f_ffree = 0; /* unlimited */ | ||
190 | |||
191 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
192 | /* BB we could add a second check for a QFS Unix capability bit */ | ||
193 | if (pTcon->ses->capabilities & CAP_UNIX) | ||
194 | rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf, cifs_sb->local_nls); | ||
195 | |||
196 | /* Only need to call the old QFSInfo if failed | ||
197 | on newer one */ | ||
198 | if(rc) | ||
199 | #endif /* CIFS_EXPERIMENTAL */ | ||
200 | rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls); | ||
201 | |||
202 | /* | ||
203 | int f_type; | ||
204 | __fsid_t f_fsid; | ||
205 | int f_namelen; */ | ||
206 | /* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */ | ||
207 | FreeXid(xid); | ||
208 | return 0; /* always return success? what if volume is no longer available? */ | ||
209 | } | ||
210 | |||
211 | static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd) | ||
212 | { | ||
213 | struct cifs_sb_info *cifs_sb; | ||
214 | |||
215 | cifs_sb = CIFS_SB(inode->i_sb); | ||
216 | |||
217 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { | ||
218 | return 0; | ||
219 | } else /* file mode might have been restricted at mount time | ||
220 | on the client (above and beyond ACL on servers) for | ||
221 | servers which do not support setting and viewing mode bits, | ||
222 | so allowing client to check permissions is useful */ | ||
223 | return generic_permission(inode, mask, NULL); | ||
224 | } | ||
225 | |||
226 | static kmem_cache_t *cifs_inode_cachep; | ||
227 | static kmem_cache_t *cifs_req_cachep; | ||
228 | static kmem_cache_t *cifs_mid_cachep; | ||
229 | kmem_cache_t *cifs_oplock_cachep; | ||
230 | static kmem_cache_t *cifs_sm_req_cachep; | ||
231 | mempool_t *cifs_sm_req_poolp; | ||
232 | mempool_t *cifs_req_poolp; | ||
233 | mempool_t *cifs_mid_poolp; | ||
234 | |||
235 | static struct inode * | ||
236 | cifs_alloc_inode(struct super_block *sb) | ||
237 | { | ||
238 | struct cifsInodeInfo *cifs_inode; | ||
239 | cifs_inode = kmem_cache_alloc(cifs_inode_cachep, SLAB_KERNEL); | ||
240 | if (!cifs_inode) | ||
241 | return NULL; | ||
242 | cifs_inode->cifsAttrs = 0x20; /* default */ | ||
243 | atomic_set(&cifs_inode->inUse, 0); | ||
244 | cifs_inode->time = 0; | ||
245 | /* Until the file is open and we have gotten oplock | ||
246 | info back from the server, can not assume caching of | ||
247 | file data or metadata */ | ||
248 | cifs_inode->clientCanCacheRead = FALSE; | ||
249 | cifs_inode->clientCanCacheAll = FALSE; | ||
250 | cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; | ||
251 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | ||
252 | |||
253 | INIT_LIST_HEAD(&cifs_inode->openFileList); | ||
254 | return &cifs_inode->vfs_inode; | ||
255 | } | ||
256 | |||
257 | static void | ||
258 | cifs_destroy_inode(struct inode *inode) | ||
259 | { | ||
260 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * cifs_show_options() is for displaying mount options in /proc/mounts. | ||
265 | * Not all settable options are displayed but most of the important | ||
266 | * ones are. | ||
267 | */ | ||
268 | static int | ||
269 | cifs_show_options(struct seq_file *s, struct vfsmount *m) | ||
270 | { | ||
271 | struct cifs_sb_info *cifs_sb; | ||
272 | |||
273 | cifs_sb = CIFS_SB(m->mnt_sb); | ||
274 | |||
275 | if (cifs_sb) { | ||
276 | if (cifs_sb->tcon) { | ||
277 | seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); | ||
278 | if (cifs_sb->tcon->ses) { | ||
279 | if (cifs_sb->tcon->ses->userName) | ||
280 | seq_printf(s, ",username=%s", | ||
281 | cifs_sb->tcon->ses->userName); | ||
282 | if(cifs_sb->tcon->ses->domainName) | ||
283 | seq_printf(s, ",domain=%s", | ||
284 | cifs_sb->tcon->ses->domainName); | ||
285 | } | ||
286 | } | ||
287 | seq_printf(s, ",rsize=%d",cifs_sb->rsize); | ||
288 | seq_printf(s, ",wsize=%d",cifs_sb->wsize); | ||
289 | } | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | #ifdef CONFIG_CIFS_QUOTA | ||
294 | int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid, | ||
295 | struct fs_disk_quota * pdquota) | ||
296 | { | ||
297 | int xid; | ||
298 | int rc = 0; | ||
299 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
300 | struct cifsTconInfo *pTcon; | ||
301 | |||
302 | if(cifs_sb) | ||
303 | pTcon = cifs_sb->tcon; | ||
304 | else | ||
305 | return -EIO; | ||
306 | |||
307 | |||
308 | xid = GetXid(); | ||
309 | if(pTcon) { | ||
310 | cFYI(1,("set type: 0x%x id: %d",quota_type,qid)); | ||
311 | } else { | ||
312 | return -EIO; | ||
313 | } | ||
314 | |||
315 | FreeXid(xid); | ||
316 | return rc; | ||
317 | } | ||
318 | |||
319 | int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid, | ||
320 | struct fs_disk_quota * pdquota) | ||
321 | { | ||
322 | int xid; | ||
323 | int rc = 0; | ||
324 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
325 | struct cifsTconInfo *pTcon; | ||
326 | |||
327 | if(cifs_sb) | ||
328 | pTcon = cifs_sb->tcon; | ||
329 | else | ||
330 | return -EIO; | ||
331 | |||
332 | xid = GetXid(); | ||
333 | if(pTcon) { | ||
334 | cFYI(1,("set type: 0x%x id: %d",quota_type,qid)); | ||
335 | } else { | ||
336 | rc = -EIO; | ||
337 | } | ||
338 | |||
339 | FreeXid(xid); | ||
340 | return rc; | ||
341 | } | ||
342 | |||
343 | int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation) | ||
344 | { | ||
345 | int xid; | ||
346 | int rc = 0; | ||
347 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
348 | struct cifsTconInfo *pTcon; | ||
349 | |||
350 | if(cifs_sb) | ||
351 | pTcon = cifs_sb->tcon; | ||
352 | else | ||
353 | return -EIO; | ||
354 | |||
355 | xid = GetXid(); | ||
356 | if(pTcon) { | ||
357 | cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation)); | ||
358 | } else { | ||
359 | rc = -EIO; | ||
360 | } | ||
361 | |||
362 | FreeXid(xid); | ||
363 | return rc; | ||
364 | } | ||
365 | |||
366 | int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats) | ||
367 | { | ||
368 | int xid; | ||
369 | int rc = 0; | ||
370 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
371 | struct cifsTconInfo *pTcon; | ||
372 | |||
373 | if(cifs_sb) { | ||
374 | pTcon = cifs_sb->tcon; | ||
375 | } else { | ||
376 | return -EIO; | ||
377 | } | ||
378 | xid = GetXid(); | ||
379 | if(pTcon) { | ||
380 | cFYI(1,("pqstats %p",qstats)); | ||
381 | } else { | ||
382 | rc = -EIO; | ||
383 | } | ||
384 | |||
385 | FreeXid(xid); | ||
386 | return rc; | ||
387 | } | ||
388 | |||
389 | static struct quotactl_ops cifs_quotactl_ops = { | ||
390 | .set_xquota = cifs_xquota_set, | ||
391 | .get_xquota = cifs_xquota_set, | ||
392 | .set_xstate = cifs_xstate_set, | ||
393 | .get_xstate = cifs_xstate_get, | ||
394 | }; | ||
395 | #endif | ||
396 | |||
397 | static int cifs_remount(struct super_block *sb, int *flags, char *data) | ||
398 | { | ||
399 | *flags |= MS_NODIRATIME; | ||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | struct super_operations cifs_super_ops = { | ||
404 | .read_inode = cifs_read_inode, | ||
405 | .put_super = cifs_put_super, | ||
406 | .statfs = cifs_statfs, | ||
407 | .alloc_inode = cifs_alloc_inode, | ||
408 | .destroy_inode = cifs_destroy_inode, | ||
409 | /* .drop_inode = generic_delete_inode, | ||
410 | .delete_inode = cifs_delete_inode, *//* Do not need the above two functions | ||
411 | unless later we add lazy close of inodes or unless the kernel forgets to call | ||
412 | us with the same number of releases (closes) as opens */ | ||
413 | .show_options = cifs_show_options, | ||
414 | /* .umount_begin = cifs_umount_begin, *//* consider adding in the future */ | ||
415 | .remount_fs = cifs_remount, | ||
416 | }; | ||
417 | |||
418 | static struct super_block * | ||
419 | cifs_get_sb(struct file_system_type *fs_type, | ||
420 | int flags, const char *dev_name, void *data) | ||
421 | { | ||
422 | int rc; | ||
423 | struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL); | ||
424 | |||
425 | cFYI(1, ("Devname: %s flags: %d ", dev_name, flags)); | ||
426 | |||
427 | if (IS_ERR(sb)) | ||
428 | return sb; | ||
429 | |||
430 | sb->s_flags = flags; | ||
431 | |||
432 | rc = cifs_read_super(sb, data, dev_name, flags & MS_VERBOSE ? 1 : 0); | ||
433 | if (rc) { | ||
434 | up_write(&sb->s_umount); | ||
435 | deactivate_super(sb); | ||
436 | return ERR_PTR(rc); | ||
437 | } | ||
438 | sb->s_flags |= MS_ACTIVE; | ||
439 | return sb; | ||
440 | } | ||
441 | |||
442 | static ssize_t | ||
443 | cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size, | ||
444 | loff_t * poffset) | ||
445 | { | ||
446 | if(file->f_dentry == NULL) | ||
447 | return -EIO; | ||
448 | else if(file->f_dentry->d_inode == NULL) | ||
449 | return -EIO; | ||
450 | |||
451 | cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset)); | ||
452 | |||
453 | if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) { | ||
454 | return generic_file_read(file,read_data,read_size,poffset); | ||
455 | } else { | ||
456 | /* BB do we need to lock inode from here until after invalidate? */ | ||
457 | /* if(file->f_dentry->d_inode->i_mapping) { | ||
458 | filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); | ||
459 | filemap_fdatawait(file->f_dentry->d_inode->i_mapping); | ||
460 | }*/ | ||
461 | /* cifs_revalidate(file->f_dentry);*/ /* BB fixme */ | ||
462 | |||
463 | /* BB we should make timer configurable - perhaps | ||
464 | by simply calling cifs_revalidate here */ | ||
465 | /* invalidate_remote_inode(file->f_dentry->d_inode);*/ | ||
466 | return generic_file_read(file,read_data,read_size,poffset); | ||
467 | } | ||
468 | } | ||
469 | |||
470 | static ssize_t | ||
471 | cifs_write_wrapper(struct file * file, const char __user *write_data, | ||
472 | size_t write_size, loff_t * poffset) | ||
473 | { | ||
474 | ssize_t written; | ||
475 | |||
476 | if(file->f_dentry == NULL) | ||
477 | return -EIO; | ||
478 | else if(file->f_dentry->d_inode == NULL) | ||
479 | return -EIO; | ||
480 | |||
481 | cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset)); | ||
482 | |||
483 | written = generic_file_write(file,write_data,write_size,poffset); | ||
484 | if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) { | ||
485 | if(file->f_dentry->d_inode->i_mapping) { | ||
486 | filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); | ||
487 | } | ||
488 | } | ||
489 | return written; | ||
490 | } | ||
491 | |||
492 | |||
493 | static struct file_system_type cifs_fs_type = { | ||
494 | .owner = THIS_MODULE, | ||
495 | .name = "cifs", | ||
496 | .get_sb = cifs_get_sb, | ||
497 | .kill_sb = kill_anon_super, | ||
498 | /* .fs_flags */ | ||
499 | }; | ||
500 | struct inode_operations cifs_dir_inode_ops = { | ||
501 | .create = cifs_create, | ||
502 | .lookup = cifs_lookup, | ||
503 | .getattr = cifs_getattr, | ||
504 | .unlink = cifs_unlink, | ||
505 | .link = cifs_hardlink, | ||
506 | .mkdir = cifs_mkdir, | ||
507 | .rmdir = cifs_rmdir, | ||
508 | .rename = cifs_rename, | ||
509 | .permission = cifs_permission, | ||
510 | /* revalidate:cifs_revalidate, */ | ||
511 | .setattr = cifs_setattr, | ||
512 | .symlink = cifs_symlink, | ||
513 | .mknod = cifs_mknod, | ||
514 | #ifdef CONFIG_CIFS_XATTR | ||
515 | .setxattr = cifs_setxattr, | ||
516 | .getxattr = cifs_getxattr, | ||
517 | .listxattr = cifs_listxattr, | ||
518 | .removexattr = cifs_removexattr, | ||
519 | #endif | ||
520 | }; | ||
521 | |||
522 | struct inode_operations cifs_file_inode_ops = { | ||
523 | /* revalidate:cifs_revalidate, */ | ||
524 | .setattr = cifs_setattr, | ||
525 | .getattr = cifs_getattr, /* do we need this anymore? */ | ||
526 | .rename = cifs_rename, | ||
527 | .permission = cifs_permission, | ||
528 | #ifdef CONFIG_CIFS_XATTR | ||
529 | .setxattr = cifs_setxattr, | ||
530 | .getxattr = cifs_getxattr, | ||
531 | .listxattr = cifs_listxattr, | ||
532 | .removexattr = cifs_removexattr, | ||
533 | #endif | ||
534 | }; | ||
535 | |||
536 | struct inode_operations cifs_symlink_inode_ops = { | ||
537 | .readlink = generic_readlink, | ||
538 | .follow_link = cifs_follow_link, | ||
539 | .put_link = cifs_put_link, | ||
540 | .permission = cifs_permission, | ||
541 | /* BB add the following two eventually */ | ||
542 | /* revalidate: cifs_revalidate, | ||
543 | setattr: cifs_notify_change, *//* BB do we need notify change */ | ||
544 | #ifdef CONFIG_CIFS_XATTR | ||
545 | .setxattr = cifs_setxattr, | ||
546 | .getxattr = cifs_getxattr, | ||
547 | .listxattr = cifs_listxattr, | ||
548 | .removexattr = cifs_removexattr, | ||
549 | #endif | ||
550 | }; | ||
551 | |||
552 | struct file_operations cifs_file_ops = { | ||
553 | .read = cifs_read_wrapper, | ||
554 | .write = cifs_write_wrapper, | ||
555 | .open = cifs_open, | ||
556 | .release = cifs_close, | ||
557 | .lock = cifs_lock, | ||
558 | .fsync = cifs_fsync, | ||
559 | .flush = cifs_flush, | ||
560 | .mmap = cifs_file_mmap, | ||
561 | .sendfile = generic_file_sendfile, | ||
562 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
563 | .readv = generic_file_readv, | ||
564 | .writev = generic_file_writev, | ||
565 | .aio_read = generic_file_aio_read, | ||
566 | .aio_write = generic_file_aio_write, | ||
567 | .dir_notify = cifs_dir_notify, | ||
568 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
569 | }; | ||
570 | |||
571 | struct file_operations cifs_file_direct_ops = { | ||
572 | /* no mmap, no aio, no readv - | ||
573 | BB reevaluate whether they can be done with directio, no cache */ | ||
574 | .read = cifs_user_read, | ||
575 | .write = cifs_user_write, | ||
576 | .open = cifs_open, | ||
577 | .release = cifs_close, | ||
578 | .lock = cifs_lock, | ||
579 | .fsync = cifs_fsync, | ||
580 | .flush = cifs_flush, | ||
581 | .sendfile = generic_file_sendfile, /* BB removeme BB */ | ||
582 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
583 | .dir_notify = cifs_dir_notify, | ||
584 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
585 | }; | ||
586 | |||
587 | struct file_operations cifs_dir_ops = { | ||
588 | .readdir = cifs_readdir, | ||
589 | .release = cifs_closedir, | ||
590 | .read = generic_read_dir, | ||
591 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
592 | .dir_notify = cifs_dir_notify, | ||
593 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
594 | }; | ||
595 | |||
596 | static void | ||
597 | cifs_init_once(void *inode, kmem_cache_t * cachep, unsigned long flags) | ||
598 | { | ||
599 | struct cifsInodeInfo *cifsi = inode; | ||
600 | |||
601 | if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == | ||
602 | SLAB_CTOR_CONSTRUCTOR) { | ||
603 | inode_init_once(&cifsi->vfs_inode); | ||
604 | INIT_LIST_HEAD(&cifsi->lockList); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static int | ||
609 | cifs_init_inodecache(void) | ||
610 | { | ||
611 | cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", | ||
612 | sizeof (struct cifsInodeInfo), | ||
613 | 0, SLAB_RECLAIM_ACCOUNT, | ||
614 | cifs_init_once, NULL); | ||
615 | if (cifs_inode_cachep == NULL) | ||
616 | return -ENOMEM; | ||
617 | |||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | static void | ||
622 | cifs_destroy_inodecache(void) | ||
623 | { | ||
624 | if (kmem_cache_destroy(cifs_inode_cachep)) | ||
625 | printk(KERN_WARNING "cifs_inode_cache: error freeing\n"); | ||
626 | } | ||
627 | |||
628 | static int | ||
629 | cifs_init_request_bufs(void) | ||
630 | { | ||
631 | if(CIFSMaxBufSize < 8192) { | ||
632 | /* Buffer size can not be smaller than 2 * PATH_MAX since maximum | ||
633 | Unicode path name has to fit in any SMB/CIFS path based frames */ | ||
634 | CIFSMaxBufSize = 8192; | ||
635 | } else if (CIFSMaxBufSize > 1024*127) { | ||
636 | CIFSMaxBufSize = 1024 * 127; | ||
637 | } else { | ||
638 | CIFSMaxBufSize &= 0x1FE00; /* Round size to even 512 byte mult*/ | ||
639 | } | ||
640 | /* cERROR(1,("CIFSMaxBufSize %d 0x%x",CIFSMaxBufSize,CIFSMaxBufSize)); */ | ||
641 | cifs_req_cachep = kmem_cache_create("cifs_request", | ||
642 | CIFSMaxBufSize + | ||
643 | MAX_CIFS_HDR_SIZE, 0, | ||
644 | SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
645 | if (cifs_req_cachep == NULL) | ||
646 | return -ENOMEM; | ||
647 | |||
648 | if(cifs_min_rcv < 1) | ||
649 | cifs_min_rcv = 1; | ||
650 | else if (cifs_min_rcv > 64) { | ||
651 | cifs_min_rcv = 64; | ||
652 | cERROR(1,("cifs_min_rcv set to maximum (64)")); | ||
653 | } | ||
654 | |||
655 | cifs_req_poolp = mempool_create(cifs_min_rcv, | ||
656 | mempool_alloc_slab, | ||
657 | mempool_free_slab, | ||
658 | cifs_req_cachep); | ||
659 | |||
660 | if(cifs_req_poolp == NULL) { | ||
661 | kmem_cache_destroy(cifs_req_cachep); | ||
662 | return -ENOMEM; | ||
663 | } | ||
664 | /* 256 (MAX_CIFS_HDR_SIZE bytes is enough for most SMB responses and | ||
665 | almost all handle based requests (but not write response, nor is it | ||
666 | sufficient for path based requests). A smaller size would have | ||
667 | been more efficient (compacting multiple slab items on one 4k page) | ||
668 | for the case in which debug was on, but this larger size allows | ||
669 | more SMBs to use small buffer alloc and is still much more | ||
670 | efficient to alloc 1 per page off the slab compared to 17K (5page) | ||
671 | alloc of large cifs buffers even when page debugging is on */ | ||
672 | cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq", | ||
673 | MAX_CIFS_HDR_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
674 | if (cifs_sm_req_cachep == NULL) { | ||
675 | mempool_destroy(cifs_req_poolp); | ||
676 | kmem_cache_destroy(cifs_req_cachep); | ||
677 | return -ENOMEM; | ||
678 | } | ||
679 | |||
680 | if(cifs_min_small < 2) | ||
681 | cifs_min_small = 2; | ||
682 | else if (cifs_min_small > 256) { | ||
683 | cifs_min_small = 256; | ||
684 | cFYI(1,("cifs_min_small set to maximum (256)")); | ||
685 | } | ||
686 | |||
687 | cifs_sm_req_poolp = mempool_create(cifs_min_small, | ||
688 | mempool_alloc_slab, | ||
689 | mempool_free_slab, | ||
690 | cifs_sm_req_cachep); | ||
691 | |||
692 | if(cifs_sm_req_poolp == NULL) { | ||
693 | mempool_destroy(cifs_req_poolp); | ||
694 | kmem_cache_destroy(cifs_req_cachep); | ||
695 | kmem_cache_destroy(cifs_sm_req_cachep); | ||
696 | return -ENOMEM; | ||
697 | } | ||
698 | |||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | static void | ||
703 | cifs_destroy_request_bufs(void) | ||
704 | { | ||
705 | mempool_destroy(cifs_req_poolp); | ||
706 | if (kmem_cache_destroy(cifs_req_cachep)) | ||
707 | printk(KERN_WARNING | ||
708 | "cifs_destroy_request_cache: error not all structures were freed\n"); | ||
709 | mempool_destroy(cifs_sm_req_poolp); | ||
710 | if (kmem_cache_destroy(cifs_sm_req_cachep)) | ||
711 | printk(KERN_WARNING | ||
712 | "cifs_destroy_request_cache: cifs_small_rq free error\n"); | ||
713 | } | ||
714 | |||
715 | static int | ||
716 | cifs_init_mids(void) | ||
717 | { | ||
718 | cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", | ||
719 | sizeof (struct mid_q_entry), 0, | ||
720 | SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
721 | if (cifs_mid_cachep == NULL) | ||
722 | return -ENOMEM; | ||
723 | |||
724 | cifs_mid_poolp = mempool_create(3 /* a reasonable min simultan opers */, | ||
725 | mempool_alloc_slab, | ||
726 | mempool_free_slab, | ||
727 | cifs_mid_cachep); | ||
728 | if(cifs_mid_poolp == NULL) { | ||
729 | kmem_cache_destroy(cifs_mid_cachep); | ||
730 | return -ENOMEM; | ||
731 | } | ||
732 | |||
733 | cifs_oplock_cachep = kmem_cache_create("cifs_oplock_structs", | ||
734 | sizeof (struct oplock_q_entry), 0, | ||
735 | SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
736 | if (cifs_oplock_cachep == NULL) { | ||
737 | kmem_cache_destroy(cifs_mid_cachep); | ||
738 | mempool_destroy(cifs_mid_poolp); | ||
739 | return -ENOMEM; | ||
740 | } | ||
741 | |||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static void | ||
746 | cifs_destroy_mids(void) | ||
747 | { | ||
748 | mempool_destroy(cifs_mid_poolp); | ||
749 | if (kmem_cache_destroy(cifs_mid_cachep)) | ||
750 | printk(KERN_WARNING | ||
751 | "cifs_destroy_mids: error not all structures were freed\n"); | ||
752 | |||
753 | if (kmem_cache_destroy(cifs_oplock_cachep)) | ||
754 | printk(KERN_WARNING | ||
755 | "error not all oplock structures were freed\n"); | ||
756 | } | ||
757 | |||
758 | static int cifs_oplock_thread(void * dummyarg) | ||
759 | { | ||
760 | struct oplock_q_entry * oplock_item; | ||
761 | struct cifsTconInfo *pTcon; | ||
762 | struct inode * inode; | ||
763 | __u16 netfid; | ||
764 | int rc; | ||
765 | |||
766 | daemonize("cifsoplockd"); | ||
767 | allow_signal(SIGTERM); | ||
768 | |||
769 | oplockThread = current; | ||
770 | do { | ||
771 | set_current_state(TASK_INTERRUPTIBLE); | ||
772 | |||
773 | schedule_timeout(1*HZ); | ||
774 | spin_lock(&GlobalMid_Lock); | ||
775 | if(list_empty(&GlobalOplock_Q)) { | ||
776 | spin_unlock(&GlobalMid_Lock); | ||
777 | set_current_state(TASK_INTERRUPTIBLE); | ||
778 | schedule_timeout(39*HZ); | ||
779 | } else { | ||
780 | oplock_item = list_entry(GlobalOplock_Q.next, | ||
781 | struct oplock_q_entry, qhead); | ||
782 | if(oplock_item) { | ||
783 | cFYI(1,("found oplock item to write out")); | ||
784 | pTcon = oplock_item->tcon; | ||
785 | inode = oplock_item->pinode; | ||
786 | netfid = oplock_item->netfid; | ||
787 | spin_unlock(&GlobalMid_Lock); | ||
788 | DeleteOplockQEntry(oplock_item); | ||
789 | /* can not grab inode sem here since it would | ||
790 | deadlock when oplock received on delete | ||
791 | since vfs_unlink holds the i_sem across | ||
792 | the call */ | ||
793 | /* down(&inode->i_sem);*/ | ||
794 | if (S_ISREG(inode->i_mode)) { | ||
795 | rc = filemap_fdatawrite(inode->i_mapping); | ||
796 | if(CIFS_I(inode)->clientCanCacheRead == 0) { | ||
797 | filemap_fdatawait(inode->i_mapping); | ||
798 | invalidate_remote_inode(inode); | ||
799 | } | ||
800 | } else | ||
801 | rc = 0; | ||
802 | /* up(&inode->i_sem);*/ | ||
803 | if (rc) | ||
804 | CIFS_I(inode)->write_behind_rc = rc; | ||
805 | cFYI(1,("Oplock flush inode %p rc %d",inode,rc)); | ||
806 | |||
807 | /* releasing a stale oplock after recent reconnection | ||
808 | of smb session using a now incorrect file | ||
809 | handle is not a data integrity issue but do | ||
810 | not bother sending an oplock release if session | ||
811 | to server still is disconnected since oplock | ||
812 | already released by the server in that case */ | ||
813 | if(pTcon->tidStatus != CifsNeedReconnect) { | ||
814 | rc = CIFSSMBLock(0, pTcon, netfid, | ||
815 | 0 /* len */ , 0 /* offset */, 0, | ||
816 | 0, LOCKING_ANDX_OPLOCK_RELEASE, | ||
817 | 0 /* wait flag */); | ||
818 | cFYI(1,("Oplock release rc = %d ",rc)); | ||
819 | } | ||
820 | } else | ||
821 | spin_unlock(&GlobalMid_Lock); | ||
822 | } | ||
823 | } while(!signal_pending(current)); | ||
824 | complete_and_exit (&cifs_oplock_exited, 0); | ||
825 | } | ||
826 | |||
827 | static int __init | ||
828 | init_cifs(void) | ||
829 | { | ||
830 | int rc = 0; | ||
831 | #ifdef CONFIG_PROC_FS | ||
832 | cifs_proc_init(); | ||
833 | #endif | ||
834 | INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */ | ||
835 | INIT_LIST_HEAD(&GlobalSMBSessionList); | ||
836 | INIT_LIST_HEAD(&GlobalTreeConnectionList); | ||
837 | INIT_LIST_HEAD(&GlobalOplock_Q); | ||
838 | /* | ||
839 | * Initialize Global counters | ||
840 | */ | ||
841 | atomic_set(&sesInfoAllocCount, 0); | ||
842 | atomic_set(&tconInfoAllocCount, 0); | ||
843 | atomic_set(&tcpSesAllocCount,0); | ||
844 | atomic_set(&tcpSesReconnectCount, 0); | ||
845 | atomic_set(&tconInfoReconnectCount, 0); | ||
846 | |||
847 | atomic_set(&bufAllocCount, 0); | ||
848 | atomic_set(&midCount, 0); | ||
849 | GlobalCurrentXid = 0; | ||
850 | GlobalTotalActiveXid = 0; | ||
851 | GlobalMaxActiveXid = 0; | ||
852 | rwlock_init(&GlobalSMBSeslock); | ||
853 | spin_lock_init(&GlobalMid_Lock); | ||
854 | |||
855 | if(cifs_max_pending < 2) { | ||
856 | cifs_max_pending = 2; | ||
857 | cFYI(1,("cifs_max_pending set to min of 2")); | ||
858 | } else if(cifs_max_pending > 256) { | ||
859 | cifs_max_pending = 256; | ||
860 | cFYI(1,("cifs_max_pending set to max of 256")); | ||
861 | } | ||
862 | |||
863 | rc = cifs_init_inodecache(); | ||
864 | if (!rc) { | ||
865 | rc = cifs_init_mids(); | ||
866 | if (!rc) { | ||
867 | rc = cifs_init_request_bufs(); | ||
868 | if (!rc) { | ||
869 | rc = register_filesystem(&cifs_fs_type); | ||
870 | if (!rc) { | ||
871 | rc = (int)kernel_thread(cifs_oplock_thread, NULL, | ||
872 | CLONE_FS | CLONE_FILES | CLONE_VM); | ||
873 | if(rc > 0) | ||
874 | return 0; | ||
875 | else | ||
876 | cERROR(1,("error %d create oplock thread",rc)); | ||
877 | } | ||
878 | cifs_destroy_request_bufs(); | ||
879 | } | ||
880 | cifs_destroy_mids(); | ||
881 | } | ||
882 | cifs_destroy_inodecache(); | ||
883 | } | ||
884 | #ifdef CONFIG_PROC_FS | ||
885 | cifs_proc_clean(); | ||
886 | #endif | ||
887 | return rc; | ||
888 | } | ||
889 | |||
890 | static void __exit | ||
891 | exit_cifs(void) | ||
892 | { | ||
893 | cFYI(0, ("In unregister ie exit_cifs")); | ||
894 | #ifdef CONFIG_PROC_FS | ||
895 | cifs_proc_clean(); | ||
896 | #endif | ||
897 | unregister_filesystem(&cifs_fs_type); | ||
898 | cifs_destroy_inodecache(); | ||
899 | cifs_destroy_mids(); | ||
900 | cifs_destroy_request_bufs(); | ||
901 | if(oplockThread) { | ||
902 | send_sig(SIGTERM, oplockThread, 1); | ||
903 | wait_for_completion(&cifs_oplock_exited); | ||
904 | } | ||
905 | } | ||
906 | |||
907 | MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); | ||
908 | MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ | ||
909 | MODULE_DESCRIPTION | ||
910 | ("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows"); | ||
911 | MODULE_VERSION(CIFS_VERSION); | ||
912 | module_init(init_cifs) | ||
913 | module_exit(exit_cifs) | ||
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h new file mode 100644 index 000000000000..451f18af3206 --- /dev/null +++ b/fs/cifs/cifsfs.h | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifsfs.h | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2002 | ||
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 | |||
22 | #ifndef _CIFSFS_H | ||
23 | #define _CIFSFS_H | ||
24 | |||
25 | #define ROOT_I 2 | ||
26 | |||
27 | #ifndef FALSE | ||
28 | #define FALSE 0 | ||
29 | #endif | ||
30 | |||
31 | #ifndef TRUE | ||
32 | #define TRUE 1 | ||
33 | #endif | ||
34 | |||
35 | extern struct address_space_operations cifs_addr_ops; | ||
36 | |||
37 | /* Functions related to super block operations */ | ||
38 | extern struct super_operations cifs_super_ops; | ||
39 | extern void cifs_read_inode(struct inode *); | ||
40 | extern void cifs_delete_inode(struct inode *); | ||
41 | /* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */ | ||
42 | |||
43 | /* Functions related to inodes */ | ||
44 | extern struct inode_operations cifs_dir_inode_ops; | ||
45 | extern int cifs_create(struct inode *, struct dentry *, int, | ||
46 | struct nameidata *); | ||
47 | extern struct dentry * cifs_lookup(struct inode *, struct dentry *, | ||
48 | struct nameidata *); | ||
49 | extern int cifs_unlink(struct inode *, struct dentry *); | ||
50 | extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); | ||
51 | extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t); | ||
52 | extern int cifs_mkdir(struct inode *, struct dentry *, int); | ||
53 | extern int cifs_rmdir(struct inode *, struct dentry *); | ||
54 | extern int cifs_rename(struct inode *, struct dentry *, struct inode *, | ||
55 | struct dentry *); | ||
56 | extern int cifs_revalidate(struct dentry *); | ||
57 | extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); | ||
58 | extern int cifs_setattr(struct dentry *, struct iattr *); | ||
59 | |||
60 | extern struct inode_operations cifs_file_inode_ops; | ||
61 | extern struct inode_operations cifs_symlink_inode_ops; | ||
62 | |||
63 | /* Functions related to files and directories */ | ||
64 | extern struct file_operations cifs_file_ops; | ||
65 | extern struct file_operations cifs_file_direct_ops; /* if directio mount */ | ||
66 | extern int cifs_open(struct inode *inode, struct file *file); | ||
67 | extern int cifs_close(struct inode *inode, struct file *file); | ||
68 | extern int cifs_closedir(struct inode *inode, struct file *file); | ||
69 | extern ssize_t cifs_user_read(struct file *file, char __user *read_data, | ||
70 | size_t read_size, loff_t * poffset); | ||
71 | extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, | ||
72 | size_t write_size, loff_t * poffset); | ||
73 | extern int cifs_lock(struct file *, int, struct file_lock *); | ||
74 | extern int cifs_fsync(struct file *, struct dentry *, int); | ||
75 | extern int cifs_flush(struct file *); | ||
76 | extern int cifs_file_mmap(struct file * , struct vm_area_struct *); | ||
77 | extern struct file_operations cifs_dir_ops; | ||
78 | extern int cifs_dir_open(struct inode *inode, struct file *file); | ||
79 | extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); | ||
80 | extern int cifs_dir_notify(struct file *, unsigned long arg); | ||
81 | |||
82 | /* Functions related to dir entries */ | ||
83 | extern struct dentry_operations cifs_dentry_ops; | ||
84 | |||
85 | /* Functions related to symlinks */ | ||
86 | extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd); | ||
87 | extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd); | ||
88 | extern int cifs_readlink(struct dentry *direntry, char __user *buffer, | ||
89 | int buflen); | ||
90 | extern int cifs_symlink(struct inode *inode, struct dentry *direntry, | ||
91 | const char *symname); | ||
92 | extern int cifs_removexattr(struct dentry *, const char *); | ||
93 | extern int cifs_setxattr(struct dentry *, const char *, const void *, | ||
94 | size_t, int); | ||
95 | extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); | ||
96 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | ||
97 | #define CIFS_VERSION "1.31" | ||
98 | #endif /* _CIFSFS_H */ | ||
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h new file mode 100644 index 000000000000..69aff1a7da9b --- /dev/null +++ b/fs/cifs/cifsglob.h | |||
@@ -0,0 +1,439 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifsglob.h | ||
3 | * | ||
4 | * Copyright (C) International Business Machines Corp., 2002,2003 | ||
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 | */ | ||
18 | #include <linux/in.h> | ||
19 | #include <linux/in6.h> | ||
20 | #include "cifs_fs_sb.h" | ||
21 | /* | ||
22 | * The sizes of various internal tables and strings | ||
23 | */ | ||
24 | #define MAX_UID_INFO 16 | ||
25 | #define MAX_SES_INFO 2 | ||
26 | #define MAX_TCON_INFO 4 | ||
27 | |||
28 | #define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1 | ||
29 | #define MAX_SERVER_SIZE 15 | ||
30 | #define MAX_SHARE_SIZE 64 /* used to be 20 - this should still be enough */ | ||
31 | #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null | ||
32 | termination then *2 for unicode versions */ | ||
33 | #define MAX_PASSWORD_SIZE 16 | ||
34 | |||
35 | #define CIFS_MIN_RCV_POOL 4 | ||
36 | |||
37 | /* | ||
38 | * MAX_REQ is the maximum number of requests that WE will send | ||
39 | * on one socket concurently. It also matches the most common | ||
40 | * value of max multiplex returned by servers. We may | ||
41 | * eventually want to use the negotiated value (in case | ||
42 | * future servers can handle more) when we are more confident that | ||
43 | * we will not have problems oveloading the socket with pending | ||
44 | * write data. | ||
45 | */ | ||
46 | #define CIFS_MAX_REQ 50 | ||
47 | |||
48 | #define SERVER_NAME_LENGTH 15 | ||
49 | #define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) | ||
50 | |||
51 | /* used to define string lengths for reversing unicode strings */ | ||
52 | /* (256+1)*2 = 514 */ | ||
53 | /* (max path length + 1 for null) * 2 for unicode */ | ||
54 | #define MAX_NAME 514 | ||
55 | |||
56 | #include "cifspdu.h" | ||
57 | |||
58 | #ifndef FALSE | ||
59 | #define FALSE 0 | ||
60 | #endif | ||
61 | |||
62 | #ifndef TRUE | ||
63 | #define TRUE 1 | ||
64 | #endif | ||
65 | |||
66 | #ifndef XATTR_DOS_ATTRIB | ||
67 | #define XATTR_DOS_ATTRIB "user.DOSATTRIB" | ||
68 | #endif | ||
69 | |||
70 | /* | ||
71 | * This information is kept on every Server we know about. | ||
72 | * | ||
73 | * Some things to note: | ||
74 | * | ||
75 | */ | ||
76 | #define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) | ||
77 | |||
78 | /* | ||
79 | * CIFS vfs client Status information (based on what we know.) | ||
80 | */ | ||
81 | |||
82 | /* associated with each tcp and smb session */ | ||
83 | enum statusEnum { | ||
84 | CifsNew = 0, | ||
85 | CifsGood, | ||
86 | CifsExiting, | ||
87 | CifsNeedReconnect | ||
88 | }; | ||
89 | |||
90 | enum securityEnum { | ||
91 | NTLM = 0, /* Legacy NTLM012 auth with NTLM hash */ | ||
92 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ | ||
93 | RawNTLMSSP, /* NTLMSSP without SPNEGO */ | ||
94 | NTLMSSP, /* NTLMSSP via SPNEGO */ | ||
95 | Kerberos /* Kerberos via SPNEGO */ | ||
96 | }; | ||
97 | |||
98 | enum protocolEnum { | ||
99 | IPV4 = 0, | ||
100 | IPV6, | ||
101 | SCTP | ||
102 | /* Netbios frames protocol not supported at this time */ | ||
103 | }; | ||
104 | |||
105 | /* | ||
106 | ***************************************************************** | ||
107 | * Except the CIFS PDUs themselves all the | ||
108 | * globally interesting structs should go here | ||
109 | ***************************************************************** | ||
110 | */ | ||
111 | |||
112 | struct TCP_Server_Info { | ||
113 | char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */ | ||
114 | char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */ | ||
115 | struct socket *ssocket; | ||
116 | union { | ||
117 | struct sockaddr_in sockAddr; | ||
118 | struct sockaddr_in6 sockAddr6; | ||
119 | } addr; | ||
120 | wait_queue_head_t response_q; | ||
121 | wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ | ||
122 | struct list_head pending_mid_q; | ||
123 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ | ||
124 | unsigned short server_codepage; /* codepage for the server */ | ||
125 | unsigned long ip_address; /* IP addr for the server if known */ | ||
126 | enum protocolEnum protocolType; | ||
127 | char versionMajor; | ||
128 | char versionMinor; | ||
129 | unsigned svlocal:1; /* local server or remote */ | ||
130 | atomic_t socketUseCount; /* number of open cifs sessions on socket */ | ||
131 | atomic_t inFlight; /* number of requests on the wire to server */ | ||
132 | enum statusEnum tcpStatus; /* what we think the status is */ | ||
133 | struct semaphore tcpSem; | ||
134 | struct task_struct *tsk; | ||
135 | char server_GUID[16]; | ||
136 | char secMode; | ||
137 | enum securityEnum secType; | ||
138 | unsigned int maxReq; /* Clients should submit no more */ | ||
139 | /* than maxReq distinct unanswered SMBs to the server when using */ | ||
140 | /* multiplexed reads or writes */ | ||
141 | unsigned int maxBuf; /* maxBuf specifies the maximum */ | ||
142 | /* message size the server can send or receive for non-raw SMBs */ | ||
143 | unsigned int maxRw; /* maxRw specifies the maximum */ | ||
144 | /* message size the server can send or receive for */ | ||
145 | /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */ | ||
146 | char sessid[4]; /* unique token id for this session */ | ||
147 | /* (returned on Negotiate */ | ||
148 | int capabilities; /* allow selective disabling of caps by smb sess */ | ||
149 | __u16 timeZone; | ||
150 | char cryptKey[CIFS_CRYPTO_KEY_SIZE]; | ||
151 | char workstation_RFC1001_name[16]; /* 16th byte is always zero */ | ||
152 | }; | ||
153 | |||
154 | /* | ||
155 | * The following is our shortcut to user information. We surface the uid, | ||
156 | * and name. We always get the password on the fly in case it | ||
157 | * has changed. We also hang a list of sessions owned by this user off here. | ||
158 | */ | ||
159 | struct cifsUidInfo { | ||
160 | struct list_head userList; | ||
161 | struct list_head sessionList; /* SMB sessions for this user */ | ||
162 | uid_t linux_uid; | ||
163 | char user[MAX_USERNAME_SIZE + 1]; /* ascii name of user */ | ||
164 | /* BB may need ptr or callback for PAM or WinBind info */ | ||
165 | }; | ||
166 | |||
167 | /* | ||
168 | * Session structure. One of these for each uid session with a particular host | ||
169 | */ | ||
170 | struct cifsSesInfo { | ||
171 | struct list_head cifsSessionList; | ||
172 | struct semaphore sesSem; | ||
173 | struct cifsUidInfo *uidInfo; /* pointer to user info */ | ||
174 | struct TCP_Server_Info *server; /* pointer to server info */ | ||
175 | atomic_t inUse; /* # of mounts (tree connections) on this ses */ | ||
176 | enum statusEnum status; | ||
177 | __u32 sequence_number; /* needed for CIFS PDU signature */ | ||
178 | __u16 ipc_tid; /* special tid for connection to IPC share */ | ||
179 | __u16 flags; | ||
180 | char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; | ||
181 | char *serverOS; /* name of operating system underlying the server */ | ||
182 | char *serverNOS; /* name of network operating system that the server is running */ | ||
183 | char *serverDomain; /* security realm of server */ | ||
184 | int Suid; /* remote smb uid */ | ||
185 | uid_t linux_uid; /* local Linux uid */ | ||
186 | int capabilities; | ||
187 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ | ||
188 | char userName[MAX_USERNAME_SIZE + 1]; | ||
189 | char domainName[MAX_USERNAME_SIZE + 1]; | ||
190 | char * password; | ||
191 | }; | ||
192 | /* session flags */ | ||
193 | #define CIFS_SES_NT4 1 | ||
194 | |||
195 | /* | ||
196 | * there is one of these for each connection to a resource on a particular | ||
197 | * session | ||
198 | */ | ||
199 | struct cifsTconInfo { | ||
200 | struct list_head cifsConnectionList; | ||
201 | struct list_head openFileList; | ||
202 | struct semaphore tconSem; | ||
203 | struct cifsSesInfo *ses; /* pointer to session associated with */ | ||
204 | char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */ | ||
205 | char *nativeFileSystem; | ||
206 | __u16 tid; /* The 2 byte tree id */ | ||
207 | __u16 Flags; /* optional support bits */ | ||
208 | enum statusEnum tidStatus; | ||
209 | atomic_t useCount; /* how many mounts (explicit or implicit) to this share */ | ||
210 | #ifdef CONFIG_CIFS_STATS | ||
211 | atomic_t num_smbs_sent; | ||
212 | atomic_t num_writes; | ||
213 | atomic_t num_reads; | ||
214 | atomic_t num_oplock_brks; | ||
215 | atomic_t num_opens; | ||
216 | atomic_t num_deletes; | ||
217 | atomic_t num_mkdirs; | ||
218 | atomic_t num_rmdirs; | ||
219 | atomic_t num_renames; | ||
220 | atomic_t num_t2renames; | ||
221 | __u64 bytes_read; | ||
222 | __u64 bytes_written; | ||
223 | spinlock_t stat_lock; | ||
224 | #endif | ||
225 | FILE_SYSTEM_DEVICE_INFO fsDevInfo; | ||
226 | FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ | ||
227 | FILE_SYSTEM_UNIX_INFO fsUnixInfo; | ||
228 | unsigned retry:1; | ||
229 | /* BB add field for back pointer to sb struct? */ | ||
230 | }; | ||
231 | |||
232 | /* | ||
233 | * This info hangs off the cifsFileInfo structure. This is used to track | ||
234 | * byte stream locks on the file | ||
235 | */ | ||
236 | struct cifsLockInfo { | ||
237 | struct cifsLockInfo *next; | ||
238 | int start; | ||
239 | int length; | ||
240 | int type; | ||
241 | }; | ||
242 | |||
243 | /* | ||
244 | * One of these for each open instance of a file | ||
245 | */ | ||
246 | struct cifs_search_info { | ||
247 | loff_t index_of_last_entry; | ||
248 | __u16 entries_in_buffer; | ||
249 | __u16 info_level; | ||
250 | __u32 resume_key; | ||
251 | char * ntwrk_buf_start; | ||
252 | char * srch_entries_start; | ||
253 | char * presume_name; | ||
254 | unsigned int resume_name_len; | ||
255 | unsigned endOfSearch:1; | ||
256 | unsigned emptyDir:1; | ||
257 | unsigned unicode:1; | ||
258 | }; | ||
259 | |||
260 | struct cifsFileInfo { | ||
261 | struct list_head tlist; /* pointer to next fid owned by tcon */ | ||
262 | struct list_head flist; /* next fid (file instance) for this inode */ | ||
263 | unsigned int uid; /* allows finding which FileInfo structure */ | ||
264 | __u32 pid; /* process id who opened file */ | ||
265 | __u16 netfid; /* file id from remote */ | ||
266 | /* BB add lock scope info here if needed */ ; | ||
267 | /* lock scope id (0 if none) */ | ||
268 | struct file * pfile; /* needed for writepage */ | ||
269 | struct inode * pInode; /* needed for oplock break */ | ||
270 | unsigned closePend:1; /* file is marked to close */ | ||
271 | unsigned invalidHandle:1; /* file closed via session abend */ | ||
272 | struct semaphore fh_sem; /* prevents reopen race after dead ses*/ | ||
273 | char * search_resume_name; /* BB removeme BB */ | ||
274 | unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ | ||
275 | struct cifs_search_info srch_inf; | ||
276 | }; | ||
277 | |||
278 | /* | ||
279 | * One of these for each file inode | ||
280 | */ | ||
281 | |||
282 | struct cifsInodeInfo { | ||
283 | struct list_head lockList; | ||
284 | /* BB add in lists for dirty pages - i.e. write caching info for oplock */ | ||
285 | struct list_head openFileList; | ||
286 | int write_behind_rc; | ||
287 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ | ||
288 | atomic_t inUse; /* num concurrent users (local openers cifs) of file*/ | ||
289 | unsigned long time; /* jiffies of last update/check of inode */ | ||
290 | unsigned clientCanCacheRead:1; /* read oplock */ | ||
291 | unsigned clientCanCacheAll:1; /* read and writebehind oplock */ | ||
292 | unsigned oplockPending:1; | ||
293 | struct inode vfs_inode; | ||
294 | }; | ||
295 | |||
296 | static inline struct cifsInodeInfo * | ||
297 | CIFS_I(struct inode *inode) | ||
298 | { | ||
299 | return container_of(inode, struct cifsInodeInfo, vfs_inode); | ||
300 | } | ||
301 | |||
302 | static inline struct cifs_sb_info * | ||
303 | CIFS_SB(struct super_block *sb) | ||
304 | { | ||
305 | return sb->s_fs_info; | ||
306 | } | ||
307 | |||
308 | |||
309 | /* one of these for every pending CIFS request to the server */ | ||
310 | struct mid_q_entry { | ||
311 | struct list_head qhead; /* mids waiting on reply from this server */ | ||
312 | __u16 mid; /* multiplex id */ | ||
313 | __u16 pid; /* process id */ | ||
314 | __u32 sequence_number; /* for CIFS signing */ | ||
315 | __u16 command; /* smb command code */ | ||
316 | struct timeval when_sent; /* time when smb sent */ | ||
317 | struct cifsSesInfo *ses; /* smb was sent to this server */ | ||
318 | struct task_struct *tsk; /* task waiting for response */ | ||
319 | struct smb_hdr *resp_buf; /* response buffer */ | ||
320 | int midState; /* wish this were enum but can not pass to wait_event */ | ||
321 | }; | ||
322 | |||
323 | struct oplock_q_entry { | ||
324 | struct list_head qhead; | ||
325 | struct inode * pinode; | ||
326 | struct cifsTconInfo * tcon; | ||
327 | __u16 netfid; | ||
328 | }; | ||
329 | |||
330 | #define MID_FREE 0 | ||
331 | #define MID_REQUEST_ALLOCATED 1 | ||
332 | #define MID_REQUEST_SUBMITTED 2 | ||
333 | #define MID_RESPONSE_RECEIVED 4 | ||
334 | #define MID_RETRY_NEEDED 8 /* session closed while this request out */ | ||
335 | #define MID_NO_RESP_NEEDED 0x10 | ||
336 | #define MID_SMALL_BUFFER 0x20 /* 112 byte response buffer instead of 4K */ | ||
337 | |||
338 | /* | ||
339 | ***************************************************************** | ||
340 | * All constants go here | ||
341 | ***************************************************************** | ||
342 | */ | ||
343 | |||
344 | #define UID_HASH (16) | ||
345 | |||
346 | /* | ||
347 | * Note that ONE module should define _DECLARE_GLOBALS_HERE to cause the | ||
348 | * following to be declared. | ||
349 | */ | ||
350 | |||
351 | /**************************************************************************** | ||
352 | * Locking notes. All updates to global variables and lists should be | ||
353 | * protected by spinlocks or semaphores. | ||
354 | * | ||
355 | * Spinlocks | ||
356 | * --------- | ||
357 | * GlobalMid_Lock protects: | ||
358 | * list operations on pending_mid_q and oplockQ | ||
359 | * updates to XID counters, multiplex id and SMB sequence numbers | ||
360 | * GlobalSMBSesLock protects: | ||
361 | * list operations on tcp and SMB session lists and tCon lists | ||
362 | * f_owner.lock protects certain per file struct operations | ||
363 | * mapping->page_lock protects certain per page operations | ||
364 | * | ||
365 | * Semaphores | ||
366 | * ---------- | ||
367 | * sesSem operations on smb session | ||
368 | * tconSem operations on tree connection | ||
369 | * fh_sem file handle reconnection operations | ||
370 | * | ||
371 | ****************************************************************************/ | ||
372 | |||
373 | #ifdef DECLARE_GLOBALS_HERE | ||
374 | #define GLOBAL_EXTERN | ||
375 | #else | ||
376 | #define GLOBAL_EXTERN extern | ||
377 | #endif | ||
378 | |||
379 | /* | ||
380 | * The list of servers that did not respond with NT LM 0.12. | ||
381 | * This list helps improve performance and eliminate the messages indicating | ||
382 | * that we had a communications error talking to the server in this list. | ||
383 | */ | ||
384 | GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */ | ||
385 | |||
386 | /* | ||
387 | * The following is a hash table of all the users we know about. | ||
388 | */ | ||
389 | GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH]; | ||
390 | |||
391 | GLOBAL_EXTERN struct list_head GlobalServerList; /* BB not implemented yet */ | ||
392 | GLOBAL_EXTERN struct list_head GlobalSMBSessionList; | ||
393 | GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; | ||
394 | GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ | ||
395 | |||
396 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; | ||
397 | |||
398 | /* | ||
399 | * Global transaction id (XID) information | ||
400 | */ | ||
401 | GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ | ||
402 | GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ | ||
403 | GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ | ||
404 | GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */ | ||
405 | /* on midQ entries */ | ||
406 | GLOBAL_EXTERN char Local_System_Name[15]; | ||
407 | |||
408 | /* | ||
409 | * Global counters, updated atomically | ||
410 | */ | ||
411 | GLOBAL_EXTERN atomic_t sesInfoAllocCount; | ||
412 | GLOBAL_EXTERN atomic_t tconInfoAllocCount; | ||
413 | GLOBAL_EXTERN atomic_t tcpSesAllocCount; | ||
414 | GLOBAL_EXTERN atomic_t tcpSesReconnectCount; | ||
415 | GLOBAL_EXTERN atomic_t tconInfoReconnectCount; | ||
416 | |||
417 | /* Various Debug counters to remove someday (BB) */ | ||
418 | GLOBAL_EXTERN atomic_t bufAllocCount; | ||
419 | GLOBAL_EXTERN atomic_t smBufAllocCount; | ||
420 | GLOBAL_EXTERN atomic_t midCount; | ||
421 | |||
422 | /* Misc globals */ | ||
423 | GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions | ||
424 | to be established on existing mount if we | ||
425 | have the uid/password or Kerberos credential | ||
426 | or equivalent for current user */ | ||
427 | GLOBAL_EXTERN unsigned int oplockEnabled; | ||
428 | GLOBAL_EXTERN unsigned int experimEnabled; | ||
429 | GLOBAL_EXTERN unsigned int lookupCacheEnabled; | ||
430 | GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent | ||
431 | with more secure ntlmssp2 challenge/resp */ | ||
432 | GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ | ||
433 | GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ | ||
434 | GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ | ||
435 | GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ | ||
436 | GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ | ||
437 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ | ||
438 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ | ||
439 | |||
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h new file mode 100644 index 000000000000..bcd4a6136f08 --- /dev/null +++ b/fs/cifs/cifspdu.h | |||
@@ -0,0 +1,1987 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifspdu.h | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2002 | ||
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 | |||
22 | #ifndef _CIFSPDU_H | ||
23 | #define _CIFSPDU_H | ||
24 | |||
25 | #include <net/sock.h> | ||
26 | |||
27 | #define CIFS_PROT 0 | ||
28 | #define BAD_PROT CIFS_PROT+1 | ||
29 | |||
30 | /* SMB command codes */ | ||
31 | /* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses | ||
32 | (ie which include no useful data other than the SMB error code itself). | ||
33 | Knowing this helps avoid response buffer allocations and copy in some cases */ | ||
34 | #define SMB_COM_CREATE_DIRECTORY 0x00 /* trivial response */ | ||
35 | #define SMB_COM_DELETE_DIRECTORY 0x01 /* trivial response */ | ||
36 | #define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ | ||
37 | #define SMB_COM_DELETE 0x06 /* trivial response */ | ||
38 | #define SMB_COM_RENAME 0x07 /* trivial response */ | ||
39 | #define SMB_COM_SETATTR 0x09 /* trivial response */ | ||
40 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ | ||
41 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ | ||
42 | #define SMB_COM_READ_ANDX 0x2E | ||
43 | #define SMB_COM_WRITE_ANDX 0x2F | ||
44 | #define SMB_COM_TRANSACTION2 0x32 | ||
45 | #define SMB_COM_TRANSACTION2_SECONDARY 0x33 | ||
46 | #define SMB_COM_FIND_CLOSE2 0x34 /* trivial response */ | ||
47 | #define SMB_COM_TREE_DISCONNECT 0x71 /* trivial response */ | ||
48 | #define SMB_COM_NEGOTIATE 0x72 | ||
49 | #define SMB_COM_SESSION_SETUP_ANDX 0x73 | ||
50 | #define SMB_COM_LOGOFF_ANDX 0x74 /* trivial response */ | ||
51 | #define SMB_COM_TREE_CONNECT_ANDX 0x75 | ||
52 | #define SMB_COM_NT_TRANSACT 0xA0 | ||
53 | #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 | ||
54 | #define SMB_COM_NT_CREATE_ANDX 0xA2 | ||
55 | #define SMB_COM_NT_RENAME 0xA5 /* trivial response */ | ||
56 | |||
57 | /* Transact2 subcommand codes */ | ||
58 | #define TRANS2_OPEN 0x00 | ||
59 | #define TRANS2_FIND_FIRST 0x01 | ||
60 | #define TRANS2_FIND_NEXT 0x02 | ||
61 | #define TRANS2_QUERY_FS_INFORMATION 0x03 | ||
62 | #define TRANS2_QUERY_PATH_INFORMATION 0x05 | ||
63 | #define TRANS2_SET_PATH_INFORMATION 0x06 | ||
64 | #define TRANS2_QUERY_FILE_INFORMATION 0x07 | ||
65 | #define TRANS2_SET_FILE_INFORMATION 0x08 | ||
66 | #define TRANS2_GET_DFS_REFERRAL 0x10 | ||
67 | #define TRANS2_REPORT_DFS_INCOSISTENCY 0x11 | ||
68 | |||
69 | /* NT Transact subcommand codes */ | ||
70 | #define NT_TRANSACT_CREATE 0x01 | ||
71 | #define NT_TRANSACT_IOCTL 0x02 | ||
72 | #define NT_TRANSACT_SET_SECURITY_DESC 0x03 | ||
73 | #define NT_TRANSACT_NOTIFY_CHANGE 0x04 | ||
74 | #define NT_TRANSACT_RENAME 0x05 | ||
75 | #define NT_TRANSACT_QUERY_SECURITY_DESC 0x06 | ||
76 | #define NT_TRANSACT_GET_USER_QUOTA 0x07 | ||
77 | #define NT_TRANSACT_SET_USER_QUOTA 0x08 | ||
78 | |||
79 | #define MAX_CIFS_HDR_SIZE 256 /* chained NTCreateXReadX will probably be biggest */ | ||
80 | |||
81 | /* internal cifs vfs structures */ | ||
82 | /***************************************************************** | ||
83 | * All constants go here | ||
84 | ***************************************************************** | ||
85 | */ | ||
86 | |||
87 | /* | ||
88 | * Starting value for maximum SMB size negotiation | ||
89 | */ | ||
90 | #define CIFS_MAX_MSGSIZE (4*4096) | ||
91 | |||
92 | /* | ||
93 | * Size of encrypted user password in bytes | ||
94 | */ | ||
95 | #define CIFS_ENCPWD_SIZE (16) | ||
96 | |||
97 | /* | ||
98 | * Size of the crypto key returned on the negotiate SMB in bytes | ||
99 | */ | ||
100 | #define CIFS_CRYPTO_KEY_SIZE (8) | ||
101 | |||
102 | /* | ||
103 | * Size of the session key (crypto key encrypted with the password | ||
104 | */ | ||
105 | #define CIFS_SESSION_KEY_SIZE (24) | ||
106 | |||
107 | /* | ||
108 | * Maximum user name length | ||
109 | */ | ||
110 | #define CIFS_UNLEN (20) | ||
111 | |||
112 | /* | ||
113 | * Flags on SMB open | ||
114 | */ | ||
115 | #define SMBOPEN_WRITE_THROUGH 0x4000 | ||
116 | #define SMBOPEN_DENY_ALL 0x0010 | ||
117 | #define SMBOPEN_DENY_WRITE 0x0020 | ||
118 | #define SMBOPEN_DENY_READ 0x0030 | ||
119 | #define SMBOPEN_DENY_NONE 0x0040 | ||
120 | #define SMBOPEN_READ 0x0000 | ||
121 | #define SMBOPEN_WRITE 0x0001 | ||
122 | #define SMBOPEN_READWRITE 0x0002 | ||
123 | #define SMBOPEN_EXECUTE 0x0003 | ||
124 | |||
125 | #define SMBOPEN_OCREATE 0x0010 | ||
126 | #define SMBOPEN_OTRUNC 0x0002 | ||
127 | #define SMBOPEN_OAPPEND 0x0001 | ||
128 | |||
129 | /* | ||
130 | * SMB flag definitions | ||
131 | */ | ||
132 | #define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock primitives */ | ||
133 | #define SMBFLG_RCV_POSTED 0x02 /* obsolete */ | ||
134 | #define SMBFLG_RSVD 0x04 | ||
135 | #define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off implies case sensitive file handling requested) */ | ||
136 | #define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */ | ||
137 | #define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */ | ||
138 | #define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */ | ||
139 | #define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */ | ||
140 | |||
141 | /* | ||
142 | * SMB flag2 definitions | ||
143 | */ | ||
144 | #define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3) path names in response */ | ||
145 | #define SMBFLG2_KNOWS_EAS cpu_to_le16(2) | ||
146 | #define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4) | ||
147 | #define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40) | ||
148 | #define SMBFLG2_EXT_SEC cpu_to_le16(0x800) | ||
149 | #define SMBFLG2_DFS cpu_to_le16(0x1000) | ||
150 | #define SMBFLG2_PAGING_IO cpu_to_le16(0x2000) | ||
151 | #define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000) | ||
152 | #define SMBFLG2_UNICODE cpu_to_le16(0x8000) | ||
153 | |||
154 | /* | ||
155 | * These are the file access permission bits defined in CIFS for the | ||
156 | * NTCreateAndX as well as the level 0x107 | ||
157 | * TRANS2_QUERY_PATH_INFORMATION API. The level 0x107, SMB_QUERY_FILE_ALL_INFO | ||
158 | * responds with the AccessFlags. | ||
159 | * The AccessFlags specifies the access permissions a caller has to the | ||
160 | * file and can have any suitable combination of the following values: | ||
161 | */ | ||
162 | |||
163 | #define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ | ||
164 | #define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ | ||
165 | #define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ | ||
166 | #define FILE_READ_EA 0x00000008 /* Extended attributes associated */ | ||
167 | /* with the file can be read */ | ||
168 | #define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ | ||
169 | /* with the file can be written */ | ||
170 | #define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ | ||
171 | /* the file using system paging I/O */ | ||
172 | #define FILE_DELETE_CHILD 0x00000040 | ||
173 | #define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ | ||
174 | /* file can be read */ | ||
175 | #define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ | ||
176 | /* file can be written */ | ||
177 | #define DELETE 0x00010000 /* The file can be deleted */ | ||
178 | #define READ_CONTROL 0x00020000 /* The access control list and */ | ||
179 | /* ownership associated with the */ | ||
180 | /* file can be read */ | ||
181 | #define WRITE_DAC 0x00040000 /* The access control list and */ | ||
182 | /* ownership associated with the */ | ||
183 | /* file can be written. */ | ||
184 | #define WRITE_OWNER 0x00080000 /* Ownership information associated */ | ||
185 | /* with the file can be written */ | ||
186 | #define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ | ||
187 | /* synchronize with the completion */ | ||
188 | /* of an input/output request */ | ||
189 | #define GENERIC_ALL 0x10000000 | ||
190 | #define GENERIC_EXECUTE 0x20000000 | ||
191 | #define GENERIC_WRITE 0x40000000 | ||
192 | #define GENERIC_READ 0x80000000 | ||
193 | /* In summary - Relevant file */ | ||
194 | /* access flags from CIFS are */ | ||
195 | /* file_read_data, file_write_data */ | ||
196 | /* file_execute, file_read_attributes */ | ||
197 | /* write_dac, and delete. */ | ||
198 | |||
199 | /* | ||
200 | * Invalid readdir handle | ||
201 | */ | ||
202 | #define CIFS_NO_HANDLE 0xFFFF | ||
203 | |||
204 | /* IPC$ in ASCII */ | ||
205 | #define CIFS_IPC_RESOURCE "\x49\x50\x43\x24" | ||
206 | |||
207 | /* IPC$ in Unicode */ | ||
208 | #define CIFS_IPC_UNICODE_RESOURCE "\x00\x49\x00\x50\x00\x43\x00\x24\x00\x00" | ||
209 | |||
210 | /* Unicode Null terminate 2 bytes of 0 */ | ||
211 | #define UNICODE_NULL "\x00\x00" | ||
212 | #define ASCII_NULL 0x00 | ||
213 | |||
214 | /* | ||
215 | * Server type values (returned on EnumServer API | ||
216 | */ | ||
217 | #define CIFS_SV_TYPE_DC 0x00000008 | ||
218 | #define CIFS_SV_TYPE_BACKDC 0x00000010 | ||
219 | |||
220 | /* | ||
221 | * Alias type flags (From EnumAlias API call | ||
222 | */ | ||
223 | #define CIFS_ALIAS_TYPE_FILE 0x0001 | ||
224 | #define CIFS_SHARE_TYPE_FILE 0x0000 | ||
225 | |||
226 | /* | ||
227 | * File Attribute flags | ||
228 | */ | ||
229 | #define ATTR_READONLY 0x0001 | ||
230 | #define ATTR_HIDDEN 0x0002 | ||
231 | #define ATTR_SYSTEM 0x0004 | ||
232 | #define ATTR_VOLUME 0x0008 | ||
233 | #define ATTR_DIRECTORY 0x0010 | ||
234 | #define ATTR_ARCHIVE 0x0020 | ||
235 | #define ATTR_DEVICE 0x0040 | ||
236 | #define ATTR_NORMAL 0x0080 | ||
237 | #define ATTR_TEMPORARY 0x0100 | ||
238 | #define ATTR_SPARSE 0x0200 | ||
239 | #define ATTR_REPARSE 0x0400 | ||
240 | #define ATTR_COMPRESSED 0x0800 | ||
241 | #define ATTR_OFFLINE 0x1000 /* ie file not immediately available - offline storage */ | ||
242 | #define ATTR_NOT_CONTENT_INDEXED 0x2000 | ||
243 | #define ATTR_ENCRYPTED 0x4000 | ||
244 | #define ATTR_POSIX_SEMANTICS 0x01000000 | ||
245 | #define ATTR_BACKUP_SEMANTICS 0x02000000 | ||
246 | #define ATTR_DELETE_ON_CLOSE 0x04000000 | ||
247 | #define ATTR_SEQUENTIAL_SCAN 0x08000000 | ||
248 | #define ATTR_RANDOM_ACCESS 0x10000000 | ||
249 | #define ATTR_NO_BUFFERING 0x20000000 | ||
250 | #define ATTR_WRITE_THROUGH 0x80000000 | ||
251 | |||
252 | /* ShareAccess flags */ | ||
253 | #define FILE_NO_SHARE 0x00000000 | ||
254 | #define FILE_SHARE_READ 0x00000001 | ||
255 | #define FILE_SHARE_WRITE 0x00000002 | ||
256 | #define FILE_SHARE_DELETE 0x00000004 | ||
257 | #define FILE_SHARE_ALL 0x00000007 | ||
258 | |||
259 | /* CreateDisposition flags */ | ||
260 | #define FILE_SUPERSEDE 0x00000000 | ||
261 | #define FILE_OPEN 0x00000001 | ||
262 | #define FILE_CREATE 0x00000002 | ||
263 | #define FILE_OPEN_IF 0x00000003 | ||
264 | #define FILE_OVERWRITE 0x00000004 | ||
265 | #define FILE_OVERWRITE_IF 0x00000005 | ||
266 | |||
267 | /* CreateOptions */ | ||
268 | #define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ | ||
269 | #define CREATE_WRITE_THROUGH 0x00000002 | ||
270 | #define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ | ||
271 | #define CREATE_RANDOM_ACCESS 0x00000800 | ||
272 | #define CREATE_DELETE_ON_CLOSE 0x00001000 | ||
273 | #define OPEN_REPARSE_POINT 0x00200000 | ||
274 | |||
275 | /* ImpersonationLevel flags */ | ||
276 | #define SECURITY_ANONYMOUS 0 | ||
277 | #define SECURITY_IDENTIFICATION 1 | ||
278 | #define SECURITY_IMPERSONATION 2 | ||
279 | #define SECURITY_DELEGATION 3 | ||
280 | |||
281 | /* SecurityFlags */ | ||
282 | #define SECURITY_CONTEXT_TRACKING 0x01 | ||
283 | #define SECURITY_EFFECTIVE_ONLY 0x02 | ||
284 | |||
285 | /* | ||
286 | * Default PID value, used in all SMBs where the PID is not important | ||
287 | */ | ||
288 | #define CIFS_DFT_PID 0x1234 | ||
289 | |||
290 | /* | ||
291 | * We use the same routine for Copy and Move SMBs. This flag is used to | ||
292 | * distinguish | ||
293 | */ | ||
294 | #define CIFS_COPY_OP 1 | ||
295 | #define CIFS_RENAME_OP 2 | ||
296 | |||
297 | #define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ | ||
298 | #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ | ||
299 | |||
300 | #pragma pack(1) | ||
301 | |||
302 | struct smb_hdr { | ||
303 | __u32 smb_buf_length; /* big endian on wire *//* BB length is only two or three bytes - with one or two byte type preceding it but that is always zero - we could mask the type byte off just in case BB */ | ||
304 | __u8 Protocol[4]; | ||
305 | __u8 Command; | ||
306 | union { | ||
307 | struct { | ||
308 | __u8 ErrorClass; | ||
309 | __u8 Reserved; | ||
310 | __le16 Error; | ||
311 | } DosError; | ||
312 | __le32 CifsError; | ||
313 | } Status; | ||
314 | __u8 Flags; | ||
315 | __le16 Flags2; /* note: le */ | ||
316 | __le16 PidHigh; | ||
317 | union { | ||
318 | struct { | ||
319 | __le32 SequenceNumber; /* le */ | ||
320 | __u32 Reserved; /* zero */ | ||
321 | } Sequence; | ||
322 | __u8 SecuritySignature[8]; /* le */ | ||
323 | } Signature; | ||
324 | __u8 pad[2]; | ||
325 | __u16 Tid; | ||
326 | __le16 Pid; | ||
327 | __u16 Uid; | ||
328 | __u16 Mid; | ||
329 | __u8 WordCount; | ||
330 | }; | ||
331 | /* given a pointer to an smb_hdr retrieve the value of byte count */ | ||
332 | #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) | ||
333 | |||
334 | /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ | ||
335 | #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) | ||
336 | |||
337 | /* | ||
338 | * Computer Name Length | ||
339 | */ | ||
340 | #define CNLEN 15 | ||
341 | |||
342 | /* | ||
343 | * Share Name Length @S8A | ||
344 | * Note: This length is limited by the SMB used to get @S8A | ||
345 | * the Share info. NetShareEnum only returns 13 @S8A | ||
346 | * chars, including the null termination. @S8A | ||
347 | */ | ||
348 | #define SNLEN 12 /*@S8A */ | ||
349 | |||
350 | /* | ||
351 | * Comment Length | ||
352 | */ | ||
353 | #define MAXCOMMENTLEN 40 | ||
354 | |||
355 | /* | ||
356 | * The OS/2 maximum path name | ||
357 | */ | ||
358 | #define MAX_PATHCONF 256 | ||
359 | |||
360 | /* | ||
361 | * SMB frame definitions (following must be packed structs) | ||
362 | * See the SNIA CIFS Specification for details. | ||
363 | * | ||
364 | * The Naming convention is the lower case version of the | ||
365 | * smb command code name for the struct and this is typedef to the | ||
366 | * uppercase version of the same name with the prefix SMB_ removed | ||
367 | * for brevity. Although typedefs are not commonly used for | ||
368 | * structure definitions in the Linux kernel, their use in the | ||
369 | * CIFS standards document, which this code is based on, may | ||
370 | * make this one of the cases where typedefs for structures make | ||
371 | * sense to improve readability for readers of the standards doc. | ||
372 | * Typedefs can always be removed later if they are too distracting | ||
373 | * and they are only used for the CIFSs PDUs themselves, not | ||
374 | * internal cifs vfs structures | ||
375 | * | ||
376 | */ | ||
377 | |||
378 | typedef struct negotiate_req { | ||
379 | struct smb_hdr hdr; /* wct = 0 */ | ||
380 | __le16 ByteCount; | ||
381 | unsigned char DialectsArray[1]; | ||
382 | } NEGOTIATE_REQ; | ||
383 | |||
384 | typedef struct negotiate_rsp { | ||
385 | struct smb_hdr hdr; /* wct = 17 */ | ||
386 | __le16 DialectIndex; | ||
387 | __u8 SecurityMode; | ||
388 | __le16 MaxMpxCount; | ||
389 | __le16 MaxNumberVcs; | ||
390 | __le32 MaxBufferSize; | ||
391 | __le32 MaxRawSize; | ||
392 | __le32 SessionKey; | ||
393 | __le32 Capabilities; /* see below */ | ||
394 | __le32 SystemTimeLow; | ||
395 | __le32 SystemTimeHigh; | ||
396 | __le16 ServerTimeZone; | ||
397 | __u8 EncryptionKeyLength; | ||
398 | __u16 ByteCount; | ||
399 | union { | ||
400 | unsigned char EncryptionKey[1]; /* if cap extended security is off */ | ||
401 | /* followed by Domain name - if extended security is off */ | ||
402 | /* followed by 16 bytes of server GUID */ | ||
403 | /* followed by security blob if cap_extended_security negotiated */ | ||
404 | struct { | ||
405 | unsigned char GUID[16]; | ||
406 | unsigned char SecurityBlob[1]; | ||
407 | } extended_response; | ||
408 | } u; | ||
409 | } NEGOTIATE_RSP; | ||
410 | |||
411 | /* SecurityMode bits */ | ||
412 | #define SECMODE_USER 0x01 /* off indicates share level security */ | ||
413 | #define SECMODE_PW_ENCRYPT 0x02 | ||
414 | #define SECMODE_SIGN_ENABLED 0x04 /* SMB security signatures enabled */ | ||
415 | #define SECMODE_SIGN_REQUIRED 0x08 /* SMB security signatures required */ | ||
416 | |||
417 | /* Negotiate response Capabilities */ | ||
418 | #define CAP_RAW_MODE 0x00000001 | ||
419 | #define CAP_MPX_MODE 0x00000002 | ||
420 | #define CAP_UNICODE 0x00000004 | ||
421 | #define CAP_LARGE_FILES 0x00000008 | ||
422 | #define CAP_NT_SMBS 0x00000010 /* implies CAP_NT_FIND */ | ||
423 | #define CAP_RPC_REMOTE_APIS 0x00000020 | ||
424 | #define CAP_STATUS32 0x00000040 | ||
425 | #define CAP_LEVEL_II_OPLOCKS 0x00000080 | ||
426 | #define CAP_LOCK_AND_READ 0x00000100 | ||
427 | #define CAP_NT_FIND 0x00000200 | ||
428 | #define CAP_DFS 0x00001000 | ||
429 | #define CAP_INFOLEVEL_PASSTHRU 0x00002000 | ||
430 | #define CAP_LARGE_READ_X 0x00004000 | ||
431 | #define CAP_LARGE_WRITE_X 0x00008000 | ||
432 | #define CAP_UNIX 0x00800000 | ||
433 | #define CAP_RESERVED 0x02000000 | ||
434 | #define CAP_BULK_TRANSFER 0x20000000 | ||
435 | #define CAP_COMPRESSED_DATA 0x40000000 | ||
436 | #define CAP_EXTENDED_SECURITY 0x80000000 | ||
437 | |||
438 | typedef union smb_com_session_setup_andx { | ||
439 | struct { /* request format */ | ||
440 | struct smb_hdr hdr; /* wct = 12 */ | ||
441 | __u8 AndXCommand; | ||
442 | __u8 AndXReserved; | ||
443 | __le16 AndXOffset; | ||
444 | __le16 MaxBufferSize; | ||
445 | __le16 MaxMpxCount; | ||
446 | __le16 VcNumber; | ||
447 | __u32 SessionKey; | ||
448 | __le16 SecurityBlobLength; | ||
449 | __u32 Reserved; | ||
450 | __le32 Capabilities; /* see below */ | ||
451 | __le16 ByteCount; | ||
452 | unsigned char SecurityBlob[1]; /* followed by */ | ||
453 | /* STRING NativeOS */ | ||
454 | /* STRING NativeLanMan */ | ||
455 | } req; /* NTLM request format (with extended security */ | ||
456 | |||
457 | struct { /* request format */ | ||
458 | struct smb_hdr hdr; /* wct = 13 */ | ||
459 | __u8 AndXCommand; | ||
460 | __u8 AndXReserved; | ||
461 | __le16 AndXOffset; | ||
462 | __le16 MaxBufferSize; | ||
463 | __le16 MaxMpxCount; | ||
464 | __le16 VcNumber; | ||
465 | __u32 SessionKey; | ||
466 | __le16 CaseInsensitivePasswordLength; /* ASCII password length */ | ||
467 | __le16 CaseSensitivePasswordLength; /* Unicode password length */ | ||
468 | __u32 Reserved; /* see below */ | ||
469 | __le32 Capabilities; | ||
470 | __le16 ByteCount; | ||
471 | unsigned char CaseInsensitivePassword[1]; /* followed by: */ | ||
472 | /* unsigned char * CaseSensitivePassword; */ | ||
473 | /* STRING AccountName */ | ||
474 | /* STRING PrimaryDomain */ | ||
475 | /* STRING NativeOS */ | ||
476 | /* STRING NativeLanMan */ | ||
477 | } req_no_secext; /* NTLM request format (without extended security */ | ||
478 | |||
479 | struct { /* default (NTLM) response format */ | ||
480 | struct smb_hdr hdr; /* wct = 4 */ | ||
481 | __u8 AndXCommand; | ||
482 | __u8 AndXReserved; | ||
483 | __le16 AndXOffset; | ||
484 | __le16 Action; /* see below */ | ||
485 | __le16 SecurityBlobLength; | ||
486 | __u16 ByteCount; | ||
487 | unsigned char SecurityBlob[1]; /* followed by */ | ||
488 | /* unsigned char * NativeOS; */ | ||
489 | /* unsigned char * NativeLanMan; */ | ||
490 | /* unsigned char * PrimaryDomain; */ | ||
491 | } resp; /* NTLM response format (with or without extended security */ | ||
492 | |||
493 | struct { /* request format */ | ||
494 | struct smb_hdr hdr; /* wct = 10 */ | ||
495 | __u8 AndXCommand; | ||
496 | __u8 AndXReserved; | ||
497 | __le16 AndXOffset; | ||
498 | __le16 MaxBufferSize; | ||
499 | __le16 MaxMpxCount; | ||
500 | __le16 VcNumber; | ||
501 | __u32 SessionKey; | ||
502 | __le16 PassswordLength; | ||
503 | __u32 Reserved; | ||
504 | __le16 ByteCount; | ||
505 | unsigned char AccountPassword[1]; /* followed by */ | ||
506 | /* STRING AccountName */ | ||
507 | /* STRING PrimaryDomain */ | ||
508 | /* STRING NativeOS */ | ||
509 | /* STRING NativeLanMan */ | ||
510 | } old_req; /* pre-NTLM (LANMAN2.1) request format */ | ||
511 | |||
512 | struct { /* default (NTLM) response format */ | ||
513 | struct smb_hdr hdr; /* wct = 3 */ | ||
514 | __u8 AndXCommand; | ||
515 | __u8 AndXReserved; | ||
516 | __le16 AndXOffset; | ||
517 | __le16 Action; /* see below */ | ||
518 | __u16 ByteCount; | ||
519 | unsigned char NativeOS[1]; /* followed by */ | ||
520 | /* unsigned char * NativeLanMan; */ | ||
521 | /* unsigned char * PrimaryDomain; */ | ||
522 | } old_resp; /* pre-NTLM (LANMAN2.1) response format */ | ||
523 | } SESSION_SETUP_ANDX; | ||
524 | |||
525 | #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" | ||
526 | |||
527 | /* Capabilities bits (for NTLM SessSetup request) */ | ||
528 | #define CAP_UNICODE 0x00000004 | ||
529 | #define CAP_LARGE_FILES 0x00000008 | ||
530 | #define CAP_NT_SMBS 0x00000010 | ||
531 | #define CAP_STATUS32 0x00000040 | ||
532 | #define CAP_LEVEL_II_OPLOCKS 0x00000080 | ||
533 | #define CAP_NT_FIND 0x00000200 /* reserved should be zero (presumably because NT_SMBs implies the same thing) */ | ||
534 | #define CAP_BULK_TRANSFER 0x20000000 | ||
535 | #define CAP_EXTENDED_SECURITY 0x80000000 | ||
536 | |||
537 | /* Action bits */ | ||
538 | #define GUEST_LOGIN 1 | ||
539 | |||
540 | typedef struct smb_com_tconx_req { | ||
541 | struct smb_hdr hdr; /* wct = 4 */ | ||
542 | __u8 AndXCommand; | ||
543 | __u8 AndXReserved; | ||
544 | __le16 AndXOffset; | ||
545 | __le16 Flags; /* see below */ | ||
546 | __le16 PasswordLength; | ||
547 | __le16 ByteCount; | ||
548 | unsigned char Password[1]; /* followed by */ | ||
549 | /* STRING Path *//* \\server\share name */ | ||
550 | /* STRING Service */ | ||
551 | } TCONX_REQ; | ||
552 | |||
553 | typedef struct smb_com_tconx_rsp { | ||
554 | struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ | ||
555 | __u8 AndXCommand; | ||
556 | __u8 AndXReserved; | ||
557 | __le16 AndXOffset; | ||
558 | __le16 OptionalSupport; /* see below */ | ||
559 | __u16 ByteCount; | ||
560 | unsigned char Service[1]; /* always ASCII, not Unicode */ | ||
561 | /* STRING NativeFileSystem */ | ||
562 | } TCONX_RSP; | ||
563 | |||
564 | /* tree connect Flags */ | ||
565 | #define DISCONNECT_TID 0x0001 | ||
566 | #define TCON_EXTENDED_SECINFO 0x0008 | ||
567 | /* OptionalSupport bits */ | ||
568 | #define SMB_SUPPORT_SEARCH_BITS 0x0001 /* must have bits (exclusive searches suppt. */ | ||
569 | #define SMB_SHARE_IS_IN_DFS 0x0002 | ||
570 | |||
571 | typedef struct smb_com_logoff_andx_req { | ||
572 | struct smb_hdr hdr; /* wct = 2 */ | ||
573 | __u8 AndXCommand; | ||
574 | __u8 AndXReserved; | ||
575 | __u16 AndXOffset; | ||
576 | __u16 ByteCount; | ||
577 | } LOGOFF_ANDX_REQ; | ||
578 | |||
579 | typedef struct smb_com_logoff_andx_rsp { | ||
580 | struct smb_hdr hdr; /* wct = 2 */ | ||
581 | __u8 AndXCommand; | ||
582 | __u8 AndXReserved; | ||
583 | __u16 AndXOffset; | ||
584 | __u16 ByteCount; | ||
585 | } LOGOFF_ANDX_RSP; | ||
586 | |||
587 | typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */ | ||
588 | struct { | ||
589 | struct smb_hdr hdr; /* wct = 0 */ | ||
590 | __u16 ByteCount; /* bcc = 0 */ | ||
591 | } req; | ||
592 | struct { | ||
593 | struct smb_hdr hdr; /* wct = 0 */ | ||
594 | __u16 ByteCount; /* bcc = 0 */ | ||
595 | } resp; | ||
596 | } TREE_DISCONNECT; | ||
597 | |||
598 | typedef struct smb_com_close_req { | ||
599 | struct smb_hdr hdr; /* wct = 3 */ | ||
600 | __u16 FileID; | ||
601 | __u32 LastWriteTime; /* should be zero */ | ||
602 | __u16 ByteCount; /* 0 */ | ||
603 | } CLOSE_REQ; | ||
604 | |||
605 | typedef struct smb_com_close_rsp { | ||
606 | struct smb_hdr hdr; /* wct = 0 */ | ||
607 | __u16 ByteCount; /* bct = 0 */ | ||
608 | } CLOSE_RSP; | ||
609 | |||
610 | typedef struct smb_com_findclose_req { | ||
611 | struct smb_hdr hdr; /* wct = 1 */ | ||
612 | __u16 FileID; | ||
613 | __u16 ByteCount; /* 0 */ | ||
614 | } FINDCLOSE_REQ; | ||
615 | |||
616 | /* OpenFlags */ | ||
617 | #define REQ_OPLOCK 0x00000002 | ||
618 | #define REQ_BATCHOPLOCK 0x00000004 | ||
619 | #define REQ_OPENDIRONLY 0x00000008 | ||
620 | |||
621 | typedef struct smb_com_open_req { /* also handles create */ | ||
622 | struct smb_hdr hdr; /* wct = 24 */ | ||
623 | __u8 AndXCommand; | ||
624 | __u8 AndXReserved; | ||
625 | __le16 AndXOffset; | ||
626 | __u8 Reserved; /* Must Be Zero */ | ||
627 | __le16 NameLength; | ||
628 | __le32 OpenFlags; | ||
629 | __le32 RootDirectoryFid; | ||
630 | __le32 DesiredAccess; | ||
631 | __le64 AllocationSize; | ||
632 | __le32 FileAttributes; | ||
633 | __le32 ShareAccess; | ||
634 | __le32 CreateDisposition; | ||
635 | __le32 CreateOptions; | ||
636 | __le32 ImpersonationLevel; | ||
637 | __u8 SecurityFlags; | ||
638 | __le16 ByteCount; | ||
639 | char fileName[1]; | ||
640 | } OPEN_REQ; | ||
641 | |||
642 | /* open response: oplock levels */ | ||
643 | #define OPLOCK_NONE 0 | ||
644 | #define OPLOCK_EXCLUSIVE 1 | ||
645 | #define OPLOCK_BATCH 2 | ||
646 | #define OPLOCK_READ 3 /* level 2 oplock */ | ||
647 | |||
648 | /* open response for CreateAction shifted left */ | ||
649 | #define CIFS_CREATE_ACTION 0x20000 /* file created */ | ||
650 | |||
651 | typedef struct smb_com_open_rsp { | ||
652 | struct smb_hdr hdr; /* wct = 34 BB */ | ||
653 | __u8 AndXCommand; | ||
654 | __u8 AndXReserved; | ||
655 | __le16 AndXOffset; | ||
656 | __u8 OplockLevel; | ||
657 | __u16 Fid; | ||
658 | __le32 CreateAction; | ||
659 | __le64 CreationTime; | ||
660 | __le64 LastAccessTime; | ||
661 | __le64 LastWriteTime; | ||
662 | __le64 ChangeTime; | ||
663 | __le32 FileAttributes; | ||
664 | __le64 AllocationSize; | ||
665 | __le64 EndOfFile; | ||
666 | __le16 FileType; | ||
667 | __le16 DeviceState; | ||
668 | __u8 DirectoryFlag; | ||
669 | __u16 ByteCount; /* bct = 0 */ | ||
670 | } OPEN_RSP; | ||
671 | |||
672 | typedef struct smb_com_write_req { | ||
673 | struct smb_hdr hdr; /* wct = 14 */ | ||
674 | __u8 AndXCommand; | ||
675 | __u8 AndXReserved; | ||
676 | __le16 AndXOffset; | ||
677 | __u16 Fid; | ||
678 | __le32 OffsetLow; | ||
679 | __u32 Reserved; | ||
680 | __le16 WriteMode; | ||
681 | __le16 Remaining; | ||
682 | __le16 DataLengthHigh; | ||
683 | __le16 DataLengthLow; | ||
684 | __le16 DataOffset; | ||
685 | __le32 OffsetHigh; | ||
686 | __le16 ByteCount; | ||
687 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ | ||
688 | char Data[0]; | ||
689 | } WRITE_REQ; | ||
690 | |||
691 | typedef struct smb_com_write_rsp { | ||
692 | struct smb_hdr hdr; /* wct = 6 */ | ||
693 | __u8 AndXCommand; | ||
694 | __u8 AndXReserved; | ||
695 | __le16 AndXOffset; | ||
696 | __le16 Count; | ||
697 | __le16 Remaining; | ||
698 | __le16 CountHigh; | ||
699 | __u16 Reserved; | ||
700 | __u16 ByteCount; | ||
701 | } WRITE_RSP; | ||
702 | |||
703 | typedef struct smb_com_read_req { | ||
704 | struct smb_hdr hdr; /* wct = 12 */ | ||
705 | __u8 AndXCommand; | ||
706 | __u8 AndXReserved; | ||
707 | __le16 AndXOffset; | ||
708 | __u16 Fid; | ||
709 | __le32 OffsetLow; | ||
710 | __le16 MaxCount; | ||
711 | __le16 MinCount; /* obsolete */ | ||
712 | __le32 MaxCountHigh; | ||
713 | __le16 Remaining; | ||
714 | __le32 OffsetHigh; | ||
715 | __le16 ByteCount; | ||
716 | } READ_REQ; | ||
717 | |||
718 | typedef struct smb_com_read_rsp { | ||
719 | struct smb_hdr hdr; /* wct = 12 */ | ||
720 | __u8 AndXCommand; | ||
721 | __u8 AndXReserved; | ||
722 | __le16 AndXOffset; | ||
723 | __le16 Remaining; | ||
724 | __le16 DataCompactionMode; | ||
725 | __le16 Reserved; | ||
726 | __le16 DataLength; | ||
727 | __le16 DataOffset; | ||
728 | __le16 DataLengthHigh; | ||
729 | __u64 Reserved2; | ||
730 | __u16 ByteCount; | ||
731 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ | ||
732 | char Data[1]; | ||
733 | } READ_RSP; | ||
734 | |||
735 | typedef struct locking_andx_range { | ||
736 | __le16 Pid; | ||
737 | __le16 Pad; | ||
738 | __le32 OffsetHigh; | ||
739 | __le32 OffsetLow; | ||
740 | __le32 LengthHigh; | ||
741 | __le32 LengthLow; | ||
742 | } LOCKING_ANDX_RANGE; | ||
743 | |||
744 | #define LOCKING_ANDX_SHARED_LOCK 0x01 | ||
745 | #define LOCKING_ANDX_OPLOCK_RELEASE 0x02 | ||
746 | #define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 | ||
747 | #define LOCKING_ANDX_CANCEL_LOCK 0x08 | ||
748 | #define LOCKING_ANDX_LARGE_FILES 0x10 /* always on for us */ | ||
749 | |||
750 | typedef struct smb_com_lock_req { | ||
751 | struct smb_hdr hdr; /* wct = 8 */ | ||
752 | __u8 AndXCommand; | ||
753 | __u8 AndXReserved; | ||
754 | __le16 AndXOffset; | ||
755 | __u16 Fid; | ||
756 | __u8 LockType; | ||
757 | __u8 OplockLevel; | ||
758 | __le32 Timeout; | ||
759 | __le16 NumberOfUnlocks; | ||
760 | __le16 NumberOfLocks; | ||
761 | __le16 ByteCount; | ||
762 | LOCKING_ANDX_RANGE Locks[1]; | ||
763 | } LOCK_REQ; | ||
764 | |||
765 | typedef struct smb_com_lock_rsp { | ||
766 | struct smb_hdr hdr; /* wct = 2 */ | ||
767 | __u8 AndXCommand; | ||
768 | __u8 AndXReserved; | ||
769 | __le16 AndXOffset; | ||
770 | __u16 ByteCount; | ||
771 | } LOCK_RSP; | ||
772 | |||
773 | typedef struct smb_com_rename_req { | ||
774 | struct smb_hdr hdr; /* wct = 1 */ | ||
775 | __le16 SearchAttributes; /* target file attributes */ | ||
776 | __le16 ByteCount; | ||
777 | __u8 BufferFormat; /* 4 = ASCII or Unicode */ | ||
778 | unsigned char OldFileName[1]; | ||
779 | /* followed by __u8 BufferFormat2 */ | ||
780 | /* followed by NewFileName */ | ||
781 | } RENAME_REQ; | ||
782 | |||
783 | /* copy request flags */ | ||
784 | #define COPY_MUST_BE_FILE 0x0001 | ||
785 | #define COPY_MUST_BE_DIR 0x0002 | ||
786 | #define COPY_TARGET_MODE_ASCII 0x0004 /* if not set, binary */ | ||
787 | #define COPY_SOURCE_MODE_ASCII 0x0008 /* if not set, binary */ | ||
788 | #define COPY_VERIFY_WRITES 0x0010 | ||
789 | #define COPY_TREE 0x0020 | ||
790 | |||
791 | typedef struct smb_com_copy_req { | ||
792 | struct smb_hdr hdr; /* wct = 3 */ | ||
793 | __u16 Tid2; | ||
794 | __le16 OpenFunction; | ||
795 | __le16 Flags; | ||
796 | __le16 ByteCount; | ||
797 | __u8 BufferFormat; /* 4 = ASCII or Unicode */ | ||
798 | unsigned char OldFileName[1]; | ||
799 | /* followed by __u8 BufferFormat2 */ | ||
800 | /* followed by NewFileName string */ | ||
801 | } COPY_REQ; | ||
802 | |||
803 | typedef struct smb_com_copy_rsp { | ||
804 | struct smb_hdr hdr; /* wct = 1 */ | ||
805 | __le16 CopyCount; /* number of files copied */ | ||
806 | __u16 ByteCount; /* may be zero */ | ||
807 | __u8 BufferFormat; /* 0x04 - only present if errored file follows */ | ||
808 | unsigned char ErrorFileName[1]; /* only present if error in copy */ | ||
809 | } COPY_RSP; | ||
810 | |||
811 | #define CREATE_HARD_LINK 0x103 | ||
812 | #define MOVEFILE_COPY_ALLOWED 0x0002 | ||
813 | #define MOVEFILE_REPLACE_EXISTING 0x0001 | ||
814 | |||
815 | typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */ | ||
816 | struct smb_hdr hdr; /* wct = 4 */ | ||
817 | __le16 SearchAttributes; /* target file attributes */ | ||
818 | __le16 Flags; /* spec says Information Level */ | ||
819 | __le32 ClusterCount; | ||
820 | __le16 ByteCount; | ||
821 | __u8 BufferFormat; /* 4 = ASCII or Unicode */ | ||
822 | unsigned char OldFileName[1]; | ||
823 | /* followed by __u8 BufferFormat2 */ | ||
824 | /* followed by NewFileName */ | ||
825 | } NT_RENAME_REQ; | ||
826 | |||
827 | typedef struct smb_com_rename_rsp { | ||
828 | struct smb_hdr hdr; /* wct = 0 */ | ||
829 | __u16 ByteCount; /* bct = 0 */ | ||
830 | } RENAME_RSP; | ||
831 | |||
832 | typedef struct smb_com_delete_file_req { | ||
833 | struct smb_hdr hdr; /* wct = 1 */ | ||
834 | __le16 SearchAttributes; | ||
835 | __le16 ByteCount; | ||
836 | __u8 BufferFormat; /* 4 = ASCII */ | ||
837 | unsigned char fileName[1]; | ||
838 | } DELETE_FILE_REQ; | ||
839 | |||
840 | typedef struct smb_com_delete_file_rsp { | ||
841 | struct smb_hdr hdr; /* wct = 0 */ | ||
842 | __u16 ByteCount; /* bct = 0 */ | ||
843 | } DELETE_FILE_RSP; | ||
844 | |||
845 | typedef struct smb_com_delete_directory_req { | ||
846 | struct smb_hdr hdr; /* wct = 0 */ | ||
847 | __le16 ByteCount; | ||
848 | __u8 BufferFormat; /* 4 = ASCII */ | ||
849 | unsigned char DirName[1]; | ||
850 | } DELETE_DIRECTORY_REQ; | ||
851 | |||
852 | typedef struct smb_com_delete_directory_rsp { | ||
853 | struct smb_hdr hdr; /* wct = 0 */ | ||
854 | __u16 ByteCount; /* bct = 0 */ | ||
855 | } DELETE_DIRECTORY_RSP; | ||
856 | |||
857 | typedef struct smb_com_create_directory_req { | ||
858 | struct smb_hdr hdr; /* wct = 0 */ | ||
859 | __le16 ByteCount; | ||
860 | __u8 BufferFormat; /* 4 = ASCII */ | ||
861 | unsigned char DirName[1]; | ||
862 | } CREATE_DIRECTORY_REQ; | ||
863 | |||
864 | typedef struct smb_com_create_directory_rsp { | ||
865 | struct smb_hdr hdr; /* wct = 0 */ | ||
866 | __u16 ByteCount; /* bct = 0 */ | ||
867 | } CREATE_DIRECTORY_RSP; | ||
868 | |||
869 | typedef struct smb_com_setattr_req { | ||
870 | struct smb_hdr hdr; /* wct = 8 */ | ||
871 | __le16 attr; | ||
872 | __le16 time_low; | ||
873 | __le16 time_high; | ||
874 | __le16 reserved[5]; /* must be zero */ | ||
875 | __u16 ByteCount; | ||
876 | __u8 BufferFormat; /* 4 = ASCII */ | ||
877 | unsigned char fileName[1]; | ||
878 | } SETATTR_REQ; | ||
879 | |||
880 | typedef struct smb_com_setattr_rsp { | ||
881 | struct smb_hdr hdr; /* wct = 0 */ | ||
882 | __u16 ByteCount; /* bct = 0 */ | ||
883 | } SETATTR_RSP; | ||
884 | |||
885 | /* empty wct response to setattr */ | ||
886 | |||
887 | /***************************************************/ | ||
888 | /* NT Transact structure defintions follow */ | ||
889 | /* Currently only ioctl and notify are implemented */ | ||
890 | /***************************************************/ | ||
891 | typedef struct smb_com_transaction_ioctl_req { | ||
892 | struct smb_hdr hdr; /* wct = 23 */ | ||
893 | __u8 MaxSetupCount; | ||
894 | __u16 Reserved; | ||
895 | __le32 TotalParameterCount; | ||
896 | __le32 TotalDataCount; | ||
897 | __le32 MaxParameterCount; | ||
898 | __le32 MaxDataCount; | ||
899 | __le32 ParameterCount; | ||
900 | __le32 ParameterOffset; | ||
901 | __le32 DataCount; | ||
902 | __le32 DataOffset; | ||
903 | __u8 SetupCount; /* four setup words follow subcommand */ | ||
904 | /* SNIA spec incorrectly included spurious pad here */ | ||
905 | __le16 SubCommand;/* 2 = IOCTL/FSCTL */ | ||
906 | __le32 FunctionCode; | ||
907 | __u16 Fid; | ||
908 | __u8 IsFsctl; /* 1 = File System Control, 0 = device control (IOCTL)*/ | ||
909 | __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/ | ||
910 | __le16 ByteCount; | ||
911 | __u8 Pad[3]; | ||
912 | __u8 Data[1]; | ||
913 | } TRANSACT_IOCTL_REQ; | ||
914 | |||
915 | typedef struct smb_com_transaction_ioctl_rsp { | ||
916 | struct smb_hdr hdr; /* wct = 19 */ | ||
917 | __u8 Reserved[3]; | ||
918 | __le32 TotalParameterCount; | ||
919 | __le32 TotalDataCount; | ||
920 | __le32 ParameterCount; | ||
921 | __le32 ParameterOffset; | ||
922 | __le32 ParameterDisplacement; | ||
923 | __le32 DataCount; | ||
924 | __le32 DataOffset; | ||
925 | __le32 DataDisplacement; | ||
926 | __u8 SetupCount; /* 1 */ | ||
927 | __le16 ReturnedDataLen; | ||
928 | __u16 ByteCount; | ||
929 | __u8 Pad[3]; | ||
930 | } TRANSACT_IOCTL_RSP; | ||
931 | |||
932 | typedef struct smb_com_transaction_change_notify_req { | ||
933 | struct smb_hdr hdr; /* wct = 23 */ | ||
934 | __u8 MaxSetupCount; | ||
935 | __u16 Reserved; | ||
936 | __le32 TotalParameterCount; | ||
937 | __le32 TotalDataCount; | ||
938 | __le32 MaxParameterCount; | ||
939 | __le32 MaxDataCount; | ||
940 | __le32 ParameterCount; | ||
941 | __le32 ParameterOffset; | ||
942 | __le32 DataCount; | ||
943 | __le32 DataOffset; | ||
944 | __u8 SetupCount; /* four setup words follow subcommand */ | ||
945 | /* SNIA spec incorrectly included spurious pad here */ | ||
946 | __le16 SubCommand;/* 4 = Change Notify */ | ||
947 | __le32 CompletionFilter; /* operation to monitor */ | ||
948 | __u16 Fid; | ||
949 | __u8 WatchTree; /* 1 = Monitor subdirectories */ | ||
950 | __u8 Reserved2; | ||
951 | __le16 ByteCount; | ||
952 | /* __u8 Pad[3];*/ | ||
953 | /* __u8 Data[1];*/ | ||
954 | } TRANSACT_CHANGE_NOTIFY_REQ; | ||
955 | |||
956 | typedef struct smb_com_transaction_change_notify_rsp { | ||
957 | struct smb_hdr hdr; /* wct = 18 */ | ||
958 | __u8 Reserved[3]; | ||
959 | __le32 TotalParameterCount; | ||
960 | __le32 TotalDataCount; | ||
961 | __le32 ParameterCount; | ||
962 | __le32 ParameterOffset; | ||
963 | __le32 ParameterDisplacement; | ||
964 | __le32 DataCount; | ||
965 | __le32 DataOffset; | ||
966 | __le32 DataDisplacement; | ||
967 | __u8 SetupCount; /* 0 */ | ||
968 | __u16 ByteCount; | ||
969 | /* __u8 Pad[3]; */ | ||
970 | } TRANSACT_CHANGE_NOTIFY_RSP; | ||
971 | /* Completion Filter flags for Notify */ | ||
972 | #define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 | ||
973 | #define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 | ||
974 | #define FILE_NOTIFY_CHANGE_NAME 0x00000003 | ||
975 | #define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 | ||
976 | #define FILE_NOTIFY_CHANGE_SIZE 0x00000008 | ||
977 | #define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 | ||
978 | #define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 | ||
979 | #define FILE_NOTIFY_CHANGE_CREATION 0x00000040 | ||
980 | #define FILE_NOTIFY_CHANGE_EA 0x00000080 | ||
981 | #define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 | ||
982 | #define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200 | ||
983 | #define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400 | ||
984 | #define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800 | ||
985 | |||
986 | #define FILE_ACTION_ADDED 0x00000001 | ||
987 | #define FILE_ACTION_REMOVED 0x00000002 | ||
988 | #define FILE_ACTION_MODIFIED 0x00000003 | ||
989 | #define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 | ||
990 | #define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 | ||
991 | #define FILE_ACTION_ADDED_STREAM 0x00000006 | ||
992 | #define FILE_ACTION_REMOVED_STREAM 0x00000007 | ||
993 | #define FILE_ACTION_MODIFIED_STREAM 0x00000008 | ||
994 | |||
995 | /* response contains array of the following structures */ | ||
996 | struct file_notify_information { | ||
997 | __le32 NextEntryOffset; | ||
998 | __le32 Action; | ||
999 | __le32 FileNameLength; | ||
1000 | __u8 FileName[0]; | ||
1001 | }; | ||
1002 | |||
1003 | struct reparse_data { | ||
1004 | __u32 ReparseTag; | ||
1005 | __u16 ReparseDataLength; | ||
1006 | __u16 Reserved; | ||
1007 | __u16 AltNameOffset; | ||
1008 | __u16 AltNameLen; | ||
1009 | __u16 TargetNameOffset; | ||
1010 | __u16 TargetNameLen; | ||
1011 | char LinkNamesBuf[1]; | ||
1012 | }; | ||
1013 | |||
1014 | struct cifs_quota_data { | ||
1015 | __u32 rsrvd1; /* 0 */ | ||
1016 | __u32 sid_size; | ||
1017 | __u64 rsrvd2; /* 0 */ | ||
1018 | __u64 space_used; | ||
1019 | __u64 soft_limit; | ||
1020 | __u64 hard_limit; | ||
1021 | char sid[1]; /* variable size? */ | ||
1022 | }; | ||
1023 | |||
1024 | /* quota sub commands */ | ||
1025 | #define QUOTA_LIST_CONTINUE 0 | ||
1026 | #define QUOTA_LIST_START 0x100 | ||
1027 | #define QUOTA_FOR_SID 0x101 | ||
1028 | |||
1029 | struct trans2_req { | ||
1030 | /* struct smb_hdr hdr precedes. Set wct = 14+ */ | ||
1031 | __le16 TotalParameterCount; | ||
1032 | __le16 TotalDataCount; | ||
1033 | __le16 MaxParameterCount; | ||
1034 | __le16 MaxDataCount; | ||
1035 | __u8 MaxSetupCount; | ||
1036 | __u8 Reserved; | ||
1037 | __le16 Flags; | ||
1038 | __le32 Timeout; | ||
1039 | __u16 Reserved2; | ||
1040 | __le16 ParameterCount; | ||
1041 | __le16 ParameterOffset; | ||
1042 | __le16 DataCount; | ||
1043 | __le16 DataOffset; | ||
1044 | __u8 SetupCount; | ||
1045 | __u8 Reserved3; | ||
1046 | __le16 SubCommand; /* 1st setup word - SetupCount words follow */ | ||
1047 | __le16 ByteCount; | ||
1048 | }; | ||
1049 | |||
1050 | struct smb_t2_req { | ||
1051 | struct smb_hdr hdr; | ||
1052 | struct trans2_req t2_req; | ||
1053 | }; | ||
1054 | |||
1055 | struct trans2_resp { | ||
1056 | /* struct smb_hdr hdr precedes. Note wct = 10 + setup count */ | ||
1057 | __le16 TotalParameterCount; | ||
1058 | __le16 TotalDataCount; | ||
1059 | __u16 Reserved; | ||
1060 | __le16 ParameterCount; | ||
1061 | __le16 ParameterOffset; | ||
1062 | __le16 ParameterDisplacement; | ||
1063 | __le16 DataCount; | ||
1064 | __le16 DataOffset; | ||
1065 | __le16 DataDisplacement; | ||
1066 | __u8 SetupCount; | ||
1067 | __u8 Reserved1; | ||
1068 | /* SetupWords[SetupCount]; | ||
1069 | __u16 ByteCount; | ||
1070 | __u16 Reserved2;*/ | ||
1071 | /* data area follows */ | ||
1072 | }; | ||
1073 | |||
1074 | struct smb_t2_rsp { | ||
1075 | struct smb_hdr hdr; | ||
1076 | struct trans2_resp t2_rsp; | ||
1077 | }; | ||
1078 | |||
1079 | /* PathInfo/FileInfo infolevels */ | ||
1080 | #define SMB_INFO_STANDARD 1 | ||
1081 | #define SMB_SET_FILE_EA 2 | ||
1082 | #define SMB_QUERY_FILE_EA_SIZE 2 | ||
1083 | #define SMB_INFO_QUERY_EAS_FROM_LIST 3 | ||
1084 | #define SMB_INFO_QUERY_ALL_EAS 4 | ||
1085 | #define SMB_INFO_IS_NAME_VALID 6 | ||
1086 | #define SMB_QUERY_FILE_BASIC_INFO 0x101 | ||
1087 | #define SMB_QUERY_FILE_STANDARD_INFO 0x102 | ||
1088 | #define SMB_QUERY_FILE_EA_INFO 0x103 | ||
1089 | #define SMB_QUERY_FILE_NAME_INFO 0x104 | ||
1090 | #define SMB_QUERY_FILE_ALLOCATION_INFO 0x105 | ||
1091 | #define SMB_QUERY_FILE_END_OF_FILEINFO 0x106 | ||
1092 | #define SMB_QUERY_FILE_ALL_INFO 0x107 | ||
1093 | #define SMB_QUERY_ALT_NAME_INFO 0x108 | ||
1094 | #define SMB_QUERY_FILE_STREAM_INFO 0x109 | ||
1095 | #define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B | ||
1096 | #define SMB_QUERY_FILE_UNIX_BASIC 0x200 | ||
1097 | #define SMB_QUERY_FILE_UNIX_LINK 0x201 | ||
1098 | #define SMB_QUERY_POSIX_ACL 0x204 | ||
1099 | #define SMB_QUERY_XATTR 0x205 | ||
1100 | #define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */ | ||
1101 | #define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee | ||
1102 | #define SMB_QUERY_FILE_ACCESS_INFO 0x3f0 | ||
1103 | #define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */ | ||
1104 | #define SMB_QUERY_FILE_POSITION_INFO 0x3f6 | ||
1105 | #define SMB_QUERY_FILE_MODE_INFO 0x3f8 | ||
1106 | #define SMB_QUERY_FILE_ALGN_INFO 0x3f9 | ||
1107 | |||
1108 | |||
1109 | #define SMB_SET_FILE_BASIC_INFO 0x101 | ||
1110 | #define SMB_SET_FILE_DISPOSITION_INFO 0x102 | ||
1111 | #define SMB_SET_FILE_ALLOCATION_INFO 0x103 | ||
1112 | #define SMB_SET_FILE_END_OF_FILE_INFO 0x104 | ||
1113 | #define SMB_SET_FILE_UNIX_BASIC 0x200 | ||
1114 | #define SMB_SET_FILE_UNIX_LINK 0x201 | ||
1115 | #define SMB_SET_FILE_UNIX_HLINK 0x203 | ||
1116 | #define SMB_SET_POSIX_ACL 0x204 | ||
1117 | #define SMB_SET_XATTR 0x205 | ||
1118 | #define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */ | ||
1119 | #define SMB_SET_FILE_BASIC_INFO2 0x3ec | ||
1120 | #define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */ | ||
1121 | #define SMB_FILE_ALL_INFO2 0x3fa | ||
1122 | #define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb | ||
1123 | #define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc | ||
1124 | #define SMB_FILE_MOVE_CLUSTER_INFO 0x407 | ||
1125 | #define SMB_FILE_QUOTA_INFO 0x408 | ||
1126 | #define SMB_FILE_REPARSEPOINT_INFO 0x409 | ||
1127 | #define SMB_FILE_MAXIMUM_INFO 0x40d | ||
1128 | |||
1129 | /* Find File infolevels */ | ||
1130 | #define SMB_FIND_FILE_DIRECTORY_INFO 0x101 | ||
1131 | #define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 | ||
1132 | #define SMB_FIND_FILE_NAMES_INFO 0x103 | ||
1133 | #define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104 | ||
1134 | #define SMB_FIND_FILE_ID_FULL_DIR_INFO 0x105 | ||
1135 | #define SMB_FIND_FILE_ID_BOTH_DIR_INFO 0x106 | ||
1136 | #define SMB_FIND_FILE_UNIX 0x202 | ||
1137 | |||
1138 | typedef struct smb_com_transaction2_qpi_req { | ||
1139 | struct smb_hdr hdr; /* wct = 14+ */ | ||
1140 | __le16 TotalParameterCount; | ||
1141 | __le16 TotalDataCount; | ||
1142 | __le16 MaxParameterCount; | ||
1143 | __le16 MaxDataCount; | ||
1144 | __u8 MaxSetupCount; | ||
1145 | __u8 Reserved; | ||
1146 | __le16 Flags; | ||
1147 | __le32 Timeout; | ||
1148 | __u16 Reserved2; | ||
1149 | __le16 ParameterCount; | ||
1150 | __le16 ParameterOffset; | ||
1151 | __le16 DataCount; | ||
1152 | __le16 DataOffset; | ||
1153 | __u8 SetupCount; | ||
1154 | __u8 Reserved3; | ||
1155 | __le16 SubCommand; /* one setup word */ | ||
1156 | __le16 ByteCount; | ||
1157 | __u8 Pad; | ||
1158 | __le16 InformationLevel; | ||
1159 | __u32 Reserved4; | ||
1160 | char FileName[1]; | ||
1161 | } TRANSACTION2_QPI_REQ; | ||
1162 | |||
1163 | typedef struct smb_com_transaction2_qpi_rsp { | ||
1164 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | ||
1165 | struct trans2_resp t2; | ||
1166 | __u16 ByteCount; | ||
1167 | __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ | ||
1168 | } TRANSACTION2_QPI_RSP; | ||
1169 | |||
1170 | typedef struct smb_com_transaction2_spi_req { | ||
1171 | struct smb_hdr hdr; /* wct = 15 */ | ||
1172 | __le16 TotalParameterCount; | ||
1173 | __le16 TotalDataCount; | ||
1174 | __le16 MaxParameterCount; | ||
1175 | __le16 MaxDataCount; | ||
1176 | __u8 MaxSetupCount; | ||
1177 | __u8 Reserved; | ||
1178 | __le16 Flags; | ||
1179 | __le32 Timeout; | ||
1180 | __u16 Reserved2; | ||
1181 | __le16 ParameterCount; | ||
1182 | __le16 ParameterOffset; | ||
1183 | __le16 DataCount; | ||
1184 | __le16 DataOffset; | ||
1185 | __u8 SetupCount; | ||
1186 | __u8 Reserved3; | ||
1187 | __le16 SubCommand; /* one setup word */ | ||
1188 | __le16 ByteCount; | ||
1189 | __u8 Pad; | ||
1190 | __u16 Pad1; | ||
1191 | __le16 InformationLevel; | ||
1192 | __u32 Reserved4; | ||
1193 | char FileName[1]; | ||
1194 | } TRANSACTION2_SPI_REQ; | ||
1195 | |||
1196 | typedef struct smb_com_transaction2_spi_rsp { | ||
1197 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | ||
1198 | struct trans2_resp t2; | ||
1199 | __u16 ByteCount; | ||
1200 | __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ | ||
1201 | } TRANSACTION2_SPI_RSP; | ||
1202 | |||
1203 | struct set_file_rename { | ||
1204 | __le32 overwrite; /* 1 = overwrite dest */ | ||
1205 | __u32 root_fid; /* zero */ | ||
1206 | __le32 target_name_len; | ||
1207 | char target_name[0]; /* Must be unicode */ | ||
1208 | }; | ||
1209 | |||
1210 | struct smb_com_transaction2_sfi_req { | ||
1211 | struct smb_hdr hdr; /* wct = 15 */ | ||
1212 | __le16 TotalParameterCount; | ||
1213 | __le16 TotalDataCount; | ||
1214 | __le16 MaxParameterCount; | ||
1215 | __le16 MaxDataCount; | ||
1216 | __u8 MaxSetupCount; | ||
1217 | __u8 Reserved; | ||
1218 | __le16 Flags; | ||
1219 | __le32 Timeout; | ||
1220 | __u16 Reserved2; | ||
1221 | __le16 ParameterCount; | ||
1222 | __le16 ParameterOffset; | ||
1223 | __le16 DataCount; | ||
1224 | __le16 DataOffset; | ||
1225 | __u8 SetupCount; | ||
1226 | __u8 Reserved3; | ||
1227 | __le16 SubCommand; /* one setup word */ | ||
1228 | __le16 ByteCount; | ||
1229 | __u8 Pad; | ||
1230 | __u16 Pad1; | ||
1231 | __u16 Fid; | ||
1232 | __le16 InformationLevel; | ||
1233 | __u16 Reserved4; | ||
1234 | }; | ||
1235 | |||
1236 | struct smb_com_transaction2_sfi_rsp { | ||
1237 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | ||
1238 | struct trans2_resp t2; | ||
1239 | __u16 ByteCount; | ||
1240 | __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ | ||
1241 | }; | ||
1242 | |||
1243 | |||
1244 | /* | ||
1245 | * Flags on T2 FINDFIRST and FINDNEXT | ||
1246 | */ | ||
1247 | #define CIFS_SEARCH_CLOSE_ALWAYS 0x0001 | ||
1248 | #define CIFS_SEARCH_CLOSE_AT_END 0x0002 | ||
1249 | #define CIFS_SEARCH_RETURN_RESUME 0x0004 | ||
1250 | #define CIFS_SEARCH_CONTINUE_FROM_LAST 0x0008 | ||
1251 | #define CIFS_SEARCH_BACKUP_SEARCH 0x0010 | ||
1252 | |||
1253 | /* | ||
1254 | * Size of the resume key on FINDFIRST and FINDNEXT calls | ||
1255 | */ | ||
1256 | #define CIFS_SMB_RESUME_KEY_SIZE 4 | ||
1257 | |||
1258 | typedef struct smb_com_transaction2_ffirst_req { | ||
1259 | struct smb_hdr hdr; /* wct = 15 */ | ||
1260 | __le16 TotalParameterCount; | ||
1261 | __le16 TotalDataCount; | ||
1262 | __le16 MaxParameterCount; | ||
1263 | __le16 MaxDataCount; | ||
1264 | __u8 MaxSetupCount; | ||
1265 | __u8 Reserved; | ||
1266 | __le16 Flags; | ||
1267 | __le32 Timeout; | ||
1268 | __u16 Reserved2; | ||
1269 | __le16 ParameterCount; | ||
1270 | __le16 ParameterOffset; | ||
1271 | __le16 DataCount; | ||
1272 | __le16 DataOffset; | ||
1273 | __u8 SetupCount; /* one */ | ||
1274 | __u8 Reserved3; | ||
1275 | __le16 SubCommand; /* TRANS2_FIND_FIRST */ | ||
1276 | __le16 ByteCount; | ||
1277 | __u8 Pad; | ||
1278 | __le16 SearchAttributes; | ||
1279 | __le16 SearchCount; | ||
1280 | __le16 SearchFlags; | ||
1281 | __le16 InformationLevel; | ||
1282 | __le32 SearchStorageType; | ||
1283 | char FileName[1]; | ||
1284 | } TRANSACTION2_FFIRST_REQ; | ||
1285 | |||
1286 | typedef struct smb_com_transaction2_ffirst_rsp { | ||
1287 | struct smb_hdr hdr; /* wct = 10 */ | ||
1288 | struct trans2_resp t2; | ||
1289 | __u16 ByteCount; | ||
1290 | } TRANSACTION2_FFIRST_RSP; | ||
1291 | |||
1292 | typedef struct smb_com_transaction2_ffirst_rsp_parms { | ||
1293 | __u16 SearchHandle; | ||
1294 | __le16 SearchCount; | ||
1295 | __le16 EndofSearch; | ||
1296 | __le16 EAErrorOffset; | ||
1297 | __le16 LastNameOffset; | ||
1298 | } T2_FFIRST_RSP_PARMS; | ||
1299 | |||
1300 | typedef struct smb_com_transaction2_fnext_req { | ||
1301 | struct smb_hdr hdr; /* wct = 15 */ | ||
1302 | __le16 TotalParameterCount; | ||
1303 | __le16 TotalDataCount; | ||
1304 | __le16 MaxParameterCount; | ||
1305 | __le16 MaxDataCount; | ||
1306 | __u8 MaxSetupCount; | ||
1307 | __u8 Reserved; | ||
1308 | __le16 Flags; | ||
1309 | __le32 Timeout; | ||
1310 | __u16 Reserved2; | ||
1311 | __le16 ParameterCount; | ||
1312 | __le16 ParameterOffset; | ||
1313 | __le16 DataCount; | ||
1314 | __le16 DataOffset; | ||
1315 | __u8 SetupCount; /* one */ | ||
1316 | __u8 Reserved3; | ||
1317 | __le16 SubCommand; /* TRANS2_FIND_NEXT */ | ||
1318 | __le16 ByteCount; | ||
1319 | __u8 Pad; | ||
1320 | __u16 SearchHandle; | ||
1321 | __le16 SearchCount; | ||
1322 | __le16 InformationLevel; | ||
1323 | __u32 ResumeKey; | ||
1324 | __le16 SearchFlags; | ||
1325 | char ResumeFileName[1]; | ||
1326 | } TRANSACTION2_FNEXT_REQ; | ||
1327 | |||
1328 | typedef struct smb_com_transaction2_fnext_rsp { | ||
1329 | struct smb_hdr hdr; /* wct = 10 */ | ||
1330 | struct trans2_resp t2; | ||
1331 | __u16 ByteCount; | ||
1332 | } TRANSACTION2_FNEXT_RSP; | ||
1333 | |||
1334 | typedef struct smb_com_transaction2_fnext_rsp_parms { | ||
1335 | __le16 SearchCount; | ||
1336 | __le16 EndofSearch; | ||
1337 | __le16 EAErrorOffset; | ||
1338 | __le16 LastNameOffset; | ||
1339 | } T2_FNEXT_RSP_PARMS; | ||
1340 | |||
1341 | /* QFSInfo Levels */ | ||
1342 | #define SMB_INFO_ALLOCATION 1 | ||
1343 | #define SMB_INFO_VOLUME 2 | ||
1344 | #define SMB_QUERY_FS_VOLUME_INFO 0x102 | ||
1345 | #define SMB_QUERY_FS_SIZE_INFO 0x103 | ||
1346 | #define SMB_QUERY_FS_DEVICE_INFO 0x104 | ||
1347 | #define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105 | ||
1348 | #define SMB_QUERY_CIFS_UNIX_INFO 0x200 | ||
1349 | #define SMB_QUERY_POSIX_FS_INFO 0x201 | ||
1350 | #define SMB_QUERY_LABEL_INFO 0x3ea | ||
1351 | #define SMB_QUERY_FS_QUOTA_INFO 0x3ee | ||
1352 | #define SMB_QUERY_FS_FULL_SIZE_INFO 0x3ef | ||
1353 | #define SMB_QUERY_OBJECTID_INFO 0x3f0 | ||
1354 | |||
1355 | typedef struct smb_com_transaction2_qfsi_req { | ||
1356 | struct smb_hdr hdr; /* wct = 14+ */ | ||
1357 | __le16 TotalParameterCount; | ||
1358 | __le16 TotalDataCount; | ||
1359 | __le16 MaxParameterCount; | ||
1360 | __le16 MaxDataCount; | ||
1361 | __u8 MaxSetupCount; | ||
1362 | __u8 Reserved; | ||
1363 | __le16 Flags; | ||
1364 | __le32 Timeout; | ||
1365 | __u16 Reserved2; | ||
1366 | __le16 ParameterCount; | ||
1367 | __le16 ParameterOffset; | ||
1368 | __le16 DataCount; | ||
1369 | __le16 DataOffset; | ||
1370 | __u8 SetupCount; | ||
1371 | __u8 Reserved3; | ||
1372 | __le16 SubCommand; /* one setup word */ | ||
1373 | __le16 ByteCount; | ||
1374 | __u8 Pad; | ||
1375 | __le16 InformationLevel; | ||
1376 | } TRANSACTION2_QFSI_REQ; | ||
1377 | |||
1378 | typedef struct smb_com_transaction_qfsi_rsp { | ||
1379 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | ||
1380 | struct trans2_resp t2; | ||
1381 | __u16 ByteCount; | ||
1382 | __u8 Pad; /* may be three bytes *//* followed by data area */ | ||
1383 | } TRANSACTION2_QFSI_RSP; | ||
1384 | |||
1385 | typedef struct smb_com_transaction2_get_dfs_refer_req { | ||
1386 | struct smb_hdr hdr; /* wct = 15 */ | ||
1387 | __le16 TotalParameterCount; | ||
1388 | __le16 TotalDataCount; | ||
1389 | __le16 MaxParameterCount; | ||
1390 | __le16 MaxDataCount; | ||
1391 | __u8 MaxSetupCount; | ||
1392 | __u8 Reserved; | ||
1393 | __le16 Flags; | ||
1394 | __le32 Timeout; | ||
1395 | __u16 Reserved2; | ||
1396 | __le16 ParameterCount; | ||
1397 | __le16 ParameterOffset; | ||
1398 | __le16 DataCount; | ||
1399 | __le16 DataOffset; | ||
1400 | __u8 SetupCount; | ||
1401 | __u8 Reserved3; | ||
1402 | __le16 SubCommand; /* one setup word */ | ||
1403 | __le16 ByteCount; | ||
1404 | __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */ | ||
1405 | __le16 MaxReferralLevel; | ||
1406 | char RequestFileName[1]; | ||
1407 | } TRANSACTION2_GET_DFS_REFER_REQ; | ||
1408 | |||
1409 | typedef struct dfs_referral_level_3 { | ||
1410 | __le16 VersionNumber; | ||
1411 | __le16 ReferralSize; | ||
1412 | __le16 ServerType; /* 0x0001 = CIFS server */ | ||
1413 | __le16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */ | ||
1414 | __le16 TimeToLive; | ||
1415 | __le16 Proximity; | ||
1416 | __le16 DfsPathOffset; | ||
1417 | __le16 DfsAlternatePathOffset; | ||
1418 | __le16 NetworkAddressOffset; | ||
1419 | } REFERRAL3; | ||
1420 | |||
1421 | typedef struct smb_com_transaction_get_dfs_refer_rsp { | ||
1422 | struct smb_hdr hdr; /* wct = 10 */ | ||
1423 | struct trans2_resp t2; | ||
1424 | __u16 ByteCount; | ||
1425 | __u8 Pad; | ||
1426 | __le16 PathConsumed; | ||
1427 | __le16 NumberOfReferrals; | ||
1428 | __le16 DFSFlags; | ||
1429 | __u16 Pad2; | ||
1430 | REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ | ||
1431 | /* followed by the strings pointed to by the referral structures */ | ||
1432 | } TRANSACTION2_GET_DFS_REFER_RSP; | ||
1433 | |||
1434 | /* DFS Flags */ | ||
1435 | #define DFSREF_REFERRAL_SERVER 0x0001 | ||
1436 | #define DFSREF_STORAGE_SERVER 0x0002 | ||
1437 | |||
1438 | /* IOCTL information */ | ||
1439 | /* List of ioctl function codes that look to be of interest to remote clients like this. */ | ||
1440 | /* Need to do some experimentation to make sure they all work remotely. */ | ||
1441 | /* Some of the following such as the encryption/compression ones would be */ | ||
1442 | /* invoked from tools via a specialized hook into the VFS rather than via the */ | ||
1443 | /* standard vfs entry points */ | ||
1444 | #define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000 | ||
1445 | #define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004 | ||
1446 | #define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008 | ||
1447 | #define FSCTL_LOCK_VOLUME 0x00090018 | ||
1448 | #define FSCTL_UNLOCK_VOLUME 0x0009001C | ||
1449 | #define FSCTL_GET_COMPRESSION 0x0009003C | ||
1450 | #define FSCTL_SET_COMPRESSION 0x0009C040 | ||
1451 | #define FSCTL_REQUEST_FILTER_OPLOCK 0x0009008C | ||
1452 | #define FSCTL_FILESYS_GET_STATISTICS 0x00090090 | ||
1453 | #define FSCTL_SET_REPARSE_POINT 0x000900A4 | ||
1454 | #define FSCTL_GET_REPARSE_POINT 0x000900A8 | ||
1455 | #define FSCTL_DELETE_REPARSE_POINT 0x000900AC | ||
1456 | #define FSCTL_SET_SPARSE 0x000900C4 | ||
1457 | #define FSCTL_SET_ZERO_DATA 0x000900C8 | ||
1458 | #define FSCTL_SET_ENCRYPTION 0x000900D7 | ||
1459 | #define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB | ||
1460 | #define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF | ||
1461 | #define FSCTL_READ_RAW_ENCRYPTED 0x000900E3 | ||
1462 | #define FSCTL_SIS_COPYFILE 0x00090100 | ||
1463 | #define FSCTL_SIS_LINK_FILES 0x0009C104 | ||
1464 | |||
1465 | #define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 | ||
1466 | #define IO_REPARSE_TAG_HSM 0xC0000004 | ||
1467 | #define IO_REPARSE_TAG_SIS 0x80000007 | ||
1468 | |||
1469 | /* | ||
1470 | ************************************************************************ | ||
1471 | * All structs for everything above the SMB PDUs themselves | ||
1472 | * (such as the T2 level specific data) go here | ||
1473 | ************************************************************************ | ||
1474 | */ | ||
1475 | |||
1476 | /* | ||
1477 | * Information on a server | ||
1478 | */ | ||
1479 | |||
1480 | struct serverInfo { | ||
1481 | char name[16]; | ||
1482 | unsigned char versionMajor; | ||
1483 | unsigned char versionMinor; | ||
1484 | unsigned long type; | ||
1485 | unsigned int commentOffset; | ||
1486 | }; | ||
1487 | |||
1488 | /* | ||
1489 | * The following structure is the format of the data returned on a NetShareEnum | ||
1490 | * with level "90" (x5A) | ||
1491 | */ | ||
1492 | |||
1493 | struct shareInfo { | ||
1494 | char shareName[13]; | ||
1495 | char pad; | ||
1496 | unsigned short type; | ||
1497 | unsigned int commentOffset; | ||
1498 | }; | ||
1499 | |||
1500 | struct aliasInfo { | ||
1501 | char aliasName[9]; | ||
1502 | char pad; | ||
1503 | unsigned int commentOffset; | ||
1504 | unsigned char type[2]; | ||
1505 | }; | ||
1506 | |||
1507 | struct aliasInfo92 { | ||
1508 | int aliasNameOffset; | ||
1509 | int serverNameOffset; | ||
1510 | int shareNameOffset; | ||
1511 | }; | ||
1512 | |||
1513 | typedef struct { | ||
1514 | __le64 TotalAllocationUnits; | ||
1515 | __le64 FreeAllocationUnits; | ||
1516 | __le32 SectorsPerAllocationUnit; | ||
1517 | __le32 BytesPerSector; | ||
1518 | } FILE_SYSTEM_INFO; /* size info, level 0x103 */ | ||
1519 | |||
1520 | typedef struct { | ||
1521 | __le16 MajorVersionNumber; | ||
1522 | __le16 MinorVersionNumber; | ||
1523 | __le64 Capability; | ||
1524 | } FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ | ||
1525 | /* Linux/Unix extensions capability flags */ | ||
1526 | #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ | ||
1527 | #define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 | ||
1528 | #define CIFS_UNIX_XATTR_CAP 0x00000004 /*support for new namespace*/ | ||
1529 | |||
1530 | typedef struct { | ||
1531 | /* For undefined recommended transfer size return -1 in that field */ | ||
1532 | __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ | ||
1533 | __le32 BlockSize; | ||
1534 | /* The next three fields are in terms of the block size. | ||
1535 | (above). If block size is unknown, 4096 would be a | ||
1536 | reasonable block size for a server to report. | ||
1537 | Note that returning the blocks/blocksavail removes need | ||
1538 | to make a second call (to QFSInfo level 0x103 to get this info. | ||
1539 | UserBlockAvail is typically less than or equal to BlocksAvail, | ||
1540 | if no distinction is made return the same value in each */ | ||
1541 | __le64 TotalBlocks; | ||
1542 | __le64 BlocksAvail; /* bfree */ | ||
1543 | __le64 UserBlocksAvail; /* bavail */ | ||
1544 | /* For undefined Node fields or FSID return -1 */ | ||
1545 | __le64 TotalFileNodes; | ||
1546 | __le64 FreeFileNodes; | ||
1547 | __le64 FileSysIdentifier; /* fsid */ | ||
1548 | /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */ | ||
1549 | /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */ | ||
1550 | } FILE_SYSTEM_POSIX_INFO; | ||
1551 | |||
1552 | /* DeviceType Flags */ | ||
1553 | #define FILE_DEVICE_CD_ROM 0x00000002 | ||
1554 | #define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 | ||
1555 | #define FILE_DEVICE_DFS 0x00000006 | ||
1556 | #define FILE_DEVICE_DISK 0x00000007 | ||
1557 | #define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 | ||
1558 | #define FILE_DEVICE_FILE_SYSTEM 0x00000009 | ||
1559 | #define FILE_DEVICE_NAMED_PIPE 0x00000011 | ||
1560 | #define FILE_DEVICE_NETWORK 0x00000012 | ||
1561 | #define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 | ||
1562 | #define FILE_DEVICE_NULL 0x00000015 | ||
1563 | #define FILE_DEVICE_PARALLEL_PORT 0x00000016 | ||
1564 | #define FILE_DEVICE_PRINTER 0x00000018 | ||
1565 | #define FILE_DEVICE_SERIAL_PORT 0x0000001b | ||
1566 | #define FILE_DEVICE_STREAMS 0x0000001e | ||
1567 | #define FILE_DEVICE_TAPE 0x0000001f | ||
1568 | #define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 | ||
1569 | #define FILE_DEVICE_VIRTUAL_DISK 0x00000024 | ||
1570 | #define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 | ||
1571 | |||
1572 | typedef struct { | ||
1573 | __le32 DeviceType; | ||
1574 | __le32 DeviceCharacteristics; | ||
1575 | } FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ | ||
1576 | |||
1577 | typedef struct { | ||
1578 | __le32 Attributes; | ||
1579 | __le32 MaxPathNameComponentLength; | ||
1580 | __le32 FileSystemNameLen; | ||
1581 | char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ | ||
1582 | } FILE_SYSTEM_ATTRIBUTE_INFO; | ||
1583 | |||
1584 | /******************************************************************************/ | ||
1585 | /* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */ | ||
1586 | /******************************************************************************/ | ||
1587 | typedef struct { /* data block encoding of response to level 263 QPathInfo */ | ||
1588 | __le64 CreationTime; | ||
1589 | __le64 LastAccessTime; | ||
1590 | __le64 LastWriteTime; | ||
1591 | __le64 ChangeTime; | ||
1592 | __le32 Attributes; | ||
1593 | __u32 Pad1; | ||
1594 | __le64 AllocationSize; | ||
1595 | __le64 EndOfFile; /* size ie offset to first free byte in file */ | ||
1596 | __le32 NumberOfLinks; /* hard links */ | ||
1597 | __u8 DeletePending; | ||
1598 | __u8 Directory; | ||
1599 | __u16 Pad2; | ||
1600 | __u64 IndexNumber; | ||
1601 | __le32 EASize; | ||
1602 | __le32 AccessFlags; | ||
1603 | __u64 IndexNumber1; | ||
1604 | __le64 CurrentByteOffset; | ||
1605 | __le32 Mode; | ||
1606 | __le32 AlignmentRequirement; | ||
1607 | __le32 FileNameLength; | ||
1608 | char FileName[1]; | ||
1609 | } FILE_ALL_INFO; /* level 0x107 QPathInfo */ | ||
1610 | |||
1611 | /* defines for enumerating possible values of the Unix type field below */ | ||
1612 | #define UNIX_FILE 0 | ||
1613 | #define UNIX_DIR 1 | ||
1614 | #define UNIX_SYMLINK 2 | ||
1615 | #define UNIX_CHARDEV 3 | ||
1616 | #define UNIX_BLOCKDEV 4 | ||
1617 | #define UNIX_FIFO 5 | ||
1618 | #define UNIX_SOCKET 6 | ||
1619 | typedef struct { | ||
1620 | __le64 EndOfFile; | ||
1621 | __le64 NumOfBytes; | ||
1622 | __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */ | ||
1623 | __le64 LastAccessTime; | ||
1624 | __le64 LastModificationTime; | ||
1625 | __le64 Uid; | ||
1626 | __le64 Gid; | ||
1627 | __le32 Type; | ||
1628 | __le64 DevMajor; | ||
1629 | __le64 DevMinor; | ||
1630 | __u64 UniqueId; | ||
1631 | __le64 Permissions; | ||
1632 | __le64 Nlinks; | ||
1633 | } FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ | ||
1634 | |||
1635 | typedef struct { | ||
1636 | char LinkDest[1]; | ||
1637 | } FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ | ||
1638 | |||
1639 | /* The following three structures are needed only for | ||
1640 | setting time to NT4 and some older servers via | ||
1641 | the primitive DOS time format */ | ||
1642 | typedef struct { | ||
1643 | __u16 Day:5; | ||
1644 | __u16 Month:4; | ||
1645 | __u16 Year:7; | ||
1646 | } SMB_DATE; | ||
1647 | |||
1648 | typedef struct { | ||
1649 | __u16 TwoSeconds:5; | ||
1650 | __u16 Minutes:6; | ||
1651 | __u16 Hours:5; | ||
1652 | } SMB_TIME; | ||
1653 | |||
1654 | typedef struct { | ||
1655 | __le16 CreationDate; /* SMB Date see above */ | ||
1656 | __le16 CreationTime; /* SMB Time */ | ||
1657 | __le16 LastAccessDate; | ||
1658 | __le16 LastAccessTime; | ||
1659 | __le16 LastWriteDate; | ||
1660 | __le16 LastWriteTime; | ||
1661 | __le32 DataSize; /* File Size (EOF) */ | ||
1662 | __le32 AllocationSize; | ||
1663 | __le16 Attributes; /* verify not u32 */ | ||
1664 | __le32 EASize; | ||
1665 | } FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ | ||
1666 | |||
1667 | typedef struct { | ||
1668 | __le64 CreationTime; | ||
1669 | __le64 LastAccessTime; | ||
1670 | __le64 LastWriteTime; | ||
1671 | __le64 ChangeTime; | ||
1672 | __le32 Attributes; | ||
1673 | __u32 Pad; | ||
1674 | } FILE_BASIC_INFO; /* size info, level 0x101 */ | ||
1675 | |||
1676 | struct file_allocation_info { | ||
1677 | __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ | ||
1678 | }; /* size used on disk, level 0x103 for set, 0x105 for query */ | ||
1679 | |||
1680 | struct file_end_of_file_info { | ||
1681 | __le64 FileSize; /* offset to end of file */ | ||
1682 | }; /* size info, level 0x104 for set, 0x106 for query */ | ||
1683 | |||
1684 | struct file_alt_name_info { | ||
1685 | __u8 alt_name[1]; | ||
1686 | }; /* level 0x0108 */ | ||
1687 | |||
1688 | struct file_stream_info { | ||
1689 | __le32 number_of_streams; /* BB check sizes and verify location */ | ||
1690 | /* followed by info on streams themselves | ||
1691 | u64 size; | ||
1692 | u64 allocation_size | ||
1693 | stream info */ | ||
1694 | }; /* level 0x109 */ | ||
1695 | |||
1696 | struct file_compression_info { | ||
1697 | __le64 compressed_size; | ||
1698 | __le16 format; | ||
1699 | __u8 unit_shift; | ||
1700 | __u8 ch_shift; | ||
1701 | __u8 cl_shift; | ||
1702 | __u8 pad[3]; | ||
1703 | }; /* level 0x10b */ | ||
1704 | |||
1705 | /* POSIX ACL set/query path info structures */ | ||
1706 | #define CIFS_ACL_VERSION 1 | ||
1707 | struct cifs_posix_ace { /* access control entry (ACE) */ | ||
1708 | __u8 cifs_e_tag; | ||
1709 | __u8 cifs_e_perm; | ||
1710 | __le64 cifs_uid; /* or gid */ | ||
1711 | }; | ||
1712 | |||
1713 | struct cifs_posix_acl { /* access conrol list (ACL) */ | ||
1714 | __le16 version; | ||
1715 | __le16 access_entry_count; /* access ACL - count of entries */ | ||
1716 | __le16 default_entry_count; /* default ACL - count of entries */ | ||
1717 | struct cifs_posix_ace ace_array[0]; | ||
1718 | /* followed by | ||
1719 | struct cifs_posix_ace default_ace_arraay[] */ | ||
1720 | }; /* level 0x204 */ | ||
1721 | |||
1722 | /* types of access control entries already defined in posix_acl.h */ | ||
1723 | /* #define CIFS_POSIX_ACL_USER_OBJ 0x01 | ||
1724 | #define CIFS_POSIX_ACL_USER 0x02 | ||
1725 | #define CIFS_POSIX_ACL_GROUP_OBJ 0x04 | ||
1726 | #define CIFS_POSIX_ACL_GROUP 0x08 | ||
1727 | #define CIFS_POSIX_ACL_MASK 0x10 | ||
1728 | #define CIFS_POSIX_ACL_OTHER 0x20 */ | ||
1729 | |||
1730 | /* types of perms */ | ||
1731 | /* #define CIFS_POSIX_ACL_EXECUTE 0x01 | ||
1732 | #define CIFS_POSIX_ACL_WRITE 0x02 | ||
1733 | #define CIFS_POSIX_ACL_READ 0x04 */ | ||
1734 | |||
1735 | /* end of POSIX ACL definitions */ | ||
1736 | |||
1737 | struct file_internal_info { | ||
1738 | __u64 UniqueId; /* inode number */ | ||
1739 | }; /* level 0x3ee */ | ||
1740 | struct file_mode_info { | ||
1741 | __le32 Mode; | ||
1742 | }; /* level 0x3f8 */ | ||
1743 | |||
1744 | struct file_attrib_tag { | ||
1745 | __le32 Attribute; | ||
1746 | __le32 ReparseTag; | ||
1747 | }; /* level 0x40b */ | ||
1748 | |||
1749 | |||
1750 | /********************************************************/ | ||
1751 | /* FindFirst/FindNext transact2 data buffer formats */ | ||
1752 | /********************************************************/ | ||
1753 | |||
1754 | typedef struct { | ||
1755 | __le32 NextEntryOffset; | ||
1756 | __u32 ResumeKey; /* as with FileIndex - no need to convert */ | ||
1757 | __le64 EndOfFile; | ||
1758 | __le64 NumOfBytes; | ||
1759 | __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */ | ||
1760 | __le64 LastAccessTime; | ||
1761 | __le64 LastModificationTime; | ||
1762 | __le64 Uid; | ||
1763 | __le64 Gid; | ||
1764 | __le32 Type; | ||
1765 | __le64 DevMajor; | ||
1766 | __le64 DevMinor; | ||
1767 | __u64 UniqueId; | ||
1768 | __le64 Permissions; | ||
1769 | __le64 Nlinks; | ||
1770 | char FileName[1]; | ||
1771 | } FILE_UNIX_INFO; /* level 0x202 */ | ||
1772 | |||
1773 | typedef struct { | ||
1774 | __le32 NextEntryOffset; | ||
1775 | __u32 FileIndex; | ||
1776 | __le64 CreationTime; | ||
1777 | __le64 LastAccessTime; | ||
1778 | __le64 LastWriteTime; | ||
1779 | __le64 ChangeTime; | ||
1780 | __le64 EndOfFile; | ||
1781 | __le64 AllocationSize; | ||
1782 | __le32 ExtFileAttributes; | ||
1783 | __le32 FileNameLength; | ||
1784 | char FileName[1]; | ||
1785 | } FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */ | ||
1786 | |||
1787 | typedef struct { | ||
1788 | __le32 NextEntryOffset; | ||
1789 | __u32 FileIndex; | ||
1790 | __le64 CreationTime; | ||
1791 | __le64 LastAccessTime; | ||
1792 | __le64 LastWriteTime; | ||
1793 | __le64 ChangeTime; | ||
1794 | __le64 EndOfFile; | ||
1795 | __le64 AllocationSize; | ||
1796 | __le32 ExtFileAttributes; | ||
1797 | __le32 FileNameLength; | ||
1798 | __le32 EaSize; /* length of the xattrs */ | ||
1799 | char FileName[1]; | ||
1800 | } FILE_FULL_DIRECTORY_INFO; /* level 0x102 FF response data area */ | ||
1801 | |||
1802 | typedef struct { | ||
1803 | __le32 NextEntryOffset; | ||
1804 | __u32 FileIndex; | ||
1805 | __le64 CreationTime; | ||
1806 | __le64 LastAccessTime; | ||
1807 | __le64 LastWriteTime; | ||
1808 | __le64 ChangeTime; | ||
1809 | __le64 EndOfFile; | ||
1810 | __le64 AllocationSize; | ||
1811 | __le32 ExtFileAttributes; | ||
1812 | __le32 FileNameLength; | ||
1813 | __le32 EaSize; /* EA size */ | ||
1814 | __le32 Reserved; | ||
1815 | __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ | ||
1816 | char FileName[1]; | ||
1817 | } SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF response data area */ | ||
1818 | |||
1819 | typedef struct { | ||
1820 | __le32 NextEntryOffset; | ||
1821 | __u32 FileIndex; | ||
1822 | __le64 CreationTime; | ||
1823 | __le64 LastAccessTime; | ||
1824 | __le64 LastWriteTime; | ||
1825 | __le64 ChangeTime; | ||
1826 | __le64 EndOfFile; | ||
1827 | __le64 AllocationSize; | ||
1828 | __le32 ExtFileAttributes; | ||
1829 | __le32 FileNameLength; | ||
1830 | __le32 EaSize; /* length of the xattrs */ | ||
1831 | __u8 ShortNameLength; | ||
1832 | __u8 Reserved; | ||
1833 | __u8 ShortName[12]; | ||
1834 | char FileName[1]; | ||
1835 | } FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ | ||
1836 | |||
1837 | |||
1838 | struct gea { | ||
1839 | unsigned char name_len; | ||
1840 | char name[1]; | ||
1841 | }; | ||
1842 | |||
1843 | struct gealist { | ||
1844 | unsigned long list_len; | ||
1845 | struct gea list[1]; | ||
1846 | }; | ||
1847 | |||
1848 | struct fea { | ||
1849 | unsigned char EA_flags; | ||
1850 | __u8 name_len; | ||
1851 | __le16 value_len; | ||
1852 | char name[1]; | ||
1853 | /* optionally followed by value */ | ||
1854 | }; | ||
1855 | /* flags for _FEA.fEA */ | ||
1856 | #define FEA_NEEDEA 0x80 /* need EA bit */ | ||
1857 | |||
1858 | struct fealist { | ||
1859 | __le32 list_len; | ||
1860 | struct fea list[1]; | ||
1861 | }; | ||
1862 | |||
1863 | /* used to hold an arbitrary blob of data */ | ||
1864 | struct data_blob { | ||
1865 | __u8 *data; | ||
1866 | size_t length; | ||
1867 | void (*free) (struct data_blob * data_blob); | ||
1868 | }; | ||
1869 | |||
1870 | |||
1871 | #ifdef CONFIG_CIFS_POSIX | ||
1872 | /* | ||
1873 | For better POSIX semantics from Linux client, (even better | ||
1874 | than the existing CIFS Unix Extensions) we need updated PDUs for: | ||
1875 | |||
1876 | 1) PosixCreateX - to set and return the mode, inode#, device info and | ||
1877 | perhaps add a CreateDevice - to create Pipes and other special .inodes | ||
1878 | Also note POSIX open flags | ||
1879 | 2) Close - to return the last write time to do cache across close more safely | ||
1880 | 3) PosixQFSInfo - to return statfs info | ||
1881 | 4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes) | ||
1882 | 5) Mkdir - set mode | ||
1883 | |||
1884 | And under consideration: | ||
1885 | 6) FindClose2 (return nanosecond timestamp ??) | ||
1886 | 7) Use nanosecond timestamps throughout all time fields if | ||
1887 | corresponding attribute flag is set | ||
1888 | 8) sendfile - handle based copy | ||
1889 | 9) Direct i/o | ||
1890 | 10) "POSIX ACL" support | ||
1891 | 11) Misc fcntls? | ||
1892 | |||
1893 | what about fixing 64 bit alignment | ||
1894 | |||
1895 | There are also various legacy SMB/CIFS requests used as is | ||
1896 | |||
1897 | From existing Lanman and NTLM dialects: | ||
1898 | -------------------------------------- | ||
1899 | NEGOTIATE | ||
1900 | SESSION_SETUP_ANDX (BB which?) | ||
1901 | TREE_CONNECT_ANDX (BB which wct?) | ||
1902 | TREE_DISCONNECT (BB add volume timestamp on response) | ||
1903 | LOGOFF_ANDX | ||
1904 | DELETE (note delete open file behavior) | ||
1905 | DELETE_DIRECTORY | ||
1906 | READ_AND_X | ||
1907 | WRITE_AND_X | ||
1908 | LOCKING_AND_X (note posix lock semantics) | ||
1909 | RENAME (note rename across dirs and open file rename posix behaviors) | ||
1910 | NT_RENAME (for hardlinks) Is this good enough for all features? | ||
1911 | FIND_CLOSE2 | ||
1912 | TRANSACTION2 (18 cases) | ||
1913 | SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2 | ||
1914 | (BB verify that never need to set allocation size) | ||
1915 | SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?) | ||
1916 | |||
1917 | COPY (note support for copy across directories) - FUTURE, OPTIONAL | ||
1918 | setting/getting OS/2 EAs - FUTURE (BB can this handle | ||
1919 | setting Linux xattrs perfectly) - OPTIONAL | ||
1920 | dnotify - FUTURE, OPTIONAL | ||
1921 | quota - FUTURE, OPTIONAL | ||
1922 | |||
1923 | Note that various requests implemented for NT interop such as | ||
1924 | NT_TRANSACT (IOCTL) QueryReparseInfo | ||
1925 | are unneeded to servers compliant with the CIFS POSIX extensions | ||
1926 | |||
1927 | From CIFS Unix Extensions: | ||
1928 | ------------------------- | ||
1929 | T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks | ||
1930 | T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2) | ||
1931 | T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK) | ||
1932 | T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields | ||
1933 | Actually need QUERY_FILE_UNIX_INFO since has inode num | ||
1934 | BB what about a) blksize/blkbits/blocks | ||
1935 | b) i_version | ||
1936 | c) i_rdev | ||
1937 | d) notify mask? | ||
1938 | e) generation | ||
1939 | f) size_seqcount | ||
1940 | T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX | ||
1941 | TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended | ||
1942 | T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL | ||
1943 | |||
1944 | |||
1945 | */ | ||
1946 | |||
1947 | /* xsymlink is a symlink format that can be used | ||
1948 | to save symlink info in a regular file when | ||
1949 | mounted to operating systems that do not | ||
1950 | support the cifs Unix extensions or EAs (for xattr | ||
1951 | based symlinks). For such a file to be recognized | ||
1952 | as containing symlink data: | ||
1953 | |||
1954 | 1) file size must be 1067, | ||
1955 | 2) signature must begin file data, | ||
1956 | 3) length field must be set to ASCII representation | ||
1957 | of a number which is less than or equal to 1024, | ||
1958 | 4) md5 must match that of the path data */ | ||
1959 | |||
1960 | struct xsymlink { | ||
1961 | /* 1067 bytes */ | ||
1962 | char signature[4]; /* XSym */ /* not null terminated */ | ||
1963 | char cr0; /* \n */ | ||
1964 | /* ASCII representation of length (4 bytes decimal) terminated by \n not null */ | ||
1965 | char length[4]; | ||
1966 | char cr1; /* \n */ | ||
1967 | /* md5 of valid subset of path ie path[0] through path[length-1] */ | ||
1968 | __u8 md5[32]; | ||
1969 | char cr2; /* \n */ | ||
1970 | /* if room left, then end with \n then 0x20s by convention but not required */ | ||
1971 | char path[1024]; | ||
1972 | }; | ||
1973 | |||
1974 | typedef struct { | ||
1975 | /* BB do we need another field for flags? BB */ | ||
1976 | __u32 xattr_name_len; | ||
1977 | __u32 xattr_value_len; | ||
1978 | char xattr_name[0]; | ||
1979 | /* followed by xattr_value[xattr_value_len], no pad */ | ||
1980 | } FILE_XATTR_INFO; /* extended attribute, info level 205 */ | ||
1981 | |||
1982 | |||
1983 | #endif | ||
1984 | |||
1985 | #pragma pack() /* resume default structure packing */ | ||
1986 | |||
1987 | #endif /* _CIFSPDU_H */ | ||
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h new file mode 100644 index 000000000000..787eef4d86d3 --- /dev/null +++ b/fs/cifs/cifsproto.h | |||
@@ -0,0 +1,269 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifsproto.h | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2002,2005 | ||
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 | #ifndef _CIFSPROTO_H | ||
22 | #define _CIFSPROTO_H | ||
23 | #include <linux/nls.h> | ||
24 | |||
25 | struct statfs; | ||
26 | |||
27 | /* | ||
28 | ***************************************************************** | ||
29 | * All Prototypes | ||
30 | ***************************************************************** | ||
31 | */ | ||
32 | |||
33 | extern struct smb_hdr *cifs_buf_get(void); | ||
34 | extern void cifs_buf_release(void *); | ||
35 | extern struct smb_hdr *cifs_small_buf_get(void); | ||
36 | extern void cifs_small_buf_release(void *); | ||
37 | extern int smb_send(struct socket *, struct smb_hdr *, | ||
38 | unsigned int /* length */ , struct sockaddr *); | ||
39 | extern unsigned int _GetXid(void); | ||
40 | extern void _FreeXid(unsigned int); | ||
41 | #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid)); | ||
42 | #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));} | ||
43 | extern char *build_path_from_dentry(struct dentry *); | ||
44 | extern char *build_wildcard_path_from_dentry(struct dentry *direntry); | ||
45 | extern void renew_parental_timestamps(struct dentry *direntry); | ||
46 | extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | ||
47 | struct smb_hdr * /* input */ , | ||
48 | struct smb_hdr * /* out */ , | ||
49 | int * /* bytes returned */ , const int long_op); | ||
50 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); | ||
51 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); | ||
52 | extern int is_valid_oplock_break(struct smb_hdr *smb); | ||
53 | extern int is_size_safe_to_change(struct cifsInodeInfo *); | ||
54 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); | ||
55 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | ||
56 | enum securityEnum *secType); | ||
57 | extern int cifs_inet_pton(int, char * source, void *dst); | ||
58 | extern int map_smb_to_linux_error(struct smb_hdr *smb); | ||
59 | extern void header_assemble(struct smb_hdr *, char /* command */ , | ||
60 | const struct cifsTconInfo *, int | ||
61 | /* length of fixed section (word count) in two byte units */ | ||
62 | ); | ||
63 | extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *); | ||
64 | extern void DeleteOplockQEntry(struct oplock_q_entry *); | ||
65 | extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); | ||
66 | extern u64 cifs_UnixTimeToNT(struct timespec); | ||
67 | extern int cifs_get_inode_info(struct inode **pinode, | ||
68 | const unsigned char *search_path, | ||
69 | FILE_ALL_INFO * pfile_info, | ||
70 | struct super_block *sb, int xid); | ||
71 | extern int cifs_get_inode_info_unix(struct inode **pinode, | ||
72 | const unsigned char *search_path, | ||
73 | struct super_block *sb,int xid); | ||
74 | |||
75 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, | ||
76 | const char *); | ||
77 | extern int cifs_umount(struct super_block *, struct cifs_sb_info *); | ||
78 | void cifs_proc_init(void); | ||
79 | void cifs_proc_clean(void); | ||
80 | |||
81 | extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | ||
82 | struct nls_table * nls_info); | ||
83 | extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); | ||
84 | |||
85 | extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | ||
86 | const char *tree, struct cifsTconInfo *tcon, | ||
87 | const struct nls_table *); | ||
88 | |||
89 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | ||
90 | const char *searchName, const struct nls_table *nls_codepage, | ||
91 | __u16 *searchHandle, struct cifs_search_info * psrch_inf); | ||
92 | |||
93 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | ||
94 | __u16 searchHandle, struct cifs_search_info * psrch_inf); | ||
95 | |||
96 | extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, | ||
97 | const __u16 search_handle); | ||
98 | |||
99 | extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | ||
100 | const unsigned char *searchName, | ||
101 | FILE_ALL_INFO * findData, | ||
102 | const struct nls_table *nls_codepage); | ||
103 | |||
104 | extern int CIFSSMBUnixQPathInfo(const int xid, | ||
105 | struct cifsTconInfo *tcon, | ||
106 | const unsigned char *searchName, | ||
107 | FILE_UNIX_BASIC_INFO * pFindData, | ||
108 | const struct nls_table *nls_codepage); | ||
109 | |||
110 | extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, | ||
111 | const unsigned char *searchName, | ||
112 | unsigned char **targetUNCs, | ||
113 | unsigned int *number_of_UNC_in_array, | ||
114 | const struct nls_table *nls_codepage); | ||
115 | |||
116 | extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | ||
117 | const char *old_path, | ||
118 | const struct nls_table *nls_codepage); | ||
119 | extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | ||
120 | const char *old_path, const struct nls_table *nls_codepage, | ||
121 | unsigned int *pnum_referrals, unsigned char ** preferrals); | ||
122 | extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, | ||
123 | struct kstatfs *FSData, | ||
124 | const struct nls_table *nls_codepage); | ||
125 | extern int CIFSSMBQFSAttributeInfo(const int xid, | ||
126 | struct cifsTconInfo *tcon, | ||
127 | const struct nls_table *nls_codepage); | ||
128 | extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon, | ||
129 | const struct nls_table *nls_codepage); | ||
130 | extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon, | ||
131 | const struct nls_table *nls_codepage); | ||
132 | extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, | ||
133 | struct kstatfs *FSData, const struct nls_table *nls_codepage); | ||
134 | |||
135 | extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, | ||
136 | const char *fileName, const FILE_BASIC_INFO * data, | ||
137 | const struct nls_table *nls_codepage); | ||
138 | extern int CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, | ||
139 | const FILE_BASIC_INFO * data, __u16 fid); | ||
140 | #if 0 | ||
141 | extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, | ||
142 | char *fileName, __u16 dos_attributes, | ||
143 | const struct nls_table *nls_codepage); | ||
144 | #endif /* possibly unneeded function */ | ||
145 | extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, | ||
146 | const char *fileName, __u64 size,int setAllocationSizeFlag, | ||
147 | const struct nls_table *nls_codepage); | ||
148 | extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, | ||
149 | __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag); | ||
150 | extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon, | ||
151 | char *full_path, __u64 mode, __u64 uid, | ||
152 | __u64 gid, dev_t dev, const struct nls_table *nls_codepage); | ||
153 | |||
154 | extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, | ||
155 | const char *newName, | ||
156 | const struct nls_table *nls_codepage); | ||
157 | extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, | ||
158 | const char *name, const struct nls_table *nls_codepage); | ||
159 | |||
160 | extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, | ||
161 | const char *name, | ||
162 | const struct nls_table *nls_codepage); | ||
163 | extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, | ||
164 | const char *fromName, const char *toName, | ||
165 | const struct nls_table *nls_codepage); | ||
166 | extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, | ||
167 | int netfid, char * target_name, const struct nls_table *nls_codepage); | ||
168 | extern int CIFSCreateHardLink(const int xid, | ||
169 | struct cifsTconInfo *tcon, | ||
170 | const char *fromName, const char *toName, | ||
171 | const struct nls_table *nls_codepage); | ||
172 | extern int CIFSUnixCreateHardLink(const int xid, | ||
173 | struct cifsTconInfo *tcon, | ||
174 | const char *fromName, const char *toName, | ||
175 | const struct nls_table *nls_codepage); | ||
176 | extern int CIFSUnixCreateSymLink(const int xid, | ||
177 | struct cifsTconInfo *tcon, | ||
178 | const char *fromName, const char *toName, | ||
179 | const struct nls_table *nls_codepage); | ||
180 | extern int CIFSSMBUnixQuerySymLink(const int xid, | ||
181 | struct cifsTconInfo *tcon, | ||
182 | const unsigned char *searchName, | ||
183 | char *syminfo, const int buflen, | ||
184 | const struct nls_table *nls_codepage); | ||
185 | extern int CIFSSMBQueryReparseLinkInfo(const int xid, | ||
186 | struct cifsTconInfo *tcon, | ||
187 | const unsigned char *searchName, | ||
188 | char *symlinkinfo, const int buflen, __u16 fid, | ||
189 | const struct nls_table *nls_codepage); | ||
190 | |||
191 | extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | ||
192 | const char *fileName, const int disposition, | ||
193 | const int access_flags, const int omode, | ||
194 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, | ||
195 | const struct nls_table *nls_codepage); | ||
196 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, | ||
197 | const int smb_file_id); | ||
198 | |||
199 | extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | ||
200 | const int netfid, unsigned int count, | ||
201 | const __u64 lseek, unsigned int *nbytes, char **buf); | ||
202 | extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | ||
203 | const int netfid, const unsigned int count, | ||
204 | const __u64 lseek, unsigned int *nbytes, | ||
205 | const char *buf, const char __user *ubuf, | ||
206 | const int long_op); | ||
207 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
208 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | ||
209 | const int netfid, const unsigned int count, | ||
210 | const __u64 offset, unsigned int *nbytes, | ||
211 | const char __user *buf,const int long_op); | ||
212 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | ||
213 | const unsigned char *searchName, __u64 * inode_number, | ||
214 | const struct nls_table *nls_codepage); | ||
215 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
216 | |||
217 | extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | ||
218 | const __u16 netfid, const __u64 len, | ||
219 | const __u64 offset, const __u32 numUnlock, | ||
220 | const __u32 numLock, const __u8 lockType, | ||
221 | const int waitFlag); | ||
222 | |||
223 | extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); | ||
224 | extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); | ||
225 | |||
226 | extern struct cifsSesInfo *sesInfoAlloc(void); | ||
227 | extern void sesInfoFree(struct cifsSesInfo *); | ||
228 | extern struct cifsTconInfo *tconInfoAlloc(void); | ||
229 | extern void tconInfoFree(struct cifsTconInfo *); | ||
230 | |||
231 | extern int cifs_reconnect(struct TCP_Server_Info *server); | ||
232 | |||
233 | extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *); | ||
234 | extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, | ||
235 | __u32 expected_sequence_number); | ||
236 | extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); | ||
237 | extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); | ||
238 | extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); | ||
239 | extern int CIFSSMBCopy(int xid, | ||
240 | struct cifsTconInfo *source_tcon, | ||
241 | const char *fromName, | ||
242 | const __u16 target_tid, | ||
243 | const char *toName, const int flags, | ||
244 | const struct nls_table *nls_codepage); | ||
245 | extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | ||
246 | const int notify_subdirs,const __u16 netfid,__u32 filter, | ||
247 | const struct nls_table *nls_codepage); | ||
248 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | ||
249 | const unsigned char *searchName, char * EAData, | ||
250 | size_t bufsize, const struct nls_table *nls_codepage); | ||
251 | extern ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon, | ||
252 | const unsigned char * searchName,const unsigned char * ea_name, | ||
253 | unsigned char * ea_value, size_t buf_size, | ||
254 | const struct nls_table *nls_codepage); | ||
255 | extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, | ||
256 | const char *fileName, const char * ea_name, | ||
257 | const void * ea_value, const __u16 ea_value_len, | ||
258 | const struct nls_table *nls_codepage); | ||
259 | extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, | ||
260 | const unsigned char *searchName, | ||
261 | char *acl_inf, const int buflen,const int acl_type, | ||
262 | const struct nls_table *nls_codepage); | ||
263 | extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, | ||
264 | const unsigned char *fileName, | ||
265 | const char *local_acl, const int buflen, const int acl_type, | ||
266 | const struct nls_table *nls_codepage); | ||
267 | int cifs_ioctl (struct inode * inode, struct file * filep, | ||
268 | unsigned int command, unsigned long arg); | ||
269 | #endif /* _CIFSPROTO_H */ | ||
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c new file mode 100644 index 000000000000..df6a619a6821 --- /dev/null +++ b/fs/cifs/cifssmb.c | |||
@@ -0,0 +1,4186 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifssmb.c | ||
3 | * | ||
4 | * Copyright (C) International Business Machines Corp., 2002,2005 | ||
5 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
6 | * | ||
7 | * Contains the routines for constructing the SMB PDUs themselves | ||
8 | * | ||
9 | * This library is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU Lesser General Public License as published | ||
11 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This library is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
17 | * the GNU Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public License | ||
20 | * along with this library; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */ | ||
25 | /* These are mostly routines that operate on a pathname, or on a tree id */ | ||
26 | /* (mounted volume), but there are eight handle based routines which must be */ | ||
27 | /* treated slightly different for reconnection purposes since we never want */ | ||
28 | /* to reuse a stale file handle and the caller knows the file handle */ | ||
29 | |||
30 | #include <linux/fs.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/vfs.h> | ||
33 | #include <linux/posix_acl_xattr.h> | ||
34 | #include <asm/uaccess.h> | ||
35 | #include "cifspdu.h" | ||
36 | #include "cifsglob.h" | ||
37 | #include "cifsproto.h" | ||
38 | #include "cifs_unicode.h" | ||
39 | #include "cifs_debug.h" | ||
40 | |||
41 | #ifdef CONFIG_CIFS_POSIX | ||
42 | static struct { | ||
43 | int index; | ||
44 | char *name; | ||
45 | } protocols[] = { | ||
46 | {CIFS_PROT, "\2NT LM 0.12"}, | ||
47 | {CIFS_PROT, "\2POSIX 2"}, | ||
48 | {BAD_PROT, "\2"} | ||
49 | }; | ||
50 | #else | ||
51 | static struct { | ||
52 | int index; | ||
53 | char *name; | ||
54 | } protocols[] = { | ||
55 | {CIFS_PROT, "\2NT LM 0.12"}, | ||
56 | {BAD_PROT, "\2"} | ||
57 | }; | ||
58 | #endif | ||
59 | |||
60 | |||
61 | /* Mark as invalid, all open files on tree connections since they | ||
62 | were closed when session to server was lost */ | ||
63 | static void mark_open_files_invalid(struct cifsTconInfo * pTcon) | ||
64 | { | ||
65 | struct cifsFileInfo *open_file = NULL; | ||
66 | struct list_head * tmp; | ||
67 | struct list_head * tmp1; | ||
68 | |||
69 | /* list all files open on tree connection and mark them invalid */ | ||
70 | write_lock(&GlobalSMBSeslock); | ||
71 | list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { | ||
72 | open_file = list_entry(tmp,struct cifsFileInfo, tlist); | ||
73 | if(open_file) { | ||
74 | open_file->invalidHandle = TRUE; | ||
75 | } | ||
76 | } | ||
77 | write_unlock(&GlobalSMBSeslock); | ||
78 | /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */ | ||
79 | } | ||
80 | |||
81 | /* If the return code is zero, this function must fill in request_buf pointer */ | ||
82 | static int | ||
83 | small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | ||
84 | void **request_buf /* returned */) | ||
85 | { | ||
86 | int rc = 0; | ||
87 | |||
88 | /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so | ||
89 | check for tcp and smb session status done differently | ||
90 | for those three - in the calling routine */ | ||
91 | if(tcon) { | ||
92 | if((tcon->ses) && (tcon->ses->server)){ | ||
93 | struct nls_table *nls_codepage; | ||
94 | /* Give Demultiplex thread up to 10 seconds to | ||
95 | reconnect, should be greater than cifs socket | ||
96 | timeout which is 7 seconds */ | ||
97 | while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { | ||
98 | wait_event_interruptible_timeout(tcon->ses->server->response_q, | ||
99 | (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); | ||
100 | if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { | ||
101 | /* on "soft" mounts we wait once */ | ||
102 | if((tcon->retry == FALSE) || | ||
103 | (tcon->ses->status == CifsExiting)) { | ||
104 | cFYI(1,("gave up waiting on reconnect in smb_init")); | ||
105 | return -EHOSTDOWN; | ||
106 | } /* else "hard" mount - keep retrying until | ||
107 | process is killed or server comes back up */ | ||
108 | } else /* TCP session is reestablished now */ | ||
109 | break; | ||
110 | |||
111 | } | ||
112 | |||
113 | nls_codepage = load_nls_default(); | ||
114 | /* need to prevent multiple threads trying to | ||
115 | simultaneously reconnect the same SMB session */ | ||
116 | down(&tcon->ses->sesSem); | ||
117 | if(tcon->ses->status == CifsNeedReconnect) | ||
118 | rc = cifs_setup_session(0, tcon->ses, nls_codepage); | ||
119 | if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { | ||
120 | mark_open_files_invalid(tcon); | ||
121 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, | ||
122 | nls_codepage); | ||
123 | up(&tcon->ses->sesSem); | ||
124 | if(rc == 0) | ||
125 | atomic_inc(&tconInfoReconnectCount); | ||
126 | |||
127 | cFYI(1, ("reconnect tcon rc = %d", rc)); | ||
128 | /* Removed call to reopen open files here - | ||
129 | it is safer (and faster) to reopen files | ||
130 | one at a time as needed in read and write */ | ||
131 | |||
132 | /* Check if handle based operation so we | ||
133 | know whether we can continue or not without | ||
134 | returning to caller to reset file handle */ | ||
135 | switch(smb_command) { | ||
136 | case SMB_COM_READ_ANDX: | ||
137 | case SMB_COM_WRITE_ANDX: | ||
138 | case SMB_COM_CLOSE: | ||
139 | case SMB_COM_FIND_CLOSE2: | ||
140 | case SMB_COM_LOCKING_ANDX: { | ||
141 | unload_nls(nls_codepage); | ||
142 | return -EAGAIN; | ||
143 | } | ||
144 | } | ||
145 | } else { | ||
146 | up(&tcon->ses->sesSem); | ||
147 | } | ||
148 | unload_nls(nls_codepage); | ||
149 | |||
150 | } else { | ||
151 | return -EIO; | ||
152 | } | ||
153 | } | ||
154 | if(rc) | ||
155 | return rc; | ||
156 | |||
157 | *request_buf = cifs_small_buf_get(); | ||
158 | if (*request_buf == NULL) { | ||
159 | /* BB should we add a retry in here if not a writepage? */ | ||
160 | return -ENOMEM; | ||
161 | } | ||
162 | |||
163 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); | ||
164 | |||
165 | #ifdef CONFIG_CIFS_STATS | ||
166 | if(tcon != NULL) { | ||
167 | atomic_inc(&tcon->num_smbs_sent); | ||
168 | } | ||
169 | #endif /* CONFIG_CIFS_STATS */ | ||
170 | return rc; | ||
171 | } | ||
172 | |||
173 | /* If the return code is zero, this function must fill in request_buf pointer */ | ||
174 | static int | ||
175 | smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | ||
176 | void **request_buf /* returned */ , | ||
177 | void **response_buf /* returned */ ) | ||
178 | { | ||
179 | int rc = 0; | ||
180 | |||
181 | /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so | ||
182 | check for tcp and smb session status done differently | ||
183 | for those three - in the calling routine */ | ||
184 | if(tcon) { | ||
185 | if((tcon->ses) && (tcon->ses->server)){ | ||
186 | struct nls_table *nls_codepage; | ||
187 | /* Give Demultiplex thread up to 10 seconds to | ||
188 | reconnect, should be greater than cifs socket | ||
189 | timeout which is 7 seconds */ | ||
190 | while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { | ||
191 | wait_event_interruptible_timeout(tcon->ses->server->response_q, | ||
192 | (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); | ||
193 | if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { | ||
194 | /* on "soft" mounts we wait once */ | ||
195 | if((tcon->retry == FALSE) || | ||
196 | (tcon->ses->status == CifsExiting)) { | ||
197 | cFYI(1,("gave up waiting on reconnect in smb_init")); | ||
198 | return -EHOSTDOWN; | ||
199 | } /* else "hard" mount - keep retrying until | ||
200 | process is killed or server comes back up */ | ||
201 | } else /* TCP session is reestablished now */ | ||
202 | break; | ||
203 | |||
204 | } | ||
205 | |||
206 | nls_codepage = load_nls_default(); | ||
207 | /* need to prevent multiple threads trying to | ||
208 | simultaneously reconnect the same SMB session */ | ||
209 | down(&tcon->ses->sesSem); | ||
210 | if(tcon->ses->status == CifsNeedReconnect) | ||
211 | rc = cifs_setup_session(0, tcon->ses, nls_codepage); | ||
212 | if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { | ||
213 | mark_open_files_invalid(tcon); | ||
214 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, | ||
215 | nls_codepage); | ||
216 | up(&tcon->ses->sesSem); | ||
217 | if(rc == 0) | ||
218 | atomic_inc(&tconInfoReconnectCount); | ||
219 | |||
220 | cFYI(1, ("reconnect tcon rc = %d", rc)); | ||
221 | /* Removed call to reopen open files here - | ||
222 | it is safer (and faster) to reopen files | ||
223 | one at a time as needed in read and write */ | ||
224 | |||
225 | /* Check if handle based operation so we | ||
226 | know whether we can continue or not without | ||
227 | returning to caller to reset file handle */ | ||
228 | switch(smb_command) { | ||
229 | case SMB_COM_READ_ANDX: | ||
230 | case SMB_COM_WRITE_ANDX: | ||
231 | case SMB_COM_CLOSE: | ||
232 | case SMB_COM_FIND_CLOSE2: | ||
233 | case SMB_COM_LOCKING_ANDX: { | ||
234 | unload_nls(nls_codepage); | ||
235 | return -EAGAIN; | ||
236 | } | ||
237 | } | ||
238 | } else { | ||
239 | up(&tcon->ses->sesSem); | ||
240 | } | ||
241 | unload_nls(nls_codepage); | ||
242 | |||
243 | } else { | ||
244 | return -EIO; | ||
245 | } | ||
246 | } | ||
247 | if(rc) | ||
248 | return rc; | ||
249 | |||
250 | *request_buf = cifs_buf_get(); | ||
251 | if (*request_buf == NULL) { | ||
252 | /* BB should we add a retry in here if not a writepage? */ | ||
253 | return -ENOMEM; | ||
254 | } | ||
255 | /* Although the original thought was we needed the response buf for */ | ||
256 | /* potential retries of smb operations it turns out we can determine */ | ||
257 | /* from the mid flags when the request buffer can be resent without */ | ||
258 | /* having to use a second distinct buffer for the response */ | ||
259 | *response_buf = *request_buf; | ||
260 | |||
261 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, | ||
262 | wct /*wct */ ); | ||
263 | |||
264 | #ifdef CONFIG_CIFS_STATS | ||
265 | if(tcon != NULL) { | ||
266 | atomic_inc(&tcon->num_smbs_sent); | ||
267 | } | ||
268 | #endif /* CONFIG_CIFS_STATS */ | ||
269 | return rc; | ||
270 | } | ||
271 | |||
272 | static int validate_t2(struct smb_t2_rsp * pSMB) | ||
273 | { | ||
274 | int rc = -EINVAL; | ||
275 | int total_size; | ||
276 | char * pBCC; | ||
277 | |||
278 | /* check for plausible wct, bcc and t2 data and parm sizes */ | ||
279 | /* check for parm and data offset going beyond end of smb */ | ||
280 | if(pSMB->hdr.WordCount >= 10) { | ||
281 | if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) && | ||
282 | (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) { | ||
283 | /* check that bcc is at least as big as parms + data */ | ||
284 | /* check that bcc is less than negotiated smb buffer */ | ||
285 | total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount); | ||
286 | if(total_size < 512) { | ||
287 | total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount); | ||
288 | /* BCC le converted in SendReceive */ | ||
289 | pBCC = (pSMB->hdr.WordCount * 2) + sizeof(struct smb_hdr) + | ||
290 | (char *)pSMB; | ||
291 | if((total_size <= (*(u16 *)pBCC)) && | ||
292 | (total_size < | ||
293 | CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) { | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | } | ||
298 | } | ||
299 | } | ||
300 | cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB, | ||
301 | sizeof(struct smb_t2_rsp) + 16); | ||
302 | return rc; | ||
303 | } | ||
304 | int | ||
305 | CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | ||
306 | { | ||
307 | NEGOTIATE_REQ *pSMB; | ||
308 | NEGOTIATE_RSP *pSMBr; | ||
309 | int rc = 0; | ||
310 | int bytes_returned; | ||
311 | struct TCP_Server_Info * server; | ||
312 | u16 count; | ||
313 | |||
314 | if(ses->server) | ||
315 | server = ses->server; | ||
316 | else { | ||
317 | rc = -EIO; | ||
318 | return rc; | ||
319 | } | ||
320 | rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , | ||
321 | (void **) &pSMB, (void **) &pSMBr); | ||
322 | if (rc) | ||
323 | return rc; | ||
324 | |||
325 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | ||
326 | if (extended_security) | ||
327 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
328 | |||
329 | count = strlen(protocols[0].name) + 1; | ||
330 | strncpy(pSMB->DialectsArray, protocols[0].name, 30); | ||
331 | /* null guaranteed to be at end of source and target buffers anyway */ | ||
332 | |||
333 | pSMB->hdr.smb_buf_length += count; | ||
334 | pSMB->ByteCount = cpu_to_le16(count); | ||
335 | |||
336 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | ||
337 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
338 | if (rc == 0) { | ||
339 | server->secMode = pSMBr->SecurityMode; | ||
340 | server->secType = NTLM; /* BB override default for NTLMv2 or krb*/ | ||
341 | /* one byte - no need to convert this or EncryptionKeyLen from le,*/ | ||
342 | server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); | ||
343 | /* probably no need to store and check maxvcs */ | ||
344 | server->maxBuf = | ||
345 | min(le32_to_cpu(pSMBr->MaxBufferSize), | ||
346 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | ||
347 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); | ||
348 | cFYI(0, ("Max buf = %d ", ses->server->maxBuf)); | ||
349 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); | ||
350 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | ||
351 | server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); | ||
352 | /* BB with UTC do we ever need to be using srvr timezone? */ | ||
353 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | ||
354 | memcpy(server->cryptKey, pSMBr->u.EncryptionKey, | ||
355 | CIFS_CRYPTO_KEY_SIZE); | ||
356 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) | ||
357 | && (pSMBr->EncryptionKeyLength == 0)) { | ||
358 | /* decode security blob */ | ||
359 | } else | ||
360 | rc = -EIO; | ||
361 | |||
362 | /* BB might be helpful to save off the domain of server here */ | ||
363 | |||
364 | if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && | ||
365 | (server->capabilities & CAP_EXTENDED_SECURITY)) { | ||
366 | count = pSMBr->ByteCount; | ||
367 | if (count < 16) | ||
368 | rc = -EIO; | ||
369 | else if (count == 16) { | ||
370 | server->secType = RawNTLMSSP; | ||
371 | if (server->socketUseCount.counter > 1) { | ||
372 | if (memcmp | ||
373 | (server->server_GUID, | ||
374 | pSMBr->u.extended_response. | ||
375 | GUID, 16) != 0) { | ||
376 | cFYI(1, | ||
377 | ("UID of server does not match previous connection to same ip address")); | ||
378 | memcpy(server-> | ||
379 | server_GUID, | ||
380 | pSMBr->u. | ||
381 | extended_response. | ||
382 | GUID, 16); | ||
383 | } | ||
384 | } else | ||
385 | memcpy(server->server_GUID, | ||
386 | pSMBr->u.extended_response. | ||
387 | GUID, 16); | ||
388 | } else { | ||
389 | rc = decode_negTokenInit(pSMBr->u. | ||
390 | extended_response. | ||
391 | SecurityBlob, | ||
392 | count - 16, | ||
393 | &server->secType); | ||
394 | if(rc == 1) { | ||
395 | /* BB Need to fill struct for sessetup here */ | ||
396 | rc = -EOPNOTSUPP; | ||
397 | } else { | ||
398 | rc = -EINVAL; | ||
399 | } | ||
400 | } | ||
401 | } else | ||
402 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | ||
403 | if(sign_CIFS_PDUs == FALSE) { | ||
404 | if(server->secMode & SECMODE_SIGN_REQUIRED) | ||
405 | cERROR(1, | ||
406 | ("Server requires /proc/fs/cifs/PacketSigningEnabled")); | ||
407 | server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
408 | } else if(sign_CIFS_PDUs == 1) { | ||
409 | if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) | ||
410 | server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
411 | } | ||
412 | |||
413 | } | ||
414 | if (pSMB) | ||
415 | cifs_buf_release(pSMB); | ||
416 | return rc; | ||
417 | } | ||
418 | |||
419 | int | ||
420 | CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | ||
421 | { | ||
422 | struct smb_hdr *smb_buffer; | ||
423 | struct smb_hdr *smb_buffer_response; /* BB removeme BB */ | ||
424 | int rc = 0; | ||
425 | int length; | ||
426 | |||
427 | cFYI(1, ("In tree disconnect")); | ||
428 | /* | ||
429 | * If last user of the connection and | ||
430 | * connection alive - disconnect it | ||
431 | * If this is the last connection on the server session disconnect it | ||
432 | * (and inside session disconnect we should check if tcp socket needs | ||
433 | * to be freed and kernel thread woken up). | ||
434 | */ | ||
435 | if (tcon) | ||
436 | down(&tcon->tconSem); | ||
437 | else | ||
438 | return -EIO; | ||
439 | |||
440 | atomic_dec(&tcon->useCount); | ||
441 | if (atomic_read(&tcon->useCount) > 0) { | ||
442 | up(&tcon->tconSem); | ||
443 | return -EBUSY; | ||
444 | } | ||
445 | |||
446 | /* No need to return error on this operation if tid invalidated and | ||
447 | closed on server already e.g. due to tcp session crashing */ | ||
448 | if(tcon->tidStatus == CifsNeedReconnect) { | ||
449 | up(&tcon->tconSem); | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | if((tcon->ses == NULL) || (tcon->ses->server == NULL)) { | ||
454 | up(&tcon->tconSem); | ||
455 | return -EIO; | ||
456 | } | ||
457 | rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **)&smb_buffer); | ||
458 | if (rc) { | ||
459 | up(&tcon->tconSem); | ||
460 | return rc; | ||
461 | } else { | ||
462 | smb_buffer_response = smb_buffer; /* BB removeme BB */ | ||
463 | } | ||
464 | rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, | ||
465 | &length, 0); | ||
466 | if (rc) | ||
467 | cFYI(1, (" Tree disconnect failed %d", rc)); | ||
468 | |||
469 | if (smb_buffer) | ||
470 | cifs_small_buf_release(smb_buffer); | ||
471 | up(&tcon->tconSem); | ||
472 | |||
473 | /* No need to return error on this operation if tid invalidated and | ||
474 | closed on server already e.g. due to tcp session crashing */ | ||
475 | if (rc == -EAGAIN) | ||
476 | rc = 0; | ||
477 | |||
478 | return rc; | ||
479 | } | ||
480 | |||
481 | int | ||
482 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | ||
483 | { | ||
484 | struct smb_hdr *smb_buffer_response; | ||
485 | LOGOFF_ANDX_REQ *pSMB; | ||
486 | int rc = 0; | ||
487 | int length; | ||
488 | |||
489 | cFYI(1, ("In SMBLogoff for session disconnect")); | ||
490 | if (ses) | ||
491 | down(&ses->sesSem); | ||
492 | else | ||
493 | return -EIO; | ||
494 | |||
495 | atomic_dec(&ses->inUse); | ||
496 | if (atomic_read(&ses->inUse) > 0) { | ||
497 | up(&ses->sesSem); | ||
498 | return -EBUSY; | ||
499 | } | ||
500 | rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); | ||
501 | if (rc) { | ||
502 | up(&ses->sesSem); | ||
503 | return rc; | ||
504 | } | ||
505 | |||
506 | smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ | ||
507 | |||
508 | if(ses->server) { | ||
509 | if(ses->server->secMode & | ||
510 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
511 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
512 | } | ||
513 | |||
514 | pSMB->hdr.Uid = ses->Suid; | ||
515 | |||
516 | pSMB->AndXCommand = 0xFF; | ||
517 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | ||
518 | smb_buffer_response, &length, 0); | ||
519 | if (ses->server) { | ||
520 | atomic_dec(&ses->server->socketUseCount); | ||
521 | if (atomic_read(&ses->server->socketUseCount) == 0) { | ||
522 | spin_lock(&GlobalMid_Lock); | ||
523 | ses->server->tcpStatus = CifsExiting; | ||
524 | spin_unlock(&GlobalMid_Lock); | ||
525 | rc = -ESHUTDOWN; | ||
526 | } | ||
527 | } | ||
528 | if (pSMB) | ||
529 | cifs_small_buf_release(pSMB); | ||
530 | up(&ses->sesSem); | ||
531 | |||
532 | /* if session dead then we do not need to do ulogoff, | ||
533 | since server closed smb session, no sense reporting | ||
534 | error */ | ||
535 | if (rc == -EAGAIN) | ||
536 | rc = 0; | ||
537 | return rc; | ||
538 | } | ||
539 | |||
540 | int | ||
541 | CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, | ||
542 | const char *fileName, const struct nls_table *nls_codepage) | ||
543 | { | ||
544 | DELETE_FILE_REQ *pSMB = NULL; | ||
545 | DELETE_FILE_RSP *pSMBr = NULL; | ||
546 | int rc = 0; | ||
547 | int bytes_returned; | ||
548 | int name_len; | ||
549 | |||
550 | DelFileRetry: | ||
551 | rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, | ||
552 | (void **) &pSMBr); | ||
553 | if (rc) | ||
554 | return rc; | ||
555 | |||
556 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
557 | name_len = | ||
558 | cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, PATH_MAX | ||
559 | /* find define for this maxpathcomponent */ | ||
560 | , nls_codepage); | ||
561 | name_len++; /* trailing null */ | ||
562 | name_len *= 2; | ||
563 | } else { /* BB improve the check for buffer overruns BB */ | ||
564 | name_len = strnlen(fileName, PATH_MAX); | ||
565 | name_len++; /* trailing null */ | ||
566 | strncpy(pSMB->fileName, fileName, name_len); | ||
567 | } | ||
568 | pSMB->SearchAttributes = | ||
569 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); | ||
570 | pSMB->BufferFormat = 0x04; | ||
571 | pSMB->hdr.smb_buf_length += name_len + 1; | ||
572 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | ||
573 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
574 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
575 | if (rc) { | ||
576 | cFYI(1, ("Error in RMFile = %d", rc)); | ||
577 | } | ||
578 | #ifdef CONFIG_CIFS_STATS | ||
579 | else { | ||
580 | atomic_inc(&tcon->num_deletes); | ||
581 | } | ||
582 | #endif | ||
583 | |||
584 | cifs_buf_release(pSMB); | ||
585 | if (rc == -EAGAIN) | ||
586 | goto DelFileRetry; | ||
587 | |||
588 | return rc; | ||
589 | } | ||
590 | |||
591 | int | ||
592 | CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, | ||
593 | const char *dirName, const struct nls_table *nls_codepage) | ||
594 | { | ||
595 | DELETE_DIRECTORY_REQ *pSMB = NULL; | ||
596 | DELETE_DIRECTORY_RSP *pSMBr = NULL; | ||
597 | int rc = 0; | ||
598 | int bytes_returned; | ||
599 | int name_len; | ||
600 | |||
601 | cFYI(1, ("In CIFSSMBRmDir")); | ||
602 | RmDirRetry: | ||
603 | rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB, | ||
604 | (void **) &pSMBr); | ||
605 | if (rc) | ||
606 | return rc; | ||
607 | |||
608 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
609 | name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, PATH_MAX | ||
610 | /* find define for this maxpathcomponent */ | ||
611 | , nls_codepage); | ||
612 | name_len++; /* trailing null */ | ||
613 | name_len *= 2; | ||
614 | } else { /* BB improve the check for buffer overruns BB */ | ||
615 | name_len = strnlen(dirName, PATH_MAX); | ||
616 | name_len++; /* trailing null */ | ||
617 | strncpy(pSMB->DirName, dirName, name_len); | ||
618 | } | ||
619 | |||
620 | pSMB->BufferFormat = 0x04; | ||
621 | pSMB->hdr.smb_buf_length += name_len + 1; | ||
622 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | ||
623 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
624 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
625 | if (rc) { | ||
626 | cFYI(1, ("Error in RMDir = %d", rc)); | ||
627 | } | ||
628 | #ifdef CONFIG_CIFS_STATS | ||
629 | else { | ||
630 | atomic_inc(&tcon->num_rmdirs); | ||
631 | } | ||
632 | #endif | ||
633 | |||
634 | cifs_buf_release(pSMB); | ||
635 | if (rc == -EAGAIN) | ||
636 | goto RmDirRetry; | ||
637 | return rc; | ||
638 | } | ||
639 | |||
640 | int | ||
641 | CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, | ||
642 | const char *name, const struct nls_table *nls_codepage) | ||
643 | { | ||
644 | int rc = 0; | ||
645 | CREATE_DIRECTORY_REQ *pSMB = NULL; | ||
646 | CREATE_DIRECTORY_RSP *pSMBr = NULL; | ||
647 | int bytes_returned; | ||
648 | int name_len; | ||
649 | |||
650 | cFYI(1, ("In CIFSSMBMkDir")); | ||
651 | MkDirRetry: | ||
652 | rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB, | ||
653 | (void **) &pSMBr); | ||
654 | if (rc) | ||
655 | return rc; | ||
656 | |||
657 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
658 | name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, PATH_MAX | ||
659 | /* find define for this maxpathcomponent */ | ||
660 | , nls_codepage); | ||
661 | name_len++; /* trailing null */ | ||
662 | name_len *= 2; | ||
663 | } else { /* BB improve the check for buffer overruns BB */ | ||
664 | name_len = strnlen(name, PATH_MAX); | ||
665 | name_len++; /* trailing null */ | ||
666 | strncpy(pSMB->DirName, name, name_len); | ||
667 | } | ||
668 | |||
669 | pSMB->BufferFormat = 0x04; | ||
670 | pSMB->hdr.smb_buf_length += name_len + 1; | ||
671 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | ||
672 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
673 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
674 | if (rc) { | ||
675 | cFYI(1, ("Error in Mkdir = %d", rc)); | ||
676 | } | ||
677 | #ifdef CONFIG_CIFS_STATS | ||
678 | else { | ||
679 | atomic_inc(&tcon->num_mkdirs); | ||
680 | } | ||
681 | #endif | ||
682 | cifs_buf_release(pSMB); | ||
683 | if (rc == -EAGAIN) | ||
684 | goto MkDirRetry; | ||
685 | return rc; | ||
686 | } | ||
687 | |||
688 | int | ||
689 | CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | ||
690 | const char *fileName, const int openDisposition, | ||
691 | const int access_flags, const int create_options, __u16 * netfid, | ||
692 | int *pOplock, FILE_ALL_INFO * pfile_info, | ||
693 | const struct nls_table *nls_codepage) | ||
694 | { | ||
695 | int rc = -EACCES; | ||
696 | OPEN_REQ *pSMB = NULL; | ||
697 | OPEN_RSP *pSMBr = NULL; | ||
698 | int bytes_returned; | ||
699 | int name_len; | ||
700 | __u16 count; | ||
701 | |||
702 | openRetry: | ||
703 | rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB, | ||
704 | (void **) &pSMBr); | ||
705 | if (rc) | ||
706 | return rc; | ||
707 | |||
708 | pSMB->AndXCommand = 0xFF; /* none */ | ||
709 | |||
710 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
711 | count = 1; /* account for one byte pad to word boundary */ | ||
712 | name_len = | ||
713 | cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1), | ||
714 | fileName, PATH_MAX | ||
715 | /* find define for this maxpathcomponent */ | ||
716 | , nls_codepage); | ||
717 | name_len++; /* trailing null */ | ||
718 | name_len *= 2; | ||
719 | pSMB->NameLength = cpu_to_le16(name_len); | ||
720 | } else { /* BB improve the check for buffer overruns BB */ | ||
721 | count = 0; /* no pad */ | ||
722 | name_len = strnlen(fileName, PATH_MAX); | ||
723 | name_len++; /* trailing null */ | ||
724 | pSMB->NameLength = cpu_to_le16(name_len); | ||
725 | strncpy(pSMB->fileName, fileName, name_len); | ||
726 | } | ||
727 | if (*pOplock & REQ_OPLOCK) | ||
728 | pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK); | ||
729 | else if (*pOplock & REQ_BATCHOPLOCK) { | ||
730 | pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); | ||
731 | } | ||
732 | pSMB->DesiredAccess = cpu_to_le32(access_flags); | ||
733 | pSMB->AllocationSize = 0; | ||
734 | pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); | ||
735 | /* XP does not handle ATTR_POSIX_SEMANTICS */ | ||
736 | /* but it helps speed up case sensitive checks for other | ||
737 | servers such as Samba */ | ||
738 | if (tcon->ses->capabilities & CAP_UNIX) | ||
739 | pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); | ||
740 | |||
741 | /* if ((omode & S_IWUGO) == 0) | ||
742 | pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ | ||
743 | /* Above line causes problems due to vfs splitting create into two | ||
744 | pieces - need to set mode after file created not while it is | ||
745 | being created */ | ||
746 | pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); | ||
747 | pSMB->CreateDisposition = cpu_to_le32(openDisposition); | ||
748 | pSMB->CreateOptions = cpu_to_le32(create_options); | ||
749 | pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/ | ||
750 | pSMB->SecurityFlags = | ||
751 | SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY; | ||
752 | |||
753 | count += name_len; | ||
754 | pSMB->hdr.smb_buf_length += count; | ||
755 | |||
756 | pSMB->ByteCount = cpu_to_le16(count); | ||
757 | /* long_op set to 1 to allow for oplock break timeouts */ | ||
758 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
759 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); | ||
760 | if (rc) { | ||
761 | cFYI(1, ("Error in Open = %d", rc)); | ||
762 | } else { | ||
763 | *pOplock = pSMBr->OplockLevel; /* one byte no need to le_to_cpu */ | ||
764 | *netfid = pSMBr->Fid; /* cifs fid stays in le */ | ||
765 | /* Let caller know file was created so we can set the mode. */ | ||
766 | /* Do we care about the CreateAction in any other cases? */ | ||
767 | if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) | ||
768 | *pOplock |= CIFS_CREATE_ACTION; | ||
769 | if(pfile_info) { | ||
770 | memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime, | ||
771 | 36 /* CreationTime to Attributes */); | ||
772 | /* the file_info buf is endian converted by caller */ | ||
773 | pfile_info->AllocationSize = pSMBr->AllocationSize; | ||
774 | pfile_info->EndOfFile = pSMBr->EndOfFile; | ||
775 | pfile_info->NumberOfLinks = cpu_to_le32(1); | ||
776 | } | ||
777 | |||
778 | #ifdef CONFIG_CIFS_STATS | ||
779 | atomic_inc(&tcon->num_opens); | ||
780 | #endif | ||
781 | } | ||
782 | cifs_buf_release(pSMB); | ||
783 | if (rc == -EAGAIN) | ||
784 | goto openRetry; | ||
785 | return rc; | ||
786 | } | ||
787 | |||
788 | /* If no buffer passed in, then caller wants to do the copy | ||
789 | as in the case of readpages so the SMB buffer must be | ||
790 | freed by the caller */ | ||
791 | |||
792 | int | ||
793 | CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | ||
794 | const int netfid, const unsigned int count, | ||
795 | const __u64 lseek, unsigned int *nbytes, char **buf) | ||
796 | { | ||
797 | int rc = -EACCES; | ||
798 | READ_REQ *pSMB = NULL; | ||
799 | READ_RSP *pSMBr = NULL; | ||
800 | char *pReadData = NULL; | ||
801 | int bytes_returned; | ||
802 | |||
803 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); | ||
804 | |||
805 | *nbytes = 0; | ||
806 | rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB, | ||
807 | (void **) &pSMBr); | ||
808 | if (rc) | ||
809 | return rc; | ||
810 | |||
811 | /* tcon and ses pointer are checked in smb_init */ | ||
812 | if (tcon->ses->server == NULL) | ||
813 | return -ECONNABORTED; | ||
814 | |||
815 | pSMB->AndXCommand = 0xFF; /* none */ | ||
816 | pSMB->Fid = netfid; | ||
817 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); | ||
818 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | ||
819 | pSMB->Remaining = 0; | ||
820 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); | ||
821 | pSMB->MaxCountHigh = cpu_to_le32(count >> 16); | ||
822 | pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ | ||
823 | |||
824 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
825 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
826 | if (rc) { | ||
827 | cERROR(1, ("Send error in read = %d", rc)); | ||
828 | } else { | ||
829 | int data_length = le16_to_cpu(pSMBr->DataLengthHigh); | ||
830 | data_length = data_length << 16; | ||
831 | data_length += le16_to_cpu(pSMBr->DataLength); | ||
832 | *nbytes = data_length; | ||
833 | |||
834 | /*check that DataLength would not go beyond end of SMB */ | ||
835 | if ((data_length > CIFSMaxBufSize) | ||
836 | || (data_length > count)) { | ||
837 | cFYI(1,("bad length %d for count %d",data_length,count)); | ||
838 | rc = -EIO; | ||
839 | *nbytes = 0; | ||
840 | } else { | ||
841 | pReadData = | ||
842 | (char *) (&pSMBr->hdr.Protocol) + | ||
843 | le16_to_cpu(pSMBr->DataOffset); | ||
844 | /* if(rc = copy_to_user(buf, pReadData, data_length)) { | ||
845 | cERROR(1,("Faulting on read rc = %d",rc)); | ||
846 | rc = -EFAULT; | ||
847 | }*/ /* can not use copy_to_user when using page cache*/ | ||
848 | if(*buf) | ||
849 | memcpy(*buf,pReadData,data_length); | ||
850 | } | ||
851 | } | ||
852 | if(*buf) | ||
853 | cifs_buf_release(pSMB); | ||
854 | else | ||
855 | *buf = (char *)pSMB; | ||
856 | |||
857 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
858 | since file handle passed in no longer valid */ | ||
859 | return rc; | ||
860 | } | ||
861 | |||
862 | int | ||
863 | CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | ||
864 | const int netfid, const unsigned int count, | ||
865 | const __u64 offset, unsigned int *nbytes, const char *buf, | ||
866 | const char __user * ubuf, const int long_op) | ||
867 | { | ||
868 | int rc = -EACCES; | ||
869 | WRITE_REQ *pSMB = NULL; | ||
870 | WRITE_RSP *pSMBr = NULL; | ||
871 | int bytes_returned; | ||
872 | __u32 bytes_sent; | ||
873 | __u16 byte_count; | ||
874 | |||
875 | /* cFYI(1,("write at %lld %d bytes",offset,count));*/ | ||
876 | rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB, | ||
877 | (void **) &pSMBr); | ||
878 | if (rc) | ||
879 | return rc; | ||
880 | /* tcon and ses pointer are checked in smb_init */ | ||
881 | if (tcon->ses->server == NULL) | ||
882 | return -ECONNABORTED; | ||
883 | |||
884 | pSMB->AndXCommand = 0xFF; /* none */ | ||
885 | pSMB->Fid = netfid; | ||
886 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | ||
887 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | ||
888 | pSMB->Reserved = 0xFFFFFFFF; | ||
889 | pSMB->WriteMode = 0; | ||
890 | pSMB->Remaining = 0; | ||
891 | |||
892 | /* Can increase buffer size if buffer is big enough in some cases - ie we | ||
893 | can send more if LARGE_WRITE_X capability returned by the server and if | ||
894 | our buffer is big enough or if we convert to iovecs on socket writes | ||
895 | and eliminate the copy to the CIFS buffer */ | ||
896 | if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) { | ||
897 | bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count); | ||
898 | } else { | ||
899 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) | ||
900 | & ~0xFF; | ||
901 | } | ||
902 | |||
903 | if (bytes_sent > count) | ||
904 | bytes_sent = count; | ||
905 | pSMB->DataOffset = | ||
906 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | ||
907 | if(buf) | ||
908 | memcpy(pSMB->Data,buf,bytes_sent); | ||
909 | else if(ubuf) { | ||
910 | if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) { | ||
911 | cifs_buf_release(pSMB); | ||
912 | return -EFAULT; | ||
913 | } | ||
914 | } else { | ||
915 | /* No buffer */ | ||
916 | cifs_buf_release(pSMB); | ||
917 | return -EINVAL; | ||
918 | } | ||
919 | |||
920 | byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */ | ||
921 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); | ||
922 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); | ||
923 | pSMB->hdr.smb_buf_length += bytes_sent+1; | ||
924 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
925 | |||
926 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
927 | (struct smb_hdr *) pSMBr, &bytes_returned, long_op); | ||
928 | if (rc) { | ||
929 | cFYI(1, ("Send error in write = %d", rc)); | ||
930 | *nbytes = 0; | ||
931 | } else { | ||
932 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | ||
933 | *nbytes = (*nbytes) << 16; | ||
934 | *nbytes += le16_to_cpu(pSMBr->Count); | ||
935 | } | ||
936 | |||
937 | cifs_buf_release(pSMB); | ||
938 | |||
939 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
940 | since file handle passed in no longer valid */ | ||
941 | |||
942 | return rc; | ||
943 | } | ||
944 | |||
945 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
946 | int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | ||
947 | const int netfid, const unsigned int count, | ||
948 | const __u64 offset, unsigned int *nbytes, const char __user *buf, | ||
949 | const int long_op) | ||
950 | { | ||
951 | int rc = -EACCES; | ||
952 | WRITE_REQ *pSMB = NULL; | ||
953 | WRITE_RSP *pSMBr = NULL; | ||
954 | /*int bytes_returned;*/ | ||
955 | unsigned bytes_sent; | ||
956 | __u16 byte_count; | ||
957 | |||
958 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); | ||
959 | |||
960 | if (rc) | ||
961 | return rc; | ||
962 | |||
963 | pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */ | ||
964 | |||
965 | /* tcon and ses pointer are checked in smb_init */ | ||
966 | if (tcon->ses->server == NULL) | ||
967 | return -ECONNABORTED; | ||
968 | |||
969 | pSMB->AndXCommand = 0xFF; /* none */ | ||
970 | pSMB->Fid = netfid; | ||
971 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | ||
972 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | ||
973 | pSMB->Reserved = 0xFFFFFFFF; | ||
974 | pSMB->WriteMode = 0; | ||
975 | pSMB->Remaining = 0; | ||
976 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF; | ||
977 | if (bytes_sent > count) | ||
978 | bytes_sent = count; | ||
979 | pSMB->DataLengthHigh = 0; | ||
980 | pSMB->DataOffset = | ||
981 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | ||
982 | |||
983 | byte_count = bytes_sent + 1 /* pad */ ; | ||
984 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent); | ||
985 | pSMB->DataLengthHigh = 0; | ||
986 | pSMB->hdr.smb_buf_length += byte_count; | ||
987 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
988 | |||
989 | /* rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
990 | (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */ /* BB fixme BB */ | ||
991 | if (rc) { | ||
992 | cFYI(1, ("Send error in write2 (large write) = %d", rc)); | ||
993 | *nbytes = 0; | ||
994 | } else | ||
995 | *nbytes = le16_to_cpu(pSMBr->Count); | ||
996 | |||
997 | cifs_small_buf_release(pSMB); | ||
998 | |||
999 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
1000 | since file handle passed in no longer valid */ | ||
1001 | |||
1002 | return rc; | ||
1003 | } | ||
1004 | #endif /* CIFS_EXPERIMENTAL */ | ||
1005 | |||
1006 | int | ||
1007 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | ||
1008 | const __u16 smb_file_id, const __u64 len, | ||
1009 | const __u64 offset, const __u32 numUnlock, | ||
1010 | const __u32 numLock, const __u8 lockType, const int waitFlag) | ||
1011 | { | ||
1012 | int rc = 0; | ||
1013 | LOCK_REQ *pSMB = NULL; | ||
1014 | LOCK_RSP *pSMBr = NULL; | ||
1015 | int bytes_returned; | ||
1016 | int timeout = 0; | ||
1017 | __u16 count; | ||
1018 | |||
1019 | cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock)); | ||
1020 | rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB, | ||
1021 | (void **) &pSMBr); | ||
1022 | if (rc) | ||
1023 | return rc; | ||
1024 | |||
1025 | if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) { | ||
1026 | timeout = -1; /* no response expected */ | ||
1027 | pSMB->Timeout = 0; | ||
1028 | } else if (waitFlag == TRUE) { | ||
1029 | timeout = 3; /* blocking operation, no timeout */ | ||
1030 | pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */ | ||
1031 | } else { | ||
1032 | pSMB->Timeout = 0; | ||
1033 | } | ||
1034 | |||
1035 | pSMB->NumberOfLocks = cpu_to_le16(numLock); | ||
1036 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); | ||
1037 | pSMB->LockType = lockType; | ||
1038 | pSMB->AndXCommand = 0xFF; /* none */ | ||
1039 | pSMB->Fid = smb_file_id; /* netfid stays le */ | ||
1040 | |||
1041 | if((numLock != 0) || (numUnlock != 0)) { | ||
1042 | pSMB->Locks[0].Pid = cpu_to_le16(current->tgid); | ||
1043 | /* BB where to store pid high? */ | ||
1044 | pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len); | ||
1045 | pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32)); | ||
1046 | pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset); | ||
1047 | pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32)); | ||
1048 | count = sizeof(LOCKING_ANDX_RANGE); | ||
1049 | } else { | ||
1050 | /* oplock break */ | ||
1051 | count = 0; | ||
1052 | } | ||
1053 | pSMB->hdr.smb_buf_length += count; | ||
1054 | pSMB->ByteCount = cpu_to_le16(count); | ||
1055 | |||
1056 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1057 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); | ||
1058 | |||
1059 | if (rc) { | ||
1060 | cFYI(1, ("Send error in Lock = %d", rc)); | ||
1061 | } | ||
1062 | cifs_buf_release(pSMB); | ||
1063 | |||
1064 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
1065 | since file handle passed in no longer valid */ | ||
1066 | return rc; | ||
1067 | } | ||
1068 | |||
1069 | int | ||
1070 | CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | ||
1071 | { | ||
1072 | int rc = 0; | ||
1073 | CLOSE_REQ *pSMB = NULL; | ||
1074 | CLOSE_RSP *pSMBr = NULL; | ||
1075 | int bytes_returned; | ||
1076 | cFYI(1, ("In CIFSSMBClose")); | ||
1077 | |||
1078 | /* do not retry on dead session on close */ | ||
1079 | rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB); | ||
1080 | if(rc == -EAGAIN) | ||
1081 | return 0; | ||
1082 | if (rc) | ||
1083 | return rc; | ||
1084 | |||
1085 | pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ | ||
1086 | |||
1087 | pSMB->FileID = (__u16) smb_file_id; | ||
1088 | pSMB->LastWriteTime = 0; | ||
1089 | pSMB->ByteCount = 0; | ||
1090 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1091 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
1092 | if (rc) { | ||
1093 | if(rc!=-EINTR) { | ||
1094 | /* EINTR is expected when user ctl-c to kill app */ | ||
1095 | cERROR(1, ("Send error in Close = %d", rc)); | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | cifs_small_buf_release(pSMB); | ||
1100 | |||
1101 | /* Since session is dead, file will be closed on server already */ | ||
1102 | if(rc == -EAGAIN) | ||
1103 | rc = 0; | ||
1104 | |||
1105 | return rc; | ||
1106 | } | ||
1107 | |||
1108 | int | ||
1109 | CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, | ||
1110 | const char *fromName, const char *toName, | ||
1111 | const struct nls_table *nls_codepage) | ||
1112 | { | ||
1113 | int rc = 0; | ||
1114 | RENAME_REQ *pSMB = NULL; | ||
1115 | RENAME_RSP *pSMBr = NULL; | ||
1116 | int bytes_returned; | ||
1117 | int name_len, name_len2; | ||
1118 | __u16 count; | ||
1119 | |||
1120 | cFYI(1, ("In CIFSSMBRename")); | ||
1121 | renameRetry: | ||
1122 | rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB, | ||
1123 | (void **) &pSMBr); | ||
1124 | if (rc) | ||
1125 | return rc; | ||
1126 | |||
1127 | pSMB->BufferFormat = 0x04; | ||
1128 | pSMB->SearchAttributes = | ||
1129 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | | ||
1130 | ATTR_DIRECTORY); | ||
1131 | |||
1132 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
1133 | name_len = | ||
1134 | cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX | ||
1135 | /* find define for this maxpathcomponent */ | ||
1136 | , nls_codepage); | ||
1137 | name_len++; /* trailing null */ | ||
1138 | name_len *= 2; | ||
1139 | pSMB->OldFileName[name_len] = 0x04; /* pad */ | ||
1140 | /* protocol requires ASCII signature byte on Unicode string */ | ||
1141 | pSMB->OldFileName[name_len + 1] = 0x00; | ||
1142 | name_len2 = | ||
1143 | cifs_strtoUCS((wchar_t *) & pSMB-> | ||
1144 | OldFileName[name_len + 2], toName, PATH_MAX, | ||
1145 | nls_codepage); | ||
1146 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; | ||
1147 | name_len2 *= 2; /* convert to bytes */ | ||
1148 | } else { /* BB improve the check for buffer overruns BB */ | ||
1149 | name_len = strnlen(fromName, PATH_MAX); | ||
1150 | name_len++; /* trailing null */ | ||
1151 | strncpy(pSMB->OldFileName, fromName, name_len); | ||
1152 | name_len2 = strnlen(toName, PATH_MAX); | ||
1153 | name_len2++; /* trailing null */ | ||
1154 | pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ | ||
1155 | strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); | ||
1156 | name_len2++; /* trailing null */ | ||
1157 | name_len2++; /* signature byte */ | ||
1158 | } | ||
1159 | |||
1160 | count = 1 /* 1st signature byte */ + name_len + name_len2; | ||
1161 | pSMB->hdr.smb_buf_length += count; | ||
1162 | pSMB->ByteCount = cpu_to_le16(count); | ||
1163 | |||
1164 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1165 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
1166 | if (rc) { | ||
1167 | cFYI(1, ("Send error in rename = %d", rc)); | ||
1168 | } | ||
1169 | |||
1170 | #ifdef CONFIG_CIFS_STATS | ||
1171 | else { | ||
1172 | atomic_inc(&tcon->num_renames); | ||
1173 | } | ||
1174 | #endif | ||
1175 | |||
1176 | cifs_buf_release(pSMB); | ||
1177 | |||
1178 | if (rc == -EAGAIN) | ||
1179 | goto renameRetry; | ||
1180 | |||
1181 | return rc; | ||
1182 | } | ||
1183 | |||
1184 | int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, | ||
1185 | int netfid, char * target_name, const struct nls_table * nls_codepage) | ||
1186 | { | ||
1187 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | ||
1188 | struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; | ||
1189 | struct set_file_rename * rename_info; | ||
1190 | char *data_offset; | ||
1191 | char dummy_string[30]; | ||
1192 | int rc = 0; | ||
1193 | int bytes_returned = 0; | ||
1194 | int len_of_str; | ||
1195 | __u16 params, param_offset, offset, count, byte_count; | ||
1196 | |||
1197 | cFYI(1, ("Rename to File by handle")); | ||
1198 | rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, | ||
1199 | (void **) &pSMBr); | ||
1200 | if (rc) | ||
1201 | return rc; | ||
1202 | |||
1203 | params = 6; | ||
1204 | pSMB->MaxSetupCount = 0; | ||
1205 | pSMB->Reserved = 0; | ||
1206 | pSMB->Flags = 0; | ||
1207 | pSMB->Timeout = 0; | ||
1208 | pSMB->Reserved2 = 0; | ||
1209 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | ||
1210 | offset = param_offset + params; | ||
1211 | |||
1212 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | ||
1213 | rename_info = (struct set_file_rename *) data_offset; | ||
1214 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
1215 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ | ||
1216 | pSMB->SetupCount = 1; | ||
1217 | pSMB->Reserved3 = 0; | ||
1218 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | ||
1219 | byte_count = 3 /* pad */ + params; | ||
1220 | pSMB->ParameterCount = cpu_to_le16(params); | ||
1221 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
1222 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
1223 | pSMB->DataOffset = cpu_to_le16(offset); | ||
1224 | /* construct random name ".cifs_tmp<inodenum><mid>" */ | ||
1225 | rename_info->overwrite = cpu_to_le32(1); | ||
1226 | rename_info->root_fid = 0; | ||
1227 | /* unicode only call */ | ||
1228 | if(target_name == NULL) { | ||
1229 | sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid); | ||
1230 | len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage); | ||
1231 | } else { | ||
1232 | len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, PATH_MAX, nls_codepage); | ||
1233 | } | ||
1234 | rename_info->target_name_len = cpu_to_le32(2 * len_of_str); | ||
1235 | count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2; | ||
1236 | byte_count += count; | ||
1237 | pSMB->DataCount = cpu_to_le16(count); | ||
1238 | pSMB->TotalDataCount = pSMB->DataCount; | ||
1239 | pSMB->Fid = netfid; | ||
1240 | pSMB->InformationLevel = | ||
1241 | cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); | ||
1242 | pSMB->Reserved4 = 0; | ||
1243 | pSMB->hdr.smb_buf_length += byte_count; | ||
1244 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
1245 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, | ||
1246 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
1247 | if (rc) { | ||
1248 | cFYI(1,("Send error in Rename (by file handle) = %d", rc)); | ||
1249 | } | ||
1250 | #ifdef CONFIG_CIFS_STATS | ||
1251 | else { | ||
1252 | atomic_inc(&pTcon->num_t2renames); | ||
1253 | } | ||
1254 | #endif | ||
1255 | cifs_buf_release(pSMB); | ||
1256 | |||
1257 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
1258 | since file handle passed in no longer valid */ | ||
1259 | |||
1260 | return rc; | ||
1261 | } | ||
1262 | |||
1263 | int | ||
1264 | CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, | ||
1265 | const __u16 target_tid, const char *toName, const int flags, | ||
1266 | const struct nls_table *nls_codepage) | ||
1267 | { | ||
1268 | int rc = 0; | ||
1269 | COPY_REQ *pSMB = NULL; | ||
1270 | COPY_RSP *pSMBr = NULL; | ||
1271 | int bytes_returned; | ||
1272 | int name_len, name_len2; | ||
1273 | __u16 count; | ||
1274 | |||
1275 | cFYI(1, ("In CIFSSMBCopy")); | ||
1276 | copyRetry: | ||
1277 | rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB, | ||
1278 | (void **) &pSMBr); | ||
1279 | if (rc) | ||
1280 | return rc; | ||
1281 | |||
1282 | pSMB->BufferFormat = 0x04; | ||
1283 | pSMB->Tid2 = target_tid; | ||
1284 | |||
1285 | pSMB->Flags = cpu_to_le16(flags & COPY_TREE); | ||
1286 | |||
1287 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
1288 | name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, | ||
1289 | fromName, | ||
1290 | PATH_MAX /* find define for this maxpathcomponent */, | ||
1291 | nls_codepage); | ||
1292 | name_len++; /* trailing null */ | ||
1293 | name_len *= 2; | ||
1294 | pSMB->OldFileName[name_len] = 0x04; /* pad */ | ||
1295 | /* protocol requires ASCII signature byte on Unicode string */ | ||
1296 | pSMB->OldFileName[name_len + 1] = 0x00; | ||
1297 | name_len2 = cifs_strtoUCS((wchar_t *) & pSMB-> | ||
1298 | OldFileName[name_len + 2], toName, PATH_MAX, | ||
1299 | nls_codepage); | ||
1300 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; | ||
1301 | name_len2 *= 2; /* convert to bytes */ | ||
1302 | } else { /* BB improve the check for buffer overruns BB */ | ||
1303 | name_len = strnlen(fromName, PATH_MAX); | ||
1304 | name_len++; /* trailing null */ | ||
1305 | strncpy(pSMB->OldFileName, fromName, name_len); | ||
1306 | name_len2 = strnlen(toName, PATH_MAX); | ||
1307 | name_len2++; /* trailing null */ | ||
1308 | pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ | ||
1309 | strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); | ||
1310 | name_len2++; /* trailing null */ | ||
1311 | name_len2++; /* signature byte */ | ||
1312 | } | ||
1313 | |||
1314 | count = 1 /* 1st signature byte */ + name_len + name_len2; | ||
1315 | pSMB->hdr.smb_buf_length += count; | ||
1316 | pSMB->ByteCount = cpu_to_le16(count); | ||
1317 | |||
1318 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1319 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
1320 | if (rc) { | ||
1321 | cFYI(1, ("Send error in copy = %d with %d files copied", | ||
1322 | rc, le16_to_cpu(pSMBr->CopyCount))); | ||
1323 | } | ||
1324 | if (pSMB) | ||
1325 | cifs_buf_release(pSMB); | ||
1326 | |||
1327 | if (rc == -EAGAIN) | ||
1328 | goto copyRetry; | ||
1329 | |||
1330 | return rc; | ||
1331 | } | ||
1332 | |||
1333 | int | ||
1334 | CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon, | ||
1335 | const char *fromName, const char *toName, | ||
1336 | const struct nls_table *nls_codepage) | ||
1337 | { | ||
1338 | TRANSACTION2_SPI_REQ *pSMB = NULL; | ||
1339 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | ||
1340 | char *data_offset; | ||
1341 | int name_len; | ||
1342 | int name_len_target; | ||
1343 | int rc = 0; | ||
1344 | int bytes_returned = 0; | ||
1345 | __u16 params, param_offset, offset, byte_count; | ||
1346 | |||
1347 | cFYI(1, ("In Symlink Unix style")); | ||
1348 | createSymLinkRetry: | ||
1349 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
1350 | (void **) &pSMBr); | ||
1351 | if (rc) | ||
1352 | return rc; | ||
1353 | |||
1354 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
1355 | name_len = | ||
1356 | cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX | ||
1357 | /* find define for this maxpathcomponent */ | ||
1358 | , nls_codepage); | ||
1359 | name_len++; /* trailing null */ | ||
1360 | name_len *= 2; | ||
1361 | |||
1362 | } else { /* BB improve the check for buffer overruns BB */ | ||
1363 | name_len = strnlen(fromName, PATH_MAX); | ||
1364 | name_len++; /* trailing null */ | ||
1365 | strncpy(pSMB->FileName, fromName, name_len); | ||
1366 | } | ||
1367 | params = 6 + name_len; | ||
1368 | pSMB->MaxSetupCount = 0; | ||
1369 | pSMB->Reserved = 0; | ||
1370 | pSMB->Flags = 0; | ||
1371 | pSMB->Timeout = 0; | ||
1372 | pSMB->Reserved2 = 0; | ||
1373 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | ||
1374 | InformationLevel) - 4; | ||
1375 | offset = param_offset + params; | ||
1376 | |||
1377 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | ||
1378 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
1379 | name_len_target = | ||
1380 | cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX | ||
1381 | /* find define for this maxpathcomponent */ | ||
1382 | , nls_codepage); | ||
1383 | name_len_target++; /* trailing null */ | ||
1384 | name_len_target *= 2; | ||
1385 | } else { /* BB improve the check for buffer overruns BB */ | ||
1386 | name_len_target = strnlen(toName, PATH_MAX); | ||
1387 | name_len_target++; /* trailing null */ | ||
1388 | strncpy(data_offset, toName, name_len_target); | ||
1389 | } | ||
1390 | |||
1391 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
1392 | /* BB find exact max on data count below from sess */ | ||
1393 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
1394 | pSMB->SetupCount = 1; | ||
1395 | pSMB->Reserved3 = 0; | ||
1396 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | ||
1397 | byte_count = 3 /* pad */ + params + name_len_target; | ||
1398 | pSMB->DataCount = cpu_to_le16(name_len_target); | ||
1399 | pSMB->ParameterCount = cpu_to_le16(params); | ||
1400 | pSMB->TotalDataCount = pSMB->DataCount; | ||
1401 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
1402 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
1403 | pSMB->DataOffset = cpu_to_le16(offset); | ||
1404 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); | ||
1405 | pSMB->Reserved4 = 0; | ||
1406 | pSMB->hdr.smb_buf_length += byte_count; | ||
1407 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
1408 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1409 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
1410 | if (rc) { | ||
1411 | cFYI(1, | ||
1412 | ("Send error in SetPathInfo (create symlink) = %d", | ||
1413 | rc)); | ||
1414 | } | ||
1415 | |||
1416 | if (pSMB) | ||
1417 | cifs_buf_release(pSMB); | ||
1418 | |||
1419 | if (rc == -EAGAIN) | ||
1420 | goto createSymLinkRetry; | ||
1421 | |||
1422 | return rc; | ||
1423 | } | ||
1424 | |||
1425 | int | ||
1426 | CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon, | ||
1427 | const char *fromName, const char *toName, | ||
1428 | const struct nls_table *nls_codepage) | ||
1429 | { | ||
1430 | TRANSACTION2_SPI_REQ *pSMB = NULL; | ||
1431 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | ||
1432 | char *data_offset; | ||
1433 | int name_len; | ||
1434 | int name_len_target; | ||
1435 | int rc = 0; | ||
1436 | int bytes_returned = 0; | ||
1437 | __u16 params, param_offset, offset, byte_count; | ||
1438 | |||
1439 | cFYI(1, ("In Create Hard link Unix style")); | ||
1440 | createHardLinkRetry: | ||
1441 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
1442 | (void **) &pSMBr); | ||
1443 | if (rc) | ||
1444 | return rc; | ||
1445 | |||
1446 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
1447 | name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, PATH_MAX | ||
1448 | /* find define for this maxpathcomponent */ | ||
1449 | , nls_codepage); | ||
1450 | name_len++; /* trailing null */ | ||
1451 | name_len *= 2; | ||
1452 | |||
1453 | } else { /* BB improve the check for buffer overruns BB */ | ||
1454 | name_len = strnlen(toName, PATH_MAX); | ||
1455 | name_len++; /* trailing null */ | ||
1456 | strncpy(pSMB->FileName, toName, name_len); | ||
1457 | } | ||
1458 | params = 6 + name_len; | ||
1459 | pSMB->MaxSetupCount = 0; | ||
1460 | pSMB->Reserved = 0; | ||
1461 | pSMB->Flags = 0; | ||
1462 | pSMB->Timeout = 0; | ||
1463 | pSMB->Reserved2 = 0; | ||
1464 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | ||
1465 | InformationLevel) - 4; | ||
1466 | offset = param_offset + params; | ||
1467 | |||
1468 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | ||
1469 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
1470 | name_len_target = | ||
1471 | cifs_strtoUCS((wchar_t *) data_offset, fromName, PATH_MAX | ||
1472 | /* find define for this maxpathcomponent */ | ||
1473 | , nls_codepage); | ||
1474 | name_len_target++; /* trailing null */ | ||
1475 | name_len_target *= 2; | ||
1476 | } else { /* BB improve the check for buffer overruns BB */ | ||
1477 | name_len_target = strnlen(fromName, PATH_MAX); | ||
1478 | name_len_target++; /* trailing null */ | ||
1479 | strncpy(data_offset, fromName, name_len_target); | ||
1480 | } | ||
1481 | |||
1482 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
1483 | /* BB find exact max on data count below from sess*/ | ||
1484 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
1485 | pSMB->SetupCount = 1; | ||
1486 | pSMB->Reserved3 = 0; | ||
1487 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | ||
1488 | byte_count = 3 /* pad */ + params + name_len_target; | ||
1489 | pSMB->ParameterCount = cpu_to_le16(params); | ||
1490 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
1491 | pSMB->DataCount = cpu_to_le16(name_len_target); | ||
1492 | pSMB->TotalDataCount = pSMB->DataCount; | ||
1493 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
1494 | pSMB->DataOffset = cpu_to_le16(offset); | ||
1495 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); | ||
1496 | pSMB->Reserved4 = 0; | ||
1497 | pSMB->hdr.smb_buf_length += byte_count; | ||
1498 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
1499 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1500 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
1501 | if (rc) { | ||
1502 | cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); | ||
1503 | } | ||
1504 | |||
1505 | cifs_buf_release(pSMB); | ||
1506 | if (rc == -EAGAIN) | ||
1507 | goto createHardLinkRetry; | ||
1508 | |||
1509 | return rc; | ||
1510 | } | ||
1511 | |||
1512 | int | ||
1513 | CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon, | ||
1514 | const char *fromName, const char *toName, | ||
1515 | const struct nls_table *nls_codepage) | ||
1516 | { | ||
1517 | int rc = 0; | ||
1518 | NT_RENAME_REQ *pSMB = NULL; | ||
1519 | RENAME_RSP *pSMBr = NULL; | ||
1520 | int bytes_returned; | ||
1521 | int name_len, name_len2; | ||
1522 | __u16 count; | ||
1523 | |||
1524 | cFYI(1, ("In CIFSCreateHardLink")); | ||
1525 | winCreateHardLinkRetry: | ||
1526 | |||
1527 | rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB, | ||
1528 | (void **) &pSMBr); | ||
1529 | if (rc) | ||
1530 | return rc; | ||
1531 | |||
1532 | pSMB->SearchAttributes = | ||
1533 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | | ||
1534 | ATTR_DIRECTORY); | ||
1535 | pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK); | ||
1536 | pSMB->ClusterCount = 0; | ||
1537 | |||
1538 | pSMB->BufferFormat = 0x04; | ||
1539 | |||
1540 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
1541 | name_len = | ||
1542 | cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX | ||
1543 | /* find define for this maxpathcomponent */ | ||
1544 | , nls_codepage); | ||
1545 | name_len++; /* trailing null */ | ||
1546 | name_len *= 2; | ||
1547 | pSMB->OldFileName[name_len] = 0; /* pad */ | ||
1548 | pSMB->OldFileName[name_len + 1] = 0x04; | ||
1549 | name_len2 = | ||
1550 | cifs_strtoUCS((wchar_t *) & pSMB-> | ||
1551 | OldFileName[name_len + 2], toName, PATH_MAX, | ||
1552 | nls_codepage); | ||
1553 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; | ||
1554 | name_len2 *= 2; /* convert to bytes */ | ||
1555 | } else { /* BB improve the check for buffer overruns BB */ | ||
1556 | name_len = strnlen(fromName, PATH_MAX); | ||
1557 | name_len++; /* trailing null */ | ||
1558 | strncpy(pSMB->OldFileName, fromName, name_len); | ||
1559 | name_len2 = strnlen(toName, PATH_MAX); | ||
1560 | name_len2++; /* trailing null */ | ||
1561 | pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ | ||
1562 | strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); | ||
1563 | name_len2++; /* trailing null */ | ||
1564 | name_len2++; /* signature byte */ | ||
1565 | } | ||
1566 | |||
1567 | count = 1 /* string type byte */ + name_len + name_len2; | ||
1568 | pSMB->hdr.smb_buf_length += count; | ||
1569 | pSMB->ByteCount = cpu_to_le16(count); | ||
1570 | |||
1571 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1572 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
1573 | if (rc) { | ||
1574 | cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); | ||
1575 | } | ||
1576 | cifs_buf_release(pSMB); | ||
1577 | if (rc == -EAGAIN) | ||
1578 | goto winCreateHardLinkRetry; | ||
1579 | |||
1580 | return rc; | ||
1581 | } | ||
1582 | |||
1583 | int | ||
1584 | CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, | ||
1585 | const unsigned char *searchName, | ||
1586 | char *symlinkinfo, const int buflen, | ||
1587 | const struct nls_table *nls_codepage) | ||
1588 | { | ||
1589 | /* SMB_QUERY_FILE_UNIX_LINK */ | ||
1590 | TRANSACTION2_QPI_REQ *pSMB = NULL; | ||
1591 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | ||
1592 | int rc = 0; | ||
1593 | int bytes_returned; | ||
1594 | int name_len; | ||
1595 | __u16 params, byte_count; | ||
1596 | |||
1597 | cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName)); | ||
1598 | |||
1599 | querySymLinkRetry: | ||
1600 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
1601 | (void **) &pSMBr); | ||
1602 | if (rc) | ||
1603 | return rc; | ||
1604 | |||
1605 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
1606 | name_len = | ||
1607 | cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX | ||
1608 | /* find define for this maxpathcomponent */ | ||
1609 | , nls_codepage); | ||
1610 | name_len++; /* trailing null */ | ||
1611 | name_len *= 2; | ||
1612 | } else { /* BB improve the check for buffer overruns BB */ | ||
1613 | name_len = strnlen(searchName, PATH_MAX); | ||
1614 | name_len++; /* trailing null */ | ||
1615 | strncpy(pSMB->FileName, searchName, name_len); | ||
1616 | } | ||
1617 | |||
1618 | params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; | ||
1619 | pSMB->TotalDataCount = 0; | ||
1620 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
1621 | /* BB find exact max data count below from sess structure BB */ | ||
1622 | pSMB->MaxDataCount = cpu_to_le16(4000); | ||
1623 | pSMB->MaxSetupCount = 0; | ||
1624 | pSMB->Reserved = 0; | ||
1625 | pSMB->Flags = 0; | ||
1626 | pSMB->Timeout = 0; | ||
1627 | pSMB->Reserved2 = 0; | ||
1628 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
1629 | struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); | ||
1630 | pSMB->DataCount = 0; | ||
1631 | pSMB->DataOffset = 0; | ||
1632 | pSMB->SetupCount = 1; | ||
1633 | pSMB->Reserved3 = 0; | ||
1634 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | ||
1635 | byte_count = params + 1 /* pad */ ; | ||
1636 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
1637 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
1638 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); | ||
1639 | pSMB->Reserved4 = 0; | ||
1640 | pSMB->hdr.smb_buf_length += byte_count; | ||
1641 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
1642 | |||
1643 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1644 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
1645 | if (rc) { | ||
1646 | cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc)); | ||
1647 | } else { | ||
1648 | /* decode response */ | ||
1649 | |||
1650 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
1651 | if (rc || (pSMBr->ByteCount < 2)) | ||
1652 | /* BB also check enough total bytes returned */ | ||
1653 | rc = -EIO; /* bad smb */ | ||
1654 | else { | ||
1655 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
1656 | __u16 count = le16_to_cpu(pSMBr->t2.DataCount); | ||
1657 | |||
1658 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
1659 | name_len = UniStrnlen((wchar_t *) ((char *) | ||
1660 | &pSMBr->hdr.Protocol +data_offset), | ||
1661 | min_t(const int, buflen,count) / 2); | ||
1662 | cifs_strfromUCS_le(symlinkinfo, | ||
1663 | (wchar_t *) ((char *)&pSMBr->hdr.Protocol + | ||
1664 | data_offset), | ||
1665 | name_len, nls_codepage); | ||
1666 | } else { | ||
1667 | strncpy(symlinkinfo, | ||
1668 | (char *) &pSMBr->hdr.Protocol + | ||
1669 | data_offset, | ||
1670 | min_t(const int, buflen, count)); | ||
1671 | } | ||
1672 | symlinkinfo[buflen] = 0; | ||
1673 | /* just in case so calling code does not go off the end of buffer */ | ||
1674 | } | ||
1675 | } | ||
1676 | cifs_buf_release(pSMB); | ||
1677 | if (rc == -EAGAIN) | ||
1678 | goto querySymLinkRetry; | ||
1679 | return rc; | ||
1680 | } | ||
1681 | |||
1682 | int | ||
1683 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | ||
1684 | const unsigned char *searchName, | ||
1685 | char *symlinkinfo, const int buflen,__u16 fid, | ||
1686 | const struct nls_table *nls_codepage) | ||
1687 | { | ||
1688 | int rc = 0; | ||
1689 | int bytes_returned; | ||
1690 | int name_len; | ||
1691 | struct smb_com_transaction_ioctl_req * pSMB; | ||
1692 | struct smb_com_transaction_ioctl_rsp * pSMBr; | ||
1693 | |||
1694 | cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName)); | ||
1695 | rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, | ||
1696 | (void **) &pSMBr); | ||
1697 | if (rc) | ||
1698 | return rc; | ||
1699 | |||
1700 | pSMB->TotalParameterCount = 0 ; | ||
1701 | pSMB->TotalDataCount = 0; | ||
1702 | pSMB->MaxParameterCount = cpu_to_le32(2); | ||
1703 | /* BB find exact data count max from sess structure BB */ | ||
1704 | pSMB->MaxDataCount = cpu_to_le32(4000); | ||
1705 | pSMB->MaxSetupCount = 4; | ||
1706 | pSMB->Reserved = 0; | ||
1707 | pSMB->ParameterOffset = 0; | ||
1708 | pSMB->DataCount = 0; | ||
1709 | pSMB->DataOffset = 0; | ||
1710 | pSMB->SetupCount = 4; | ||
1711 | pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); | ||
1712 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
1713 | pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT); | ||
1714 | pSMB->IsFsctl = 1; /* FSCTL */ | ||
1715 | pSMB->IsRootFlag = 0; | ||
1716 | pSMB->Fid = fid; /* file handle always le */ | ||
1717 | pSMB->ByteCount = 0; | ||
1718 | |||
1719 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1720 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
1721 | if (rc) { | ||
1722 | cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc)); | ||
1723 | } else { /* decode response */ | ||
1724 | __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); | ||
1725 | __u32 data_count = le32_to_cpu(pSMBr->DataCount); | ||
1726 | if ((pSMBr->ByteCount < 2) || (data_offset > 512)) | ||
1727 | /* BB also check enough total bytes returned */ | ||
1728 | rc = -EIO; /* bad smb */ | ||
1729 | else { | ||
1730 | if(data_count && (data_count < 2048)) { | ||
1731 | char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount; | ||
1732 | |||
1733 | struct reparse_data * reparse_buf = (struct reparse_data *) | ||
1734 | ((char *)&pSMBr->hdr.Protocol + data_offset); | ||
1735 | if((char*)reparse_buf >= end_of_smb) { | ||
1736 | rc = -EIO; | ||
1737 | goto qreparse_out; | ||
1738 | } | ||
1739 | if((reparse_buf->LinkNamesBuf + | ||
1740 | reparse_buf->TargetNameOffset + | ||
1741 | reparse_buf->TargetNameLen) > | ||
1742 | end_of_smb) { | ||
1743 | cFYI(1,("reparse buf extended beyond SMB")); | ||
1744 | rc = -EIO; | ||
1745 | goto qreparse_out; | ||
1746 | } | ||
1747 | |||
1748 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
1749 | name_len = UniStrnlen((wchar_t *) | ||
1750 | (reparse_buf->LinkNamesBuf + | ||
1751 | reparse_buf->TargetNameOffset), | ||
1752 | min(buflen/2, reparse_buf->TargetNameLen / 2)); | ||
1753 | cifs_strfromUCS_le(symlinkinfo, | ||
1754 | (wchar_t *) (reparse_buf->LinkNamesBuf + | ||
1755 | reparse_buf->TargetNameOffset), | ||
1756 | name_len, nls_codepage); | ||
1757 | } else { /* ASCII names */ | ||
1758 | strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + | ||
1759 | reparse_buf->TargetNameOffset, | ||
1760 | min_t(const int, buflen, reparse_buf->TargetNameLen)); | ||
1761 | } | ||
1762 | } else { | ||
1763 | rc = -EIO; | ||
1764 | cFYI(1,("Invalid return data count on get reparse info ioctl")); | ||
1765 | } | ||
1766 | symlinkinfo[buflen] = 0; /* just in case so the caller | ||
1767 | does not go off the end of the buffer */ | ||
1768 | cFYI(1,("readlink result - %s ",symlinkinfo)); | ||
1769 | } | ||
1770 | } | ||
1771 | qreparse_out: | ||
1772 | if (pSMB) | ||
1773 | cifs_buf_release(pSMB); | ||
1774 | |||
1775 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
1776 | since file handle passed in no longer valid */ | ||
1777 | |||
1778 | return rc; | ||
1779 | } | ||
1780 | |||
1781 | #ifdef CONFIG_CIFS_POSIX | ||
1782 | |||
1783 | /*Convert an Access Control Entry from wire format to local POSIX xattr format*/ | ||
1784 | static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace) | ||
1785 | { | ||
1786 | /* u8 cifs fields do not need le conversion */ | ||
1787 | ace->e_perm = (__u16)cifs_ace->cifs_e_perm; | ||
1788 | ace->e_tag = (__u16)cifs_ace->cifs_e_tag; | ||
1789 | ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid); | ||
1790 | /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */ | ||
1791 | |||
1792 | return; | ||
1793 | } | ||
1794 | |||
1795 | /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */ | ||
1796 | static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,const int acl_type,const int size_of_data_area) | ||
1797 | { | ||
1798 | int size = 0; | ||
1799 | int i; | ||
1800 | __u16 count; | ||
1801 | struct cifs_posix_ace * pACE; | ||
1802 | struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src; | ||
1803 | posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt; | ||
1804 | |||
1805 | if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION) | ||
1806 | return -EOPNOTSUPP; | ||
1807 | |||
1808 | if(acl_type & ACL_TYPE_ACCESS) { | ||
1809 | count = le16_to_cpu(cifs_acl->access_entry_count); | ||
1810 | pACE = &cifs_acl->ace_array[0]; | ||
1811 | size = sizeof(struct cifs_posix_acl); | ||
1812 | size += sizeof(struct cifs_posix_ace) * count; | ||
1813 | /* check if we would go beyond end of SMB */ | ||
1814 | if(size_of_data_area < size) { | ||
1815 | cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size)); | ||
1816 | return -EINVAL; | ||
1817 | } | ||
1818 | } else if(acl_type & ACL_TYPE_DEFAULT) { | ||
1819 | count = le16_to_cpu(cifs_acl->access_entry_count); | ||
1820 | size = sizeof(struct cifs_posix_acl); | ||
1821 | size += sizeof(struct cifs_posix_ace) * count; | ||
1822 | /* skip past access ACEs to get to default ACEs */ | ||
1823 | pACE = &cifs_acl->ace_array[count]; | ||
1824 | count = le16_to_cpu(cifs_acl->default_entry_count); | ||
1825 | size += sizeof(struct cifs_posix_ace) * count; | ||
1826 | /* check if we would go beyond end of SMB */ | ||
1827 | if(size_of_data_area < size) | ||
1828 | return -EINVAL; | ||
1829 | } else { | ||
1830 | /* illegal type */ | ||
1831 | return -EINVAL; | ||
1832 | } | ||
1833 | |||
1834 | size = posix_acl_xattr_size(count); | ||
1835 | if((buflen == 0) || (local_acl == NULL)) { | ||
1836 | /* used to query ACL EA size */ | ||
1837 | } else if(size > buflen) { | ||
1838 | return -ERANGE; | ||
1839 | } else /* buffer big enough */ { | ||
1840 | local_acl->a_version = POSIX_ACL_XATTR_VERSION; | ||
1841 | for(i = 0;i < count ;i++) { | ||
1842 | cifs_convert_ace(&local_acl->a_entries[i],pACE); | ||
1843 | pACE ++; | ||
1844 | } | ||
1845 | } | ||
1846 | return size; | ||
1847 | } | ||
1848 | |||
1849 | static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace, | ||
1850 | const posix_acl_xattr_entry * local_ace) | ||
1851 | { | ||
1852 | __u16 rc = 0; /* 0 = ACL converted ok */ | ||
1853 | |||
1854 | cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm); | ||
1855 | cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag); | ||
1856 | /* BB is there a better way to handle the large uid? */ | ||
1857 | if(local_ace->e_id == -1) { | ||
1858 | /* Probably no need to le convert -1 on any arch but can not hurt */ | ||
1859 | cifs_ace->cifs_uid = cpu_to_le64(-1); | ||
1860 | } else | ||
1861 | cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id); | ||
1862 | /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/ | ||
1863 | return rc; | ||
1864 | } | ||
1865 | |||
1866 | /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */ | ||
1867 | static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen, | ||
1868 | const int acl_type) | ||
1869 | { | ||
1870 | __u16 rc = 0; | ||
1871 | struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data; | ||
1872 | posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL; | ||
1873 | int count; | ||
1874 | int i; | ||
1875 | |||
1876 | if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL)) | ||
1877 | return 0; | ||
1878 | |||
1879 | count = posix_acl_xattr_count((size_t)buflen); | ||
1880 | cFYI(1,("setting acl with %d entries from buf of length %d and version of %d", | ||
1881 | count,buflen,local_acl->a_version)); | ||
1882 | if(local_acl->a_version != 2) { | ||
1883 | cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version)); | ||
1884 | return 0; | ||
1885 | } | ||
1886 | cifs_acl->version = cpu_to_le16(1); | ||
1887 | if(acl_type == ACL_TYPE_ACCESS) | ||
1888 | cifs_acl->access_entry_count = count; | ||
1889 | else if(acl_type == ACL_TYPE_DEFAULT) | ||
1890 | cifs_acl->default_entry_count = count; | ||
1891 | else { | ||
1892 | cFYI(1,("unknown ACL type %d",acl_type)); | ||
1893 | return 0; | ||
1894 | } | ||
1895 | for(i=0;i<count;i++) { | ||
1896 | rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], | ||
1897 | &local_acl->a_entries[i]); | ||
1898 | if(rc != 0) { | ||
1899 | /* ACE not converted */ | ||
1900 | break; | ||
1901 | } | ||
1902 | } | ||
1903 | if(rc == 0) { | ||
1904 | rc = (__u16)(count * sizeof(struct cifs_posix_ace)); | ||
1905 | rc += sizeof(struct cifs_posix_acl); | ||
1906 | /* BB add check to make sure ACL does not overflow SMB */ | ||
1907 | } | ||
1908 | return rc; | ||
1909 | } | ||
1910 | |||
1911 | int | ||
1912 | CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, | ||
1913 | const unsigned char *searchName, | ||
1914 | char *acl_inf, const int buflen, const int acl_type, | ||
1915 | const struct nls_table *nls_codepage) | ||
1916 | { | ||
1917 | /* SMB_QUERY_POSIX_ACL */ | ||
1918 | TRANSACTION2_QPI_REQ *pSMB = NULL; | ||
1919 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | ||
1920 | int rc = 0; | ||
1921 | int bytes_returned; | ||
1922 | int name_len; | ||
1923 | __u16 params, byte_count; | ||
1924 | |||
1925 | cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName)); | ||
1926 | |||
1927 | queryAclRetry: | ||
1928 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
1929 | (void **) &pSMBr); | ||
1930 | if (rc) | ||
1931 | return rc; | ||
1932 | |||
1933 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
1934 | name_len = | ||
1935 | cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX | ||
1936 | , nls_codepage); | ||
1937 | name_len++; /* trailing null */ | ||
1938 | name_len *= 2; | ||
1939 | pSMB->FileName[name_len] = 0; | ||
1940 | pSMB->FileName[name_len+1] = 0; | ||
1941 | } else { /* BB improve the check for buffer overruns BB */ | ||
1942 | name_len = strnlen(searchName, PATH_MAX); | ||
1943 | name_len++; /* trailing null */ | ||
1944 | strncpy(pSMB->FileName, searchName, name_len); | ||
1945 | } | ||
1946 | |||
1947 | params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; | ||
1948 | pSMB->TotalDataCount = 0; | ||
1949 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
1950 | /* BB find exact max data count below from sess structure BB */ | ||
1951 | pSMB->MaxDataCount = cpu_to_le16(4000); | ||
1952 | pSMB->MaxSetupCount = 0; | ||
1953 | pSMB->Reserved = 0; | ||
1954 | pSMB->Flags = 0; | ||
1955 | pSMB->Timeout = 0; | ||
1956 | pSMB->Reserved2 = 0; | ||
1957 | pSMB->ParameterOffset = cpu_to_le16( | ||
1958 | offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); | ||
1959 | pSMB->DataCount = 0; | ||
1960 | pSMB->DataOffset = 0; | ||
1961 | pSMB->SetupCount = 1; | ||
1962 | pSMB->Reserved3 = 0; | ||
1963 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | ||
1964 | byte_count = params + 1 /* pad */ ; | ||
1965 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
1966 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
1967 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL); | ||
1968 | pSMB->Reserved4 = 0; | ||
1969 | pSMB->hdr.smb_buf_length += byte_count; | ||
1970 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
1971 | |||
1972 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
1973 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
1974 | if (rc) { | ||
1975 | cFYI(1, ("Send error in Query POSIX ACL = %d", rc)); | ||
1976 | } else { | ||
1977 | /* decode response */ | ||
1978 | |||
1979 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
1980 | if (rc || (pSMBr->ByteCount < 2)) | ||
1981 | /* BB also check enough total bytes returned */ | ||
1982 | rc = -EIO; /* bad smb */ | ||
1983 | else { | ||
1984 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
1985 | __u16 count = le16_to_cpu(pSMBr->t2.DataCount); | ||
1986 | rc = cifs_copy_posix_acl(acl_inf, | ||
1987 | (char *)&pSMBr->hdr.Protocol+data_offset, | ||
1988 | buflen,acl_type,count); | ||
1989 | } | ||
1990 | } | ||
1991 | cifs_buf_release(pSMB); | ||
1992 | if (rc == -EAGAIN) | ||
1993 | goto queryAclRetry; | ||
1994 | return rc; | ||
1995 | } | ||
1996 | |||
1997 | int | ||
1998 | CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, | ||
1999 | const unsigned char *fileName, | ||
2000 | const char *local_acl, const int buflen, const int acl_type, | ||
2001 | const struct nls_table *nls_codepage) | ||
2002 | { | ||
2003 | struct smb_com_transaction2_spi_req *pSMB = NULL; | ||
2004 | struct smb_com_transaction2_spi_rsp *pSMBr = NULL; | ||
2005 | char *parm_data; | ||
2006 | int name_len; | ||
2007 | int rc = 0; | ||
2008 | int bytes_returned = 0; | ||
2009 | __u16 params, byte_count, data_count, param_offset, offset; | ||
2010 | |||
2011 | cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName)); | ||
2012 | setAclRetry: | ||
2013 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
2014 | (void **) &pSMBr); | ||
2015 | if (rc) | ||
2016 | return rc; | ||
2017 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2018 | name_len = | ||
2019 | cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX | ||
2020 | , nls_codepage); | ||
2021 | name_len++; /* trailing null */ | ||
2022 | name_len *= 2; | ||
2023 | } else { /* BB improve the check for buffer overruns BB */ | ||
2024 | name_len = strnlen(fileName, PATH_MAX); | ||
2025 | name_len++; /* trailing null */ | ||
2026 | strncpy(pSMB->FileName, fileName, name_len); | ||
2027 | } | ||
2028 | params = 6 + name_len; | ||
2029 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
2030 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ | ||
2031 | pSMB->MaxSetupCount = 0; | ||
2032 | pSMB->Reserved = 0; | ||
2033 | pSMB->Flags = 0; | ||
2034 | pSMB->Timeout = 0; | ||
2035 | pSMB->Reserved2 = 0; | ||
2036 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | ||
2037 | InformationLevel) - 4; | ||
2038 | offset = param_offset + params; | ||
2039 | parm_data = ((char *) &pSMB->hdr.Protocol) + offset; | ||
2040 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
2041 | |||
2042 | /* convert to on the wire format for POSIX ACL */ | ||
2043 | data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type); | ||
2044 | |||
2045 | if(data_count == 0) { | ||
2046 | rc = -EOPNOTSUPP; | ||
2047 | goto setACLerrorExit; | ||
2048 | } | ||
2049 | pSMB->DataOffset = cpu_to_le16(offset); | ||
2050 | pSMB->SetupCount = 1; | ||
2051 | pSMB->Reserved3 = 0; | ||
2052 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | ||
2053 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL); | ||
2054 | byte_count = 3 /* pad */ + params + data_count; | ||
2055 | pSMB->DataCount = cpu_to_le16(data_count); | ||
2056 | pSMB->TotalDataCount = pSMB->DataCount; | ||
2057 | pSMB->ParameterCount = cpu_to_le16(params); | ||
2058 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
2059 | pSMB->Reserved4 = 0; | ||
2060 | pSMB->hdr.smb_buf_length += byte_count; | ||
2061 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
2062 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2063 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2064 | if (rc) { | ||
2065 | cFYI(1, ("Set POSIX ACL returned %d", rc)); | ||
2066 | } | ||
2067 | |||
2068 | setACLerrorExit: | ||
2069 | cifs_buf_release(pSMB); | ||
2070 | if (rc == -EAGAIN) | ||
2071 | goto setAclRetry; | ||
2072 | return rc; | ||
2073 | } | ||
2074 | |||
2075 | #endif | ||
2076 | |||
2077 | int | ||
2078 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | ||
2079 | const unsigned char *searchName, | ||
2080 | FILE_ALL_INFO * pFindData, | ||
2081 | const struct nls_table *nls_codepage) | ||
2082 | { | ||
2083 | /* level 263 SMB_QUERY_FILE_ALL_INFO */ | ||
2084 | TRANSACTION2_QPI_REQ *pSMB = NULL; | ||
2085 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | ||
2086 | int rc = 0; | ||
2087 | int bytes_returned; | ||
2088 | int name_len; | ||
2089 | __u16 params, byte_count; | ||
2090 | |||
2091 | /* cFYI(1, ("In QPathInfo path %s", searchName)); */ | ||
2092 | QPathInfoRetry: | ||
2093 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
2094 | (void **) &pSMBr); | ||
2095 | if (rc) | ||
2096 | return rc; | ||
2097 | |||
2098 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2099 | name_len = | ||
2100 | cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX | ||
2101 | /* find define for this maxpathcomponent */ | ||
2102 | , nls_codepage); | ||
2103 | name_len++; /* trailing null */ | ||
2104 | name_len *= 2; | ||
2105 | } else { /* BB improve the check for buffer overruns BB */ | ||
2106 | name_len = strnlen(searchName, PATH_MAX); | ||
2107 | name_len++; /* trailing null */ | ||
2108 | strncpy(pSMB->FileName, searchName, name_len); | ||
2109 | } | ||
2110 | |||
2111 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ; | ||
2112 | pSMB->TotalDataCount = 0; | ||
2113 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
2114 | pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ | ||
2115 | pSMB->MaxSetupCount = 0; | ||
2116 | pSMB->Reserved = 0; | ||
2117 | pSMB->Flags = 0; | ||
2118 | pSMB->Timeout = 0; | ||
2119 | pSMB->Reserved2 = 0; | ||
2120 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
2121 | struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); | ||
2122 | pSMB->DataCount = 0; | ||
2123 | pSMB->DataOffset = 0; | ||
2124 | pSMB->SetupCount = 1; | ||
2125 | pSMB->Reserved3 = 0; | ||
2126 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | ||
2127 | byte_count = params + 1 /* pad */ ; | ||
2128 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
2129 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
2130 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); | ||
2131 | pSMB->Reserved4 = 0; | ||
2132 | pSMB->hdr.smb_buf_length += byte_count; | ||
2133 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
2134 | |||
2135 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2136 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2137 | if (rc) { | ||
2138 | cFYI(1, ("Send error in QPathInfo = %d", rc)); | ||
2139 | } else { /* decode response */ | ||
2140 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
2141 | |||
2142 | if (rc || (pSMBr->ByteCount < 40)) | ||
2143 | rc = -EIO; /* bad smb */ | ||
2144 | else if (pFindData){ | ||
2145 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
2146 | memcpy((char *) pFindData, | ||
2147 | (char *) &pSMBr->hdr.Protocol + | ||
2148 | data_offset, sizeof (FILE_ALL_INFO)); | ||
2149 | } else | ||
2150 | rc = -ENOMEM; | ||
2151 | } | ||
2152 | cifs_buf_release(pSMB); | ||
2153 | if (rc == -EAGAIN) | ||
2154 | goto QPathInfoRetry; | ||
2155 | |||
2156 | return rc; | ||
2157 | } | ||
2158 | |||
2159 | int | ||
2160 | CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, | ||
2161 | const unsigned char *searchName, | ||
2162 | FILE_UNIX_BASIC_INFO * pFindData, | ||
2163 | const struct nls_table *nls_codepage) | ||
2164 | { | ||
2165 | /* SMB_QUERY_FILE_UNIX_BASIC */ | ||
2166 | TRANSACTION2_QPI_REQ *pSMB = NULL; | ||
2167 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | ||
2168 | int rc = 0; | ||
2169 | int bytes_returned = 0; | ||
2170 | int name_len; | ||
2171 | __u16 params, byte_count; | ||
2172 | |||
2173 | cFYI(1, ("In QPathInfo (Unix) the path %s", searchName)); | ||
2174 | UnixQPathInfoRetry: | ||
2175 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
2176 | (void **) &pSMBr); | ||
2177 | if (rc) | ||
2178 | return rc; | ||
2179 | |||
2180 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2181 | name_len = | ||
2182 | cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX | ||
2183 | /* find define for this maxpathcomponent */ | ||
2184 | , nls_codepage); | ||
2185 | name_len++; /* trailing null */ | ||
2186 | name_len *= 2; | ||
2187 | } else { /* BB improve the check for buffer overruns BB */ | ||
2188 | name_len = strnlen(searchName, PATH_MAX); | ||
2189 | name_len++; /* trailing null */ | ||
2190 | strncpy(pSMB->FileName, searchName, name_len); | ||
2191 | } | ||
2192 | |||
2193 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ; | ||
2194 | pSMB->TotalDataCount = 0; | ||
2195 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
2196 | /* BB find exact max SMB PDU from sess structure BB */ | ||
2197 | pSMB->MaxDataCount = cpu_to_le16(4000); | ||
2198 | pSMB->MaxSetupCount = 0; | ||
2199 | pSMB->Reserved = 0; | ||
2200 | pSMB->Flags = 0; | ||
2201 | pSMB->Timeout = 0; | ||
2202 | pSMB->Reserved2 = 0; | ||
2203 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
2204 | struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); | ||
2205 | pSMB->DataCount = 0; | ||
2206 | pSMB->DataOffset = 0; | ||
2207 | pSMB->SetupCount = 1; | ||
2208 | pSMB->Reserved3 = 0; | ||
2209 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | ||
2210 | byte_count = params + 1 /* pad */ ; | ||
2211 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
2212 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
2213 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); | ||
2214 | pSMB->Reserved4 = 0; | ||
2215 | pSMB->hdr.smb_buf_length += byte_count; | ||
2216 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
2217 | |||
2218 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2219 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2220 | if (rc) { | ||
2221 | cFYI(1, ("Send error in QPathInfo = %d", rc)); | ||
2222 | } else { /* decode response */ | ||
2223 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
2224 | |||
2225 | if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { | ||
2226 | rc = -EIO; /* bad smb */ | ||
2227 | } else { | ||
2228 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
2229 | memcpy((char *) pFindData, | ||
2230 | (char *) &pSMBr->hdr.Protocol + | ||
2231 | data_offset, | ||
2232 | sizeof (FILE_UNIX_BASIC_INFO)); | ||
2233 | } | ||
2234 | } | ||
2235 | cifs_buf_release(pSMB); | ||
2236 | if (rc == -EAGAIN) | ||
2237 | goto UnixQPathInfoRetry; | ||
2238 | |||
2239 | return rc; | ||
2240 | } | ||
2241 | |||
2242 | #if 0 /* function unused at present */ | ||
2243 | int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon, | ||
2244 | const char *searchName, FILE_ALL_INFO * findData, | ||
2245 | const struct nls_table *nls_codepage) | ||
2246 | { | ||
2247 | /* level 257 SMB_ */ | ||
2248 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; | ||
2249 | TRANSACTION2_FFIRST_RSP *pSMBr = NULL; | ||
2250 | int rc = 0; | ||
2251 | int bytes_returned; | ||
2252 | int name_len; | ||
2253 | __u16 params, byte_count; | ||
2254 | |||
2255 | cFYI(1, ("In FindUnique")); | ||
2256 | findUniqueRetry: | ||
2257 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
2258 | (void **) &pSMBr); | ||
2259 | if (rc) | ||
2260 | return rc; | ||
2261 | |||
2262 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2263 | name_len = | ||
2264 | cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX | ||
2265 | /* find define for this maxpathcomponent */ | ||
2266 | , nls_codepage); | ||
2267 | name_len++; /* trailing null */ | ||
2268 | name_len *= 2; | ||
2269 | } else { /* BB improve the check for buffer overruns BB */ | ||
2270 | name_len = strnlen(searchName, PATH_MAX); | ||
2271 | name_len++; /* trailing null */ | ||
2272 | strncpy(pSMB->FileName, searchName, name_len); | ||
2273 | } | ||
2274 | |||
2275 | params = 12 + name_len /* includes null */ ; | ||
2276 | pSMB->TotalDataCount = 0; /* no EAs */ | ||
2277 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
2278 | pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ | ||
2279 | pSMB->MaxSetupCount = 0; | ||
2280 | pSMB->Reserved = 0; | ||
2281 | pSMB->Flags = 0; | ||
2282 | pSMB->Timeout = 0; | ||
2283 | pSMB->Reserved2 = 0; | ||
2284 | pSMB->ParameterOffset = cpu_to_le16( | ||
2285 | offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4); | ||
2286 | pSMB->DataCount = 0; | ||
2287 | pSMB->DataOffset = 0; | ||
2288 | pSMB->SetupCount = 1; /* one byte, no need to le convert */ | ||
2289 | pSMB->Reserved3 = 0; | ||
2290 | pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); | ||
2291 | byte_count = params + 1 /* pad */ ; | ||
2292 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
2293 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
2294 | pSMB->SearchAttributes = | ||
2295 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | | ||
2296 | ATTR_DIRECTORY); | ||
2297 | pSMB->SearchCount = cpu_to_le16(16); /* BB increase */ | ||
2298 | pSMB->SearchFlags = cpu_to_le16(1); | ||
2299 | pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); | ||
2300 | pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */ | ||
2301 | pSMB->hdr.smb_buf_length += byte_count; | ||
2302 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
2303 | |||
2304 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2305 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2306 | |||
2307 | if (rc) { | ||
2308 | cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); | ||
2309 | } else { /* decode response */ | ||
2310 | |||
2311 | /* BB fill in */ | ||
2312 | } | ||
2313 | |||
2314 | cifs_buf_release(pSMB); | ||
2315 | if (rc == -EAGAIN) | ||
2316 | goto findUniqueRetry; | ||
2317 | |||
2318 | return rc; | ||
2319 | } | ||
2320 | #endif /* end unused (temporarily) function */ | ||
2321 | |||
2322 | /* xid, tcon, searchName and codepage are input parms, rest are returned */ | ||
2323 | int | ||
2324 | CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | ||
2325 | const char *searchName, | ||
2326 | const struct nls_table *nls_codepage, | ||
2327 | __u16 * pnetfid, | ||
2328 | struct cifs_search_info * psrch_inf) | ||
2329 | { | ||
2330 | /* level 257 SMB_ */ | ||
2331 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; | ||
2332 | TRANSACTION2_FFIRST_RSP *pSMBr = NULL; | ||
2333 | T2_FFIRST_RSP_PARMS * parms; | ||
2334 | int rc = 0; | ||
2335 | int bytes_returned = 0; | ||
2336 | int name_len; | ||
2337 | __u16 params, byte_count; | ||
2338 | |||
2339 | cFYI(1, ("In FindFirst")); | ||
2340 | |||
2341 | findFirstRetry: | ||
2342 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
2343 | (void **) &pSMBr); | ||
2344 | if (rc) | ||
2345 | return rc; | ||
2346 | |||
2347 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2348 | name_len = | ||
2349 | cifs_strtoUCS((wchar_t *) pSMB->FileName,searchName, | ||
2350 | PATH_MAX, nls_codepage); | ||
2351 | name_len++; /* trailing null */ | ||
2352 | name_len *= 2; | ||
2353 | pSMB->FileName[name_len] = 0; /* null terminate just in case */ | ||
2354 | pSMB->FileName[name_len+1] = 0; | ||
2355 | } else { /* BB add check for overrun of SMB buf BB */ | ||
2356 | name_len = strnlen(searchName, PATH_MAX); | ||
2357 | name_len++; /* trailing null */ | ||
2358 | /* BB fix here and in unicode clause above ie | ||
2359 | if(name_len > buffersize-header) | ||
2360 | free buffer exit; BB */ | ||
2361 | strncpy(pSMB->FileName, searchName, name_len); | ||
2362 | pSMB->FileName[name_len] = 0; /* just in case */ | ||
2363 | } | ||
2364 | |||
2365 | params = 12 + name_len /* includes null */ ; | ||
2366 | pSMB->TotalDataCount = 0; /* no EAs */ | ||
2367 | pSMB->MaxParameterCount = cpu_to_le16(10); | ||
2368 | pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf - | ||
2369 | MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); | ||
2370 | pSMB->MaxSetupCount = 0; | ||
2371 | pSMB->Reserved = 0; | ||
2372 | pSMB->Flags = 0; | ||
2373 | pSMB->Timeout = 0; | ||
2374 | pSMB->Reserved2 = 0; | ||
2375 | byte_count = params + 1 /* pad */ ; | ||
2376 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
2377 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
2378 | pSMB->ParameterOffset = cpu_to_le16( | ||
2379 | offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4); | ||
2380 | pSMB->DataCount = 0; | ||
2381 | pSMB->DataOffset = 0; | ||
2382 | pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */ | ||
2383 | pSMB->Reserved3 = 0; | ||
2384 | pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); | ||
2385 | pSMB->SearchAttributes = | ||
2386 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | | ||
2387 | ATTR_DIRECTORY); | ||
2388 | pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO)); | ||
2389 | pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | | ||
2390 | CIFS_SEARCH_RETURN_RESUME); | ||
2391 | pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); | ||
2392 | |||
2393 | /* BB what should we set StorageType to? Does it matter? BB */ | ||
2394 | pSMB->SearchStorageType = 0; | ||
2395 | pSMB->hdr.smb_buf_length += byte_count; | ||
2396 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
2397 | |||
2398 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2399 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2400 | |||
2401 | if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ | ||
2402 | /* BB Add code to handle unsupported level rc */ | ||
2403 | cFYI(1, ("Error in FindFirst = %d", rc)); | ||
2404 | |||
2405 | if (pSMB) | ||
2406 | cifs_buf_release(pSMB); | ||
2407 | |||
2408 | /* BB eventually could optimize out free and realloc of buf */ | ||
2409 | /* for this case */ | ||
2410 | if (rc == -EAGAIN) | ||
2411 | goto findFirstRetry; | ||
2412 | } else { /* decode response */ | ||
2413 | /* BB remember to free buffer if error BB */ | ||
2414 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
2415 | if(rc == 0) { | ||
2416 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) | ||
2417 | psrch_inf->unicode = TRUE; | ||
2418 | else | ||
2419 | psrch_inf->unicode = FALSE; | ||
2420 | |||
2421 | psrch_inf->ntwrk_buf_start = (char *)pSMBr; | ||
2422 | psrch_inf->srch_entries_start = | ||
2423 | (char *) &pSMBr->hdr.Protocol + | ||
2424 | le16_to_cpu(pSMBr->t2.DataOffset); | ||
2425 | |||
2426 | parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol + | ||
2427 | le16_to_cpu(pSMBr->t2.ParameterOffset)); | ||
2428 | |||
2429 | if(parms->EndofSearch) | ||
2430 | psrch_inf->endOfSearch = TRUE; | ||
2431 | else | ||
2432 | psrch_inf->endOfSearch = FALSE; | ||
2433 | |||
2434 | psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); | ||
2435 | psrch_inf->index_of_last_entry = | ||
2436 | psrch_inf->entries_in_buffer; | ||
2437 | /*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */ | ||
2438 | *pnetfid = parms->SearchHandle; | ||
2439 | } else { | ||
2440 | cifs_buf_release(pSMB); | ||
2441 | } | ||
2442 | } | ||
2443 | |||
2444 | return rc; | ||
2445 | } | ||
2446 | |||
2447 | int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | ||
2448 | __u16 searchHandle, struct cifs_search_info * psrch_inf) | ||
2449 | { | ||
2450 | TRANSACTION2_FNEXT_REQ *pSMB = NULL; | ||
2451 | TRANSACTION2_FNEXT_RSP *pSMBr = NULL; | ||
2452 | T2_FNEXT_RSP_PARMS * parms; | ||
2453 | char *response_data; | ||
2454 | int rc = 0; | ||
2455 | int bytes_returned, name_len; | ||
2456 | __u16 params, byte_count; | ||
2457 | |||
2458 | cFYI(1, ("In FindNext")); | ||
2459 | |||
2460 | if(psrch_inf->endOfSearch == TRUE) | ||
2461 | return -ENOENT; | ||
2462 | |||
2463 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
2464 | (void **) &pSMBr); | ||
2465 | if (rc) | ||
2466 | return rc; | ||
2467 | |||
2468 | params = 14; /* includes 2 bytes of null string, converted to LE below */ | ||
2469 | byte_count = 0; | ||
2470 | pSMB->TotalDataCount = 0; /* no EAs */ | ||
2471 | pSMB->MaxParameterCount = cpu_to_le16(8); | ||
2472 | pSMB->MaxDataCount = | ||
2473 | cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); | ||
2474 | pSMB->MaxSetupCount = 0; | ||
2475 | pSMB->Reserved = 0; | ||
2476 | pSMB->Flags = 0; | ||
2477 | pSMB->Timeout = 0; | ||
2478 | pSMB->Reserved2 = 0; | ||
2479 | pSMB->ParameterOffset = cpu_to_le16( | ||
2480 | offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4); | ||
2481 | pSMB->DataCount = 0; | ||
2482 | pSMB->DataOffset = 0; | ||
2483 | pSMB->SetupCount = 1; | ||
2484 | pSMB->Reserved3 = 0; | ||
2485 | pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT); | ||
2486 | pSMB->SearchHandle = searchHandle; /* always kept as le */ | ||
2487 | pSMB->SearchCount = | ||
2488 | cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO)); | ||
2489 | /* test for Unix extensions */ | ||
2490 | /* if (tcon->ses->capabilities & CAP_UNIX) { | ||
2491 | pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX); | ||
2492 | psrch_inf->info_level = SMB_FIND_FILE_UNIX; | ||
2493 | } else { | ||
2494 | pSMB->InformationLevel = | ||
2495 | cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); | ||
2496 | psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO; | ||
2497 | } */ | ||
2498 | pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); | ||
2499 | pSMB->ResumeKey = psrch_inf->resume_key; | ||
2500 | pSMB->SearchFlags = | ||
2501 | cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); | ||
2502 | |||
2503 | name_len = psrch_inf->resume_name_len; | ||
2504 | params += name_len; | ||
2505 | if(name_len < PATH_MAX) { | ||
2506 | memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len); | ||
2507 | byte_count += name_len; | ||
2508 | } else { | ||
2509 | rc = -EINVAL; | ||
2510 | goto FNext2_err_exit; | ||
2511 | } | ||
2512 | byte_count = params + 1 /* pad */ ; | ||
2513 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
2514 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
2515 | pSMB->hdr.smb_buf_length += byte_count; | ||
2516 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
2517 | |||
2518 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2519 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2520 | |||
2521 | if (rc) { | ||
2522 | if (rc == -EBADF) { | ||
2523 | psrch_inf->endOfSearch = TRUE; | ||
2524 | rc = 0; /* search probably was closed at end of search above */ | ||
2525 | } else | ||
2526 | cFYI(1, ("FindNext returned = %d", rc)); | ||
2527 | } else { /* decode response */ | ||
2528 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
2529 | |||
2530 | if(rc == 0) { | ||
2531 | /* BB fixme add lock for file (srch_info) struct here */ | ||
2532 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) | ||
2533 | psrch_inf->unicode = TRUE; | ||
2534 | else | ||
2535 | psrch_inf->unicode = FALSE; | ||
2536 | response_data = (char *) &pSMBr->hdr.Protocol + | ||
2537 | le16_to_cpu(pSMBr->t2.ParameterOffset); | ||
2538 | parms = (T2_FNEXT_RSP_PARMS *)response_data; | ||
2539 | response_data = (char *)&pSMBr->hdr.Protocol + | ||
2540 | le16_to_cpu(pSMBr->t2.DataOffset); | ||
2541 | cifs_buf_release(psrch_inf->ntwrk_buf_start); | ||
2542 | psrch_inf->srch_entries_start = response_data; | ||
2543 | psrch_inf->ntwrk_buf_start = (char *)pSMB; | ||
2544 | if(parms->EndofSearch) | ||
2545 | psrch_inf->endOfSearch = TRUE; | ||
2546 | else | ||
2547 | psrch_inf->endOfSearch = FALSE; | ||
2548 | |||
2549 | psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); | ||
2550 | psrch_inf->index_of_last_entry += | ||
2551 | psrch_inf->entries_in_buffer; | ||
2552 | /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */ | ||
2553 | |||
2554 | /* BB fixme add unlock here */ | ||
2555 | } | ||
2556 | |||
2557 | } | ||
2558 | |||
2559 | /* BB On error, should we leave previous search buf (and count and | ||
2560 | last entry fields) intact or free the previous one? */ | ||
2561 | |||
2562 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
2563 | since file handle passed in no longer valid */ | ||
2564 | FNext2_err_exit: | ||
2565 | if (rc != 0) | ||
2566 | cifs_buf_release(pSMB); | ||
2567 | |||
2568 | return rc; | ||
2569 | } | ||
2570 | |||
2571 | int | ||
2572 | CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle) | ||
2573 | { | ||
2574 | int rc = 0; | ||
2575 | FINDCLOSE_REQ *pSMB = NULL; | ||
2576 | CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */ | ||
2577 | int bytes_returned; | ||
2578 | |||
2579 | cFYI(1, ("In CIFSSMBFindClose")); | ||
2580 | rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB); | ||
2581 | |||
2582 | /* no sense returning error if session restarted | ||
2583 | as file handle has been closed */ | ||
2584 | if(rc == -EAGAIN) | ||
2585 | return 0; | ||
2586 | if (rc) | ||
2587 | return rc; | ||
2588 | |||
2589 | pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ | ||
2590 | pSMB->FileID = searchHandle; | ||
2591 | pSMB->ByteCount = 0; | ||
2592 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2593 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2594 | if (rc) { | ||
2595 | cERROR(1, ("Send error in FindClose = %d", rc)); | ||
2596 | } | ||
2597 | cifs_small_buf_release(pSMB); | ||
2598 | |||
2599 | /* Since session is dead, search handle closed on server already */ | ||
2600 | if (rc == -EAGAIN) | ||
2601 | rc = 0; | ||
2602 | |||
2603 | return rc; | ||
2604 | } | ||
2605 | |||
2606 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
2607 | int | ||
2608 | CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | ||
2609 | const unsigned char *searchName, | ||
2610 | __u64 * inode_number, | ||
2611 | const struct nls_table *nls_codepage) | ||
2612 | { | ||
2613 | int rc = 0; | ||
2614 | TRANSACTION2_QPI_REQ *pSMB = NULL; | ||
2615 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | ||
2616 | int name_len, bytes_returned; | ||
2617 | __u16 params, byte_count; | ||
2618 | |||
2619 | cFYI(1,("In GetSrvInodeNum for %s",searchName)); | ||
2620 | if(tcon == NULL) | ||
2621 | return -ENODEV; | ||
2622 | |||
2623 | GetInodeNumberRetry: | ||
2624 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
2625 | (void **) &pSMBr); | ||
2626 | if (rc) | ||
2627 | return rc; | ||
2628 | |||
2629 | |||
2630 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2631 | name_len = | ||
2632 | cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, | ||
2633 | PATH_MAX,nls_codepage); | ||
2634 | name_len++; /* trailing null */ | ||
2635 | name_len *= 2; | ||
2636 | } else { /* BB improve the check for buffer overruns BB */ | ||
2637 | name_len = strnlen(searchName, PATH_MAX); | ||
2638 | name_len++; /* trailing null */ | ||
2639 | strncpy(pSMB->FileName, searchName, name_len); | ||
2640 | } | ||
2641 | |||
2642 | params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; | ||
2643 | pSMB->TotalDataCount = 0; | ||
2644 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
2645 | /* BB find exact max data count below from sess structure BB */ | ||
2646 | pSMB->MaxDataCount = cpu_to_le16(4000); | ||
2647 | pSMB->MaxSetupCount = 0; | ||
2648 | pSMB->Reserved = 0; | ||
2649 | pSMB->Flags = 0; | ||
2650 | pSMB->Timeout = 0; | ||
2651 | pSMB->Reserved2 = 0; | ||
2652 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
2653 | struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); | ||
2654 | pSMB->DataCount = 0; | ||
2655 | pSMB->DataOffset = 0; | ||
2656 | pSMB->SetupCount = 1; | ||
2657 | pSMB->Reserved3 = 0; | ||
2658 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | ||
2659 | byte_count = params + 1 /* pad */ ; | ||
2660 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
2661 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
2662 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO); | ||
2663 | pSMB->Reserved4 = 0; | ||
2664 | pSMB->hdr.smb_buf_length += byte_count; | ||
2665 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
2666 | |||
2667 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2668 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2669 | if (rc) { | ||
2670 | cFYI(1, ("error %d in QueryInternalInfo", rc)); | ||
2671 | } else { | ||
2672 | /* decode response */ | ||
2673 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
2674 | if (rc || (pSMBr->ByteCount < 2)) | ||
2675 | /* BB also check enough total bytes returned */ | ||
2676 | /* If rc should we check for EOPNOSUPP and | ||
2677 | disable the srvino flag? or in caller? */ | ||
2678 | rc = -EIO; /* bad smb */ | ||
2679 | else { | ||
2680 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
2681 | __u16 count = le16_to_cpu(pSMBr->t2.DataCount); | ||
2682 | struct file_internal_info * pfinfo; | ||
2683 | /* BB Do we need a cast or hash here ? */ | ||
2684 | if(count < 8) { | ||
2685 | cFYI(1, ("Illegal size ret in QryIntrnlInf")); | ||
2686 | rc = -EIO; | ||
2687 | goto GetInodeNumOut; | ||
2688 | } | ||
2689 | pfinfo = (struct file_internal_info *) | ||
2690 | (data_offset + (char *) &pSMBr->hdr.Protocol); | ||
2691 | *inode_number = pfinfo->UniqueId; | ||
2692 | } | ||
2693 | } | ||
2694 | GetInodeNumOut: | ||
2695 | cifs_buf_release(pSMB); | ||
2696 | if (rc == -EAGAIN) | ||
2697 | goto GetInodeNumberRetry; | ||
2698 | return rc; | ||
2699 | } | ||
2700 | #endif /* CIFS_EXPERIMENTAL */ | ||
2701 | |||
2702 | int | ||
2703 | CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, | ||
2704 | const unsigned char *searchName, | ||
2705 | unsigned char **targetUNCs, | ||
2706 | unsigned int *number_of_UNC_in_array, | ||
2707 | const struct nls_table *nls_codepage) | ||
2708 | { | ||
2709 | /* TRANS2_GET_DFS_REFERRAL */ | ||
2710 | TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; | ||
2711 | TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; | ||
2712 | struct dfs_referral_level_3 * referrals = NULL; | ||
2713 | int rc = 0; | ||
2714 | int bytes_returned; | ||
2715 | int name_len; | ||
2716 | unsigned int i; | ||
2717 | char * temp; | ||
2718 | __u16 params, byte_count; | ||
2719 | *number_of_UNC_in_array = 0; | ||
2720 | *targetUNCs = NULL; | ||
2721 | |||
2722 | cFYI(1, ("In GetDFSRefer the path %s", searchName)); | ||
2723 | if (ses == NULL) | ||
2724 | return -ENODEV; | ||
2725 | getDFSRetry: | ||
2726 | rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB, | ||
2727 | (void **) &pSMBr); | ||
2728 | if (rc) | ||
2729 | return rc; | ||
2730 | |||
2731 | pSMB->hdr.Tid = ses->ipc_tid; | ||
2732 | pSMB->hdr.Uid = ses->Suid; | ||
2733 | if (ses->capabilities & CAP_STATUS32) { | ||
2734 | pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS; | ||
2735 | } | ||
2736 | if (ses->capabilities & CAP_DFS) { | ||
2737 | pSMB->hdr.Flags2 |= SMBFLG2_DFS; | ||
2738 | } | ||
2739 | |||
2740 | if (ses->capabilities & CAP_UNICODE) { | ||
2741 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | ||
2742 | name_len = | ||
2743 | cifs_strtoUCS((wchar_t *) pSMB->RequestFileName, | ||
2744 | searchName, PATH_MAX | ||
2745 | /* find define for this maxpathcomponent */ | ||
2746 | , nls_codepage); | ||
2747 | name_len++; /* trailing null */ | ||
2748 | name_len *= 2; | ||
2749 | } else { /* BB improve the check for buffer overruns BB */ | ||
2750 | name_len = strnlen(searchName, PATH_MAX); | ||
2751 | name_len++; /* trailing null */ | ||
2752 | strncpy(pSMB->RequestFileName, searchName, name_len); | ||
2753 | } | ||
2754 | |||
2755 | params = 2 /* level */ + name_len /*includes null */ ; | ||
2756 | pSMB->TotalDataCount = 0; | ||
2757 | pSMB->DataCount = 0; | ||
2758 | pSMB->DataOffset = 0; | ||
2759 | pSMB->MaxParameterCount = 0; | ||
2760 | pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ | ||
2761 | pSMB->MaxSetupCount = 0; | ||
2762 | pSMB->Reserved = 0; | ||
2763 | pSMB->Flags = 0; | ||
2764 | pSMB->Timeout = 0; | ||
2765 | pSMB->Reserved2 = 0; | ||
2766 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
2767 | struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4); | ||
2768 | pSMB->SetupCount = 1; | ||
2769 | pSMB->Reserved3 = 0; | ||
2770 | pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL); | ||
2771 | byte_count = params + 3 /* pad */ ; | ||
2772 | pSMB->ParameterCount = cpu_to_le16(params); | ||
2773 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
2774 | pSMB->MaxReferralLevel = cpu_to_le16(3); | ||
2775 | pSMB->hdr.smb_buf_length += byte_count; | ||
2776 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
2777 | |||
2778 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | ||
2779 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2780 | if (rc) { | ||
2781 | cFYI(1, ("Send error in GetDFSRefer = %d", rc)); | ||
2782 | } else { /* decode response */ | ||
2783 | /* BB Add logic to parse referrals here */ | ||
2784 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
2785 | |||
2786 | if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */ | ||
2787 | rc = -EIO; /* bad smb */ | ||
2788 | else { | ||
2789 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
2790 | __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount); | ||
2791 | |||
2792 | cFYI(1, | ||
2793 | ("Decoding GetDFSRefer response. BCC: %d Offset %d", | ||
2794 | pSMBr->ByteCount, data_offset)); | ||
2795 | referrals = | ||
2796 | (struct dfs_referral_level_3 *) | ||
2797 | (8 /* sizeof start of data block */ + | ||
2798 | data_offset + | ||
2799 | (char *) &pSMBr->hdr.Protocol); | ||
2800 | cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x", | ||
2801 | le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive))); | ||
2802 | /* BB This field is actually two bytes in from start of | ||
2803 | data block so we could do safety check that DataBlock | ||
2804 | begins at address of pSMBr->NumberOfReferrals */ | ||
2805 | *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals); | ||
2806 | |||
2807 | /* BB Fix below so can return more than one referral */ | ||
2808 | if(*number_of_UNC_in_array > 1) | ||
2809 | *number_of_UNC_in_array = 1; | ||
2810 | |||
2811 | /* get the length of the strings describing refs */ | ||
2812 | name_len = 0; | ||
2813 | for(i=0;i<*number_of_UNC_in_array;i++) { | ||
2814 | /* make sure that DfsPathOffset not past end */ | ||
2815 | __u16 offset = le16_to_cpu(referrals->DfsPathOffset); | ||
2816 | if (offset > data_count) { | ||
2817 | /* if invalid referral, stop here and do | ||
2818 | not try to copy any more */ | ||
2819 | *number_of_UNC_in_array = i; | ||
2820 | break; | ||
2821 | } | ||
2822 | temp = ((char *)referrals) + offset; | ||
2823 | |||
2824 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2825 | name_len += UniStrnlen((wchar_t *)temp,data_count); | ||
2826 | } else { | ||
2827 | name_len += strnlen(temp,data_count); | ||
2828 | } | ||
2829 | referrals++; | ||
2830 | /* BB add check that referral pointer does not fall off end PDU */ | ||
2831 | |||
2832 | } | ||
2833 | /* BB add check for name_len bigger than bcc */ | ||
2834 | *targetUNCs = | ||
2835 | kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL); | ||
2836 | if(*targetUNCs == NULL) { | ||
2837 | rc = -ENOMEM; | ||
2838 | goto GetDFSRefExit; | ||
2839 | } | ||
2840 | /* copy the ref strings */ | ||
2841 | referrals = | ||
2842 | (struct dfs_referral_level_3 *) | ||
2843 | (8 /* sizeof data hdr */ + | ||
2844 | data_offset + | ||
2845 | (char *) &pSMBr->hdr.Protocol); | ||
2846 | |||
2847 | for(i=0;i<*number_of_UNC_in_array;i++) { | ||
2848 | temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset); | ||
2849 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2850 | cifs_strfromUCS_le(*targetUNCs, | ||
2851 | (wchar_t *) temp, name_len, nls_codepage); | ||
2852 | } else { | ||
2853 | strncpy(*targetUNCs,temp,name_len); | ||
2854 | } | ||
2855 | /* BB update target_uncs pointers */ | ||
2856 | referrals++; | ||
2857 | } | ||
2858 | temp = *targetUNCs; | ||
2859 | temp[name_len] = 0; | ||
2860 | } | ||
2861 | |||
2862 | } | ||
2863 | GetDFSRefExit: | ||
2864 | if (pSMB) | ||
2865 | cifs_buf_release(pSMB); | ||
2866 | |||
2867 | if (rc == -EAGAIN) | ||
2868 | goto getDFSRetry; | ||
2869 | |||
2870 | return rc; | ||
2871 | } | ||
2872 | |||
2873 | int | ||
2874 | CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, | ||
2875 | struct kstatfs *FSData, const struct nls_table *nls_codepage) | ||
2876 | { | ||
2877 | /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ | ||
2878 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | ||
2879 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | ||
2880 | FILE_SYSTEM_INFO *response_data; | ||
2881 | int rc = 0; | ||
2882 | int bytes_returned = 0; | ||
2883 | __u16 params, byte_count; | ||
2884 | |||
2885 | cFYI(1, ("In QFSInfo")); | ||
2886 | QFSInfoRetry: | ||
2887 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
2888 | (void **) &pSMBr); | ||
2889 | if (rc) | ||
2890 | return rc; | ||
2891 | |||
2892 | params = 2; /* level */ | ||
2893 | pSMB->TotalDataCount = 0; | ||
2894 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
2895 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | ||
2896 | pSMB->MaxSetupCount = 0; | ||
2897 | pSMB->Reserved = 0; | ||
2898 | pSMB->Flags = 0; | ||
2899 | pSMB->Timeout = 0; | ||
2900 | pSMB->Reserved2 = 0; | ||
2901 | byte_count = params + 1 /* pad */ ; | ||
2902 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
2903 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
2904 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
2905 | struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); | ||
2906 | pSMB->DataCount = 0; | ||
2907 | pSMB->DataOffset = 0; | ||
2908 | pSMB->SetupCount = 1; | ||
2909 | pSMB->Reserved3 = 0; | ||
2910 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | ||
2911 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); | ||
2912 | pSMB->hdr.smb_buf_length += byte_count; | ||
2913 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
2914 | |||
2915 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2916 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2917 | if (rc) { | ||
2918 | cERROR(1, ("Send error in QFSInfo = %d", rc)); | ||
2919 | } else { /* decode response */ | ||
2920 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
2921 | |||
2922 | if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */ | ||
2923 | rc = -EIO; /* bad smb */ | ||
2924 | else { | ||
2925 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
2926 | cFYI(1, | ||
2927 | ("Decoding qfsinfo response. BCC: %d Offset %d", | ||
2928 | pSMBr->ByteCount, data_offset)); | ||
2929 | |||
2930 | response_data = | ||
2931 | (FILE_SYSTEM_INFO | ||
2932 | *) (((char *) &pSMBr->hdr.Protocol) + | ||
2933 | data_offset); | ||
2934 | FSData->f_bsize = | ||
2935 | le32_to_cpu(response_data->BytesPerSector) * | ||
2936 | le32_to_cpu(response_data-> | ||
2937 | SectorsPerAllocationUnit); | ||
2938 | FSData->f_blocks = | ||
2939 | le64_to_cpu(response_data->TotalAllocationUnits); | ||
2940 | FSData->f_bfree = FSData->f_bavail = | ||
2941 | le64_to_cpu(response_data->FreeAllocationUnits); | ||
2942 | cFYI(1, | ||
2943 | ("Blocks: %lld Free: %lld Block size %ld", | ||
2944 | (unsigned long long)FSData->f_blocks, | ||
2945 | (unsigned long long)FSData->f_bfree, | ||
2946 | FSData->f_bsize)); | ||
2947 | } | ||
2948 | } | ||
2949 | cifs_buf_release(pSMB); | ||
2950 | |||
2951 | if (rc == -EAGAIN) | ||
2952 | goto QFSInfoRetry; | ||
2953 | |||
2954 | return rc; | ||
2955 | } | ||
2956 | |||
2957 | int | ||
2958 | CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon, | ||
2959 | const struct nls_table *nls_codepage) | ||
2960 | { | ||
2961 | /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */ | ||
2962 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | ||
2963 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | ||
2964 | FILE_SYSTEM_ATTRIBUTE_INFO *response_data; | ||
2965 | int rc = 0; | ||
2966 | int bytes_returned = 0; | ||
2967 | __u16 params, byte_count; | ||
2968 | |||
2969 | cFYI(1, ("In QFSAttributeInfo")); | ||
2970 | QFSAttributeRetry: | ||
2971 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
2972 | (void **) &pSMBr); | ||
2973 | if (rc) | ||
2974 | return rc; | ||
2975 | |||
2976 | params = 2; /* level */ | ||
2977 | pSMB->TotalDataCount = 0; | ||
2978 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
2979 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | ||
2980 | pSMB->MaxSetupCount = 0; | ||
2981 | pSMB->Reserved = 0; | ||
2982 | pSMB->Flags = 0; | ||
2983 | pSMB->Timeout = 0; | ||
2984 | pSMB->Reserved2 = 0; | ||
2985 | byte_count = params + 1 /* pad */ ; | ||
2986 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
2987 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
2988 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
2989 | struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); | ||
2990 | pSMB->DataCount = 0; | ||
2991 | pSMB->DataOffset = 0; | ||
2992 | pSMB->SetupCount = 1; | ||
2993 | pSMB->Reserved3 = 0; | ||
2994 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | ||
2995 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); | ||
2996 | pSMB->hdr.smb_buf_length += byte_count; | ||
2997 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
2998 | |||
2999 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3000 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3001 | if (rc) { | ||
3002 | cERROR(1, ("Send error in QFSAttributeInfo = %d", rc)); | ||
3003 | } else { /* decode response */ | ||
3004 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3005 | |||
3006 | if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */ | ||
3007 | rc = -EIO; /* bad smb */ | ||
3008 | } else { | ||
3009 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
3010 | response_data = | ||
3011 | (FILE_SYSTEM_ATTRIBUTE_INFO | ||
3012 | *) (((char *) &pSMBr->hdr.Protocol) + | ||
3013 | data_offset); | ||
3014 | memcpy(&tcon->fsAttrInfo, response_data, | ||
3015 | sizeof (FILE_SYSTEM_ATTRIBUTE_INFO)); | ||
3016 | } | ||
3017 | } | ||
3018 | cifs_buf_release(pSMB); | ||
3019 | |||
3020 | if (rc == -EAGAIN) | ||
3021 | goto QFSAttributeRetry; | ||
3022 | |||
3023 | return rc; | ||
3024 | } | ||
3025 | |||
3026 | int | ||
3027 | CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon, | ||
3028 | const struct nls_table *nls_codepage) | ||
3029 | { | ||
3030 | /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ | ||
3031 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | ||
3032 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | ||
3033 | FILE_SYSTEM_DEVICE_INFO *response_data; | ||
3034 | int rc = 0; | ||
3035 | int bytes_returned = 0; | ||
3036 | __u16 params, byte_count; | ||
3037 | |||
3038 | cFYI(1, ("In QFSDeviceInfo")); | ||
3039 | QFSDeviceRetry: | ||
3040 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3041 | (void **) &pSMBr); | ||
3042 | if (rc) | ||
3043 | return rc; | ||
3044 | |||
3045 | params = 2; /* level */ | ||
3046 | pSMB->TotalDataCount = 0; | ||
3047 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3048 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | ||
3049 | pSMB->MaxSetupCount = 0; | ||
3050 | pSMB->Reserved = 0; | ||
3051 | pSMB->Flags = 0; | ||
3052 | pSMB->Timeout = 0; | ||
3053 | pSMB->Reserved2 = 0; | ||
3054 | byte_count = params + 1 /* pad */ ; | ||
3055 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
3056 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
3057 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
3058 | struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); | ||
3059 | |||
3060 | pSMB->DataCount = 0; | ||
3061 | pSMB->DataOffset = 0; | ||
3062 | pSMB->SetupCount = 1; | ||
3063 | pSMB->Reserved3 = 0; | ||
3064 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | ||
3065 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); | ||
3066 | pSMB->hdr.smb_buf_length += byte_count; | ||
3067 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3068 | |||
3069 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3070 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3071 | if (rc) { | ||
3072 | cFYI(1, ("Send error in QFSDeviceInfo = %d", rc)); | ||
3073 | } else { /* decode response */ | ||
3074 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3075 | |||
3076 | if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO))) | ||
3077 | rc = -EIO; /* bad smb */ | ||
3078 | else { | ||
3079 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
3080 | response_data = | ||
3081 | (FILE_SYSTEM_DEVICE_INFO | ||
3082 | *) (((char *) &pSMBr->hdr.Protocol) + | ||
3083 | data_offset); | ||
3084 | memcpy(&tcon->fsDevInfo, response_data, | ||
3085 | sizeof (FILE_SYSTEM_DEVICE_INFO)); | ||
3086 | } | ||
3087 | } | ||
3088 | cifs_buf_release(pSMB); | ||
3089 | |||
3090 | if (rc == -EAGAIN) | ||
3091 | goto QFSDeviceRetry; | ||
3092 | |||
3093 | return rc; | ||
3094 | } | ||
3095 | |||
3096 | int | ||
3097 | CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon, | ||
3098 | const struct nls_table *nls_codepage) | ||
3099 | { | ||
3100 | /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */ | ||
3101 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | ||
3102 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | ||
3103 | FILE_SYSTEM_UNIX_INFO *response_data; | ||
3104 | int rc = 0; | ||
3105 | int bytes_returned = 0; | ||
3106 | __u16 params, byte_count; | ||
3107 | |||
3108 | cFYI(1, ("In QFSUnixInfo")); | ||
3109 | QFSUnixRetry: | ||
3110 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3111 | (void **) &pSMBr); | ||
3112 | if (rc) | ||
3113 | return rc; | ||
3114 | |||
3115 | params = 2; /* level */ | ||
3116 | pSMB->TotalDataCount = 0; | ||
3117 | pSMB->DataCount = 0; | ||
3118 | pSMB->DataOffset = 0; | ||
3119 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3120 | pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ | ||
3121 | pSMB->MaxSetupCount = 0; | ||
3122 | pSMB->Reserved = 0; | ||
3123 | pSMB->Flags = 0; | ||
3124 | pSMB->Timeout = 0; | ||
3125 | pSMB->Reserved2 = 0; | ||
3126 | byte_count = params + 1 /* pad */ ; | ||
3127 | pSMB->ParameterCount = cpu_to_le16(params); | ||
3128 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
3129 | pSMB->ParameterOffset = cpu_to_le16(offsetof(struct | ||
3130 | smb_com_transaction2_qfsi_req, InformationLevel) - 4); | ||
3131 | pSMB->SetupCount = 1; | ||
3132 | pSMB->Reserved3 = 0; | ||
3133 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | ||
3134 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); | ||
3135 | pSMB->hdr.smb_buf_length += byte_count; | ||
3136 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3137 | |||
3138 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3139 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3140 | if (rc) { | ||
3141 | cERROR(1, ("Send error in QFSUnixInfo = %d", rc)); | ||
3142 | } else { /* decode response */ | ||
3143 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3144 | |||
3145 | if (rc || (pSMBr->ByteCount < 13)) { | ||
3146 | rc = -EIO; /* bad smb */ | ||
3147 | } else { | ||
3148 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
3149 | response_data = | ||
3150 | (FILE_SYSTEM_UNIX_INFO | ||
3151 | *) (((char *) &pSMBr->hdr.Protocol) + | ||
3152 | data_offset); | ||
3153 | memcpy(&tcon->fsUnixInfo, response_data, | ||
3154 | sizeof (FILE_SYSTEM_UNIX_INFO)); | ||
3155 | } | ||
3156 | } | ||
3157 | cifs_buf_release(pSMB); | ||
3158 | |||
3159 | if (rc == -EAGAIN) | ||
3160 | goto QFSUnixRetry; | ||
3161 | |||
3162 | |||
3163 | return rc; | ||
3164 | } | ||
3165 | |||
3166 | |||
3167 | int | ||
3168 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, | ||
3169 | struct kstatfs *FSData, const struct nls_table *nls_codepage) | ||
3170 | { | ||
3171 | /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */ | ||
3172 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | ||
3173 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | ||
3174 | FILE_SYSTEM_POSIX_INFO *response_data; | ||
3175 | int rc = 0; | ||
3176 | int bytes_returned = 0; | ||
3177 | __u16 params, byte_count; | ||
3178 | |||
3179 | cFYI(1, ("In QFSPosixInfo")); | ||
3180 | QFSPosixRetry: | ||
3181 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3182 | (void **) &pSMBr); | ||
3183 | if (rc) | ||
3184 | return rc; | ||
3185 | |||
3186 | params = 2; /* level */ | ||
3187 | pSMB->TotalDataCount = 0; | ||
3188 | pSMB->DataCount = 0; | ||
3189 | pSMB->DataOffset = 0; | ||
3190 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3191 | pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ | ||
3192 | pSMB->MaxSetupCount = 0; | ||
3193 | pSMB->Reserved = 0; | ||
3194 | pSMB->Flags = 0; | ||
3195 | pSMB->Timeout = 0; | ||
3196 | pSMB->Reserved2 = 0; | ||
3197 | byte_count = params + 1 /* pad */ ; | ||
3198 | pSMB->ParameterCount = cpu_to_le16(params); | ||
3199 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
3200 | pSMB->ParameterOffset = cpu_to_le16(offsetof(struct | ||
3201 | smb_com_transaction2_qfsi_req, InformationLevel) - 4); | ||
3202 | pSMB->SetupCount = 1; | ||
3203 | pSMB->Reserved3 = 0; | ||
3204 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | ||
3205 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO); | ||
3206 | pSMB->hdr.smb_buf_length += byte_count; | ||
3207 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3208 | |||
3209 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3210 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3211 | if (rc) { | ||
3212 | cFYI(1, ("Send error in QFSUnixInfo = %d", rc)); | ||
3213 | } else { /* decode response */ | ||
3214 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3215 | |||
3216 | if (rc || (pSMBr->ByteCount < 13)) { | ||
3217 | rc = -EIO; /* bad smb */ | ||
3218 | } else { | ||
3219 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
3220 | response_data = | ||
3221 | (FILE_SYSTEM_POSIX_INFO | ||
3222 | *) (((char *) &pSMBr->hdr.Protocol) + | ||
3223 | data_offset); | ||
3224 | FSData->f_bsize = | ||
3225 | le32_to_cpu(response_data->BlockSize); | ||
3226 | FSData->f_blocks = | ||
3227 | le64_to_cpu(response_data->TotalBlocks); | ||
3228 | FSData->f_bfree = | ||
3229 | le64_to_cpu(response_data->BlocksAvail); | ||
3230 | if(response_data->UserBlocksAvail == -1) { | ||
3231 | FSData->f_bavail = FSData->f_bfree; | ||
3232 | } else { | ||
3233 | FSData->f_bavail = | ||
3234 | le64_to_cpu(response_data->UserBlocksAvail); | ||
3235 | } | ||
3236 | if(response_data->TotalFileNodes != -1) | ||
3237 | FSData->f_files = | ||
3238 | le64_to_cpu(response_data->TotalFileNodes); | ||
3239 | if(response_data->FreeFileNodes != -1) | ||
3240 | FSData->f_ffree = | ||
3241 | le64_to_cpu(response_data->FreeFileNodes); | ||
3242 | } | ||
3243 | } | ||
3244 | cifs_buf_release(pSMB); | ||
3245 | |||
3246 | if (rc == -EAGAIN) | ||
3247 | goto QFSPosixRetry; | ||
3248 | |||
3249 | return rc; | ||
3250 | } | ||
3251 | |||
3252 | |||
3253 | /* We can not use write of zero bytes trick to | ||
3254 | set file size due to need for large file support. Also note that | ||
3255 | this SetPathInfo is preferred to SetFileInfo based method in next | ||
3256 | routine which is only needed to work around a sharing violation bug | ||
3257 | in Samba which this routine can run into */ | ||
3258 | |||
3259 | int | ||
3260 | CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName, | ||
3261 | __u64 size, int SetAllocation, const struct nls_table *nls_codepage) | ||
3262 | { | ||
3263 | struct smb_com_transaction2_spi_req *pSMB = NULL; | ||
3264 | struct smb_com_transaction2_spi_rsp *pSMBr = NULL; | ||
3265 | struct file_end_of_file_info *parm_data; | ||
3266 | int name_len; | ||
3267 | int rc = 0; | ||
3268 | int bytes_returned = 0; | ||
3269 | __u16 params, byte_count, data_count, param_offset, offset; | ||
3270 | |||
3271 | cFYI(1, ("In SetEOF")); | ||
3272 | SetEOFRetry: | ||
3273 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3274 | (void **) &pSMBr); | ||
3275 | if (rc) | ||
3276 | return rc; | ||
3277 | |||
3278 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
3279 | name_len = | ||
3280 | cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX | ||
3281 | /* find define for this maxpathcomponent */ | ||
3282 | , nls_codepage); | ||
3283 | name_len++; /* trailing null */ | ||
3284 | name_len *= 2; | ||
3285 | } else { /* BB improve the check for buffer overruns BB */ | ||
3286 | name_len = strnlen(fileName, PATH_MAX); | ||
3287 | name_len++; /* trailing null */ | ||
3288 | strncpy(pSMB->FileName, fileName, name_len); | ||
3289 | } | ||
3290 | params = 6 + name_len; | ||
3291 | data_count = sizeof (struct file_end_of_file_info); | ||
3292 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3293 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ | ||
3294 | pSMB->MaxSetupCount = 0; | ||
3295 | pSMB->Reserved = 0; | ||
3296 | pSMB->Flags = 0; | ||
3297 | pSMB->Timeout = 0; | ||
3298 | pSMB->Reserved2 = 0; | ||
3299 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | ||
3300 | InformationLevel) - 4; | ||
3301 | offset = param_offset + params; | ||
3302 | if(SetAllocation) { | ||
3303 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | ||
3304 | pSMB->InformationLevel = | ||
3305 | cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); | ||
3306 | else | ||
3307 | pSMB->InformationLevel = | ||
3308 | cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); | ||
3309 | } else /* Set File Size */ { | ||
3310 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | ||
3311 | pSMB->InformationLevel = | ||
3312 | cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); | ||
3313 | else | ||
3314 | pSMB->InformationLevel = | ||
3315 | cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); | ||
3316 | } | ||
3317 | |||
3318 | parm_data = | ||
3319 | (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + | ||
3320 | offset); | ||
3321 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
3322 | pSMB->DataOffset = cpu_to_le16(offset); | ||
3323 | pSMB->SetupCount = 1; | ||
3324 | pSMB->Reserved3 = 0; | ||
3325 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | ||
3326 | byte_count = 3 /* pad */ + params + data_count; | ||
3327 | pSMB->DataCount = cpu_to_le16(data_count); | ||
3328 | pSMB->TotalDataCount = pSMB->DataCount; | ||
3329 | pSMB->ParameterCount = cpu_to_le16(params); | ||
3330 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
3331 | pSMB->Reserved4 = 0; | ||
3332 | pSMB->hdr.smb_buf_length += byte_count; | ||
3333 | parm_data->FileSize = cpu_to_le64(size); | ||
3334 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3335 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3336 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3337 | if (rc) { | ||
3338 | cFYI(1, ("SetPathInfo (file size) returned %d", rc)); | ||
3339 | } | ||
3340 | |||
3341 | cifs_buf_release(pSMB); | ||
3342 | |||
3343 | if (rc == -EAGAIN) | ||
3344 | goto SetEOFRetry; | ||
3345 | |||
3346 | return rc; | ||
3347 | } | ||
3348 | |||
3349 | int | ||
3350 | CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | ||
3351 | __u16 fid, __u32 pid_of_opener, int SetAllocation) | ||
3352 | { | ||
3353 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | ||
3354 | struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; | ||
3355 | char *data_offset; | ||
3356 | struct file_end_of_file_info *parm_data; | ||
3357 | int rc = 0; | ||
3358 | int bytes_returned = 0; | ||
3359 | __u16 params, param_offset, offset, byte_count, count; | ||
3360 | |||
3361 | cFYI(1, ("SetFileSize (via SetFileInfo) %lld", | ||
3362 | (long long)size)); | ||
3363 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3364 | (void **) &pSMBr); | ||
3365 | if (rc) | ||
3366 | return rc; | ||
3367 | |||
3368 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); | ||
3369 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); | ||
3370 | |||
3371 | params = 6; | ||
3372 | pSMB->MaxSetupCount = 0; | ||
3373 | pSMB->Reserved = 0; | ||
3374 | pSMB->Flags = 0; | ||
3375 | pSMB->Timeout = 0; | ||
3376 | pSMB->Reserved2 = 0; | ||
3377 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | ||
3378 | offset = param_offset + params; | ||
3379 | |||
3380 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | ||
3381 | |||
3382 | count = sizeof(struct file_end_of_file_info); | ||
3383 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3384 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ | ||
3385 | pSMB->SetupCount = 1; | ||
3386 | pSMB->Reserved3 = 0; | ||
3387 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | ||
3388 | byte_count = 3 /* pad */ + params + count; | ||
3389 | pSMB->DataCount = cpu_to_le16(count); | ||
3390 | pSMB->ParameterCount = cpu_to_le16(params); | ||
3391 | pSMB->TotalDataCount = pSMB->DataCount; | ||
3392 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
3393 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
3394 | parm_data = | ||
3395 | (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + | ||
3396 | offset); | ||
3397 | pSMB->DataOffset = cpu_to_le16(offset); | ||
3398 | parm_data->FileSize = cpu_to_le64(size); | ||
3399 | pSMB->Fid = fid; | ||
3400 | if(SetAllocation) { | ||
3401 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | ||
3402 | pSMB->InformationLevel = | ||
3403 | cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); | ||
3404 | else | ||
3405 | pSMB->InformationLevel = | ||
3406 | cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); | ||
3407 | } else /* Set File Size */ { | ||
3408 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | ||
3409 | pSMB->InformationLevel = | ||
3410 | cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); | ||
3411 | else | ||
3412 | pSMB->InformationLevel = | ||
3413 | cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); | ||
3414 | } | ||
3415 | pSMB->Reserved4 = 0; | ||
3416 | pSMB->hdr.smb_buf_length += byte_count; | ||
3417 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3418 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3419 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3420 | if (rc) { | ||
3421 | cFYI(1, | ||
3422 | ("Send error in SetFileInfo (SetFileSize) = %d", | ||
3423 | rc)); | ||
3424 | } | ||
3425 | |||
3426 | if (pSMB) | ||
3427 | cifs_buf_release(pSMB); | ||
3428 | |||
3429 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
3430 | since file handle passed in no longer valid */ | ||
3431 | |||
3432 | return rc; | ||
3433 | } | ||
3434 | |||
3435 | /* Some legacy servers such as NT4 require that the file times be set on | ||
3436 | an open handle, rather than by pathname - this is awkward due to | ||
3437 | potential access conflicts on the open, but it is unavoidable for these | ||
3438 | old servers since the only other choice is to go from 100 nanosecond DCE | ||
3439 | time and resort to the original setpathinfo level which takes the ancient | ||
3440 | DOS time format with 2 second granularity */ | ||
3441 | int | ||
3442 | CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, | ||
3443 | __u16 fid) | ||
3444 | { | ||
3445 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | ||
3446 | struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; | ||
3447 | char *data_offset; | ||
3448 | int rc = 0; | ||
3449 | int bytes_returned = 0; | ||
3450 | __u16 params, param_offset, offset, byte_count, count; | ||
3451 | |||
3452 | cFYI(1, ("Set Times (via SetFileInfo)")); | ||
3453 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3454 | (void **) &pSMBr); | ||
3455 | if (rc) | ||
3456 | return rc; | ||
3457 | |||
3458 | /* At this point there is no need to override the current pid | ||
3459 | with the pid of the opener, but that could change if we someday | ||
3460 | use an existing handle (rather than opening one on the fly) */ | ||
3461 | /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); | ||
3462 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/ | ||
3463 | |||
3464 | params = 6; | ||
3465 | pSMB->MaxSetupCount = 0; | ||
3466 | pSMB->Reserved = 0; | ||
3467 | pSMB->Flags = 0; | ||
3468 | pSMB->Timeout = 0; | ||
3469 | pSMB->Reserved2 = 0; | ||
3470 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | ||
3471 | offset = param_offset + params; | ||
3472 | |||
3473 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | ||
3474 | |||
3475 | count = sizeof (FILE_BASIC_INFO); | ||
3476 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3477 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ | ||
3478 | pSMB->SetupCount = 1; | ||
3479 | pSMB->Reserved3 = 0; | ||
3480 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | ||
3481 | byte_count = 3 /* pad */ + params + count; | ||
3482 | pSMB->DataCount = cpu_to_le16(count); | ||
3483 | pSMB->ParameterCount = cpu_to_le16(params); | ||
3484 | pSMB->TotalDataCount = pSMB->DataCount; | ||
3485 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
3486 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
3487 | pSMB->DataOffset = cpu_to_le16(offset); | ||
3488 | pSMB->Fid = fid; | ||
3489 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | ||
3490 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2); | ||
3491 | else | ||
3492 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); | ||
3493 | pSMB->Reserved4 = 0; | ||
3494 | pSMB->hdr.smb_buf_length += byte_count; | ||
3495 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3496 | memcpy(data_offset,data,sizeof(FILE_BASIC_INFO)); | ||
3497 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3498 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3499 | if (rc) { | ||
3500 | cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc)); | ||
3501 | } | ||
3502 | |||
3503 | cifs_buf_release(pSMB); | ||
3504 | |||
3505 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
3506 | since file handle passed in no longer valid */ | ||
3507 | |||
3508 | return rc; | ||
3509 | } | ||
3510 | |||
3511 | |||
3512 | int | ||
3513 | CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName, | ||
3514 | const FILE_BASIC_INFO * data, | ||
3515 | const struct nls_table *nls_codepage) | ||
3516 | { | ||
3517 | TRANSACTION2_SPI_REQ *pSMB = NULL; | ||
3518 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | ||
3519 | int name_len; | ||
3520 | int rc = 0; | ||
3521 | int bytes_returned = 0; | ||
3522 | char *data_offset; | ||
3523 | __u16 params, param_offset, offset, byte_count, count; | ||
3524 | |||
3525 | cFYI(1, ("In SetTimes")); | ||
3526 | |||
3527 | SetTimesRetry: | ||
3528 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3529 | (void **) &pSMBr); | ||
3530 | if (rc) | ||
3531 | return rc; | ||
3532 | |||
3533 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
3534 | name_len = | ||
3535 | cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX | ||
3536 | /* find define for this maxpathcomponent */ | ||
3537 | , nls_codepage); | ||
3538 | name_len++; /* trailing null */ | ||
3539 | name_len *= 2; | ||
3540 | } else { /* BB improve the check for buffer overruns BB */ | ||
3541 | name_len = strnlen(fileName, PATH_MAX); | ||
3542 | name_len++; /* trailing null */ | ||
3543 | strncpy(pSMB->FileName, fileName, name_len); | ||
3544 | } | ||
3545 | |||
3546 | params = 6 + name_len; | ||
3547 | count = sizeof (FILE_BASIC_INFO); | ||
3548 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3549 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | ||
3550 | pSMB->MaxSetupCount = 0; | ||
3551 | pSMB->Reserved = 0; | ||
3552 | pSMB->Flags = 0; | ||
3553 | pSMB->Timeout = 0; | ||
3554 | pSMB->Reserved2 = 0; | ||
3555 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | ||
3556 | InformationLevel) - 4; | ||
3557 | offset = param_offset + params; | ||
3558 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | ||
3559 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
3560 | pSMB->DataOffset = cpu_to_le16(offset); | ||
3561 | pSMB->SetupCount = 1; | ||
3562 | pSMB->Reserved3 = 0; | ||
3563 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | ||
3564 | byte_count = 3 /* pad */ + params + count; | ||
3565 | |||
3566 | pSMB->DataCount = cpu_to_le16(count); | ||
3567 | pSMB->ParameterCount = cpu_to_le16(params); | ||
3568 | pSMB->TotalDataCount = pSMB->DataCount; | ||
3569 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
3570 | if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) | ||
3571 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2); | ||
3572 | else | ||
3573 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); | ||
3574 | pSMB->Reserved4 = 0; | ||
3575 | pSMB->hdr.smb_buf_length += byte_count; | ||
3576 | memcpy(data_offset, data, sizeof (FILE_BASIC_INFO)); | ||
3577 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3578 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3579 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3580 | if (rc) { | ||
3581 | cFYI(1, ("SetPathInfo (times) returned %d", rc)); | ||
3582 | } | ||
3583 | |||
3584 | cifs_buf_release(pSMB); | ||
3585 | |||
3586 | if (rc == -EAGAIN) | ||
3587 | goto SetTimesRetry; | ||
3588 | |||
3589 | return rc; | ||
3590 | } | ||
3591 | |||
3592 | /* Can not be used to set time stamps yet (due to old DOS time format) */ | ||
3593 | /* Can be used to set attributes */ | ||
3594 | #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug | ||
3595 | handling it anyway and NT4 was what we thought it would be needed for | ||
3596 | Do not delete it until we prove whether needed for Win9x though */ | ||
3597 | int | ||
3598 | CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName, | ||
3599 | __u16 dos_attrs, const struct nls_table *nls_codepage) | ||
3600 | { | ||
3601 | SETATTR_REQ *pSMB = NULL; | ||
3602 | SETATTR_RSP *pSMBr = NULL; | ||
3603 | int rc = 0; | ||
3604 | int bytes_returned; | ||
3605 | int name_len; | ||
3606 | |||
3607 | cFYI(1, ("In SetAttrLegacy")); | ||
3608 | |||
3609 | SetAttrLgcyRetry: | ||
3610 | rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB, | ||
3611 | (void **) &pSMBr); | ||
3612 | if (rc) | ||
3613 | return rc; | ||
3614 | |||
3615 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
3616 | name_len = | ||
3617 | cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, | ||
3618 | PATH_MAX, nls_codepage); | ||
3619 | name_len++; /* trailing null */ | ||
3620 | name_len *= 2; | ||
3621 | } else { /* BB improve the check for buffer overruns BB */ | ||
3622 | name_len = strnlen(fileName, PATH_MAX); | ||
3623 | name_len++; /* trailing null */ | ||
3624 | strncpy(pSMB->fileName, fileName, name_len); | ||
3625 | } | ||
3626 | pSMB->attr = cpu_to_le16(dos_attrs); | ||
3627 | pSMB->BufferFormat = 0x04; | ||
3628 | pSMB->hdr.smb_buf_length += name_len + 1; | ||
3629 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | ||
3630 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3631 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3632 | if (rc) { | ||
3633 | cFYI(1, ("Error in LegacySetAttr = %d", rc)); | ||
3634 | } | ||
3635 | |||
3636 | cifs_buf_release(pSMB); | ||
3637 | |||
3638 | if (rc == -EAGAIN) | ||
3639 | goto SetAttrLgcyRetry; | ||
3640 | |||
3641 | return rc; | ||
3642 | } | ||
3643 | #endif /* temporarily unneeded SetAttr legacy function */ | ||
3644 | |||
3645 | int | ||
3646 | CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, | ||
3647 | char *fileName, __u64 mode, __u64 uid, __u64 gid, | ||
3648 | dev_t device, const struct nls_table *nls_codepage) | ||
3649 | { | ||
3650 | TRANSACTION2_SPI_REQ *pSMB = NULL; | ||
3651 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | ||
3652 | int name_len; | ||
3653 | int rc = 0; | ||
3654 | int bytes_returned = 0; | ||
3655 | FILE_UNIX_BASIC_INFO *data_offset; | ||
3656 | __u16 params, param_offset, offset, count, byte_count; | ||
3657 | |||
3658 | cFYI(1, ("In SetUID/GID/Mode")); | ||
3659 | setPermsRetry: | ||
3660 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3661 | (void **) &pSMBr); | ||
3662 | if (rc) | ||
3663 | return rc; | ||
3664 | |||
3665 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
3666 | name_len = | ||
3667 | cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX | ||
3668 | /* find define for this maxpathcomponent */ | ||
3669 | , nls_codepage); | ||
3670 | name_len++; /* trailing null */ | ||
3671 | name_len *= 2; | ||
3672 | } else { /* BB improve the check for buffer overruns BB */ | ||
3673 | name_len = strnlen(fileName, PATH_MAX); | ||
3674 | name_len++; /* trailing null */ | ||
3675 | strncpy(pSMB->FileName, fileName, name_len); | ||
3676 | } | ||
3677 | |||
3678 | params = 6 + name_len; | ||
3679 | count = sizeof (FILE_UNIX_BASIC_INFO); | ||
3680 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3681 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | ||
3682 | pSMB->MaxSetupCount = 0; | ||
3683 | pSMB->Reserved = 0; | ||
3684 | pSMB->Flags = 0; | ||
3685 | pSMB->Timeout = 0; | ||
3686 | pSMB->Reserved2 = 0; | ||
3687 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | ||
3688 | InformationLevel) - 4; | ||
3689 | offset = param_offset + params; | ||
3690 | data_offset = | ||
3691 | (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol + | ||
3692 | offset); | ||
3693 | memset(data_offset, 0, count); | ||
3694 | pSMB->DataOffset = cpu_to_le16(offset); | ||
3695 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
3696 | pSMB->SetupCount = 1; | ||
3697 | pSMB->Reserved3 = 0; | ||
3698 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | ||
3699 | byte_count = 3 /* pad */ + params + count; | ||
3700 | pSMB->ParameterCount = cpu_to_le16(params); | ||
3701 | pSMB->DataCount = cpu_to_le16(count); | ||
3702 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
3703 | pSMB->TotalDataCount = pSMB->DataCount; | ||
3704 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); | ||
3705 | pSMB->Reserved4 = 0; | ||
3706 | pSMB->hdr.smb_buf_length += byte_count; | ||
3707 | data_offset->Uid = cpu_to_le64(uid); | ||
3708 | data_offset->Gid = cpu_to_le64(gid); | ||
3709 | /* better to leave device as zero when it is */ | ||
3710 | data_offset->DevMajor = cpu_to_le64(MAJOR(device)); | ||
3711 | data_offset->DevMinor = cpu_to_le64(MINOR(device)); | ||
3712 | data_offset->Permissions = cpu_to_le64(mode); | ||
3713 | |||
3714 | if(S_ISREG(mode)) | ||
3715 | data_offset->Type = cpu_to_le32(UNIX_FILE); | ||
3716 | else if(S_ISDIR(mode)) | ||
3717 | data_offset->Type = cpu_to_le32(UNIX_DIR); | ||
3718 | else if(S_ISLNK(mode)) | ||
3719 | data_offset->Type = cpu_to_le32(UNIX_SYMLINK); | ||
3720 | else if(S_ISCHR(mode)) | ||
3721 | data_offset->Type = cpu_to_le32(UNIX_CHARDEV); | ||
3722 | else if(S_ISBLK(mode)) | ||
3723 | data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV); | ||
3724 | else if(S_ISFIFO(mode)) | ||
3725 | data_offset->Type = cpu_to_le32(UNIX_FIFO); | ||
3726 | else if(S_ISSOCK(mode)) | ||
3727 | data_offset->Type = cpu_to_le32(UNIX_SOCKET); | ||
3728 | |||
3729 | |||
3730 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3731 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3732 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3733 | if (rc) { | ||
3734 | cFYI(1, ("SetPathInfo (perms) returned %d", rc)); | ||
3735 | } | ||
3736 | |||
3737 | if (pSMB) | ||
3738 | cifs_buf_release(pSMB); | ||
3739 | if (rc == -EAGAIN) | ||
3740 | goto setPermsRetry; | ||
3741 | return rc; | ||
3742 | } | ||
3743 | |||
3744 | int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | ||
3745 | const int notify_subdirs, const __u16 netfid, | ||
3746 | __u32 filter, const struct nls_table *nls_codepage) | ||
3747 | { | ||
3748 | int rc = 0; | ||
3749 | struct smb_com_transaction_change_notify_req * pSMB = NULL; | ||
3750 | struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; | ||
3751 | int bytes_returned; | ||
3752 | |||
3753 | cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); | ||
3754 | rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, | ||
3755 | (void **) &pSMBr); | ||
3756 | if (rc) | ||
3757 | return rc; | ||
3758 | |||
3759 | pSMB->TotalParameterCount = 0 ; | ||
3760 | pSMB->TotalDataCount = 0; | ||
3761 | pSMB->MaxParameterCount = cpu_to_le32(2); | ||
3762 | /* BB find exact data count max from sess structure BB */ | ||
3763 | pSMB->MaxDataCount = 0; /* same in little endian or be */ | ||
3764 | pSMB->MaxSetupCount = 4; | ||
3765 | pSMB->Reserved = 0; | ||
3766 | pSMB->ParameterOffset = 0; | ||
3767 | pSMB->DataCount = 0; | ||
3768 | pSMB->DataOffset = 0; | ||
3769 | pSMB->SetupCount = 4; /* single byte does not need le conversion */ | ||
3770 | pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); | ||
3771 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
3772 | if(notify_subdirs) | ||
3773 | pSMB->WatchTree = 1; /* one byte - no le conversion needed */ | ||
3774 | pSMB->Reserved2 = 0; | ||
3775 | pSMB->CompletionFilter = cpu_to_le32(filter); | ||
3776 | pSMB->Fid = netfid; /* file handle always le */ | ||
3777 | pSMB->ByteCount = 0; | ||
3778 | |||
3779 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3780 | (struct smb_hdr *) pSMBr, &bytes_returned, -1); | ||
3781 | if (rc) { | ||
3782 | cFYI(1, ("Error in Notify = %d", rc)); | ||
3783 | } | ||
3784 | cifs_buf_release(pSMB); | ||
3785 | return rc; | ||
3786 | } | ||
3787 | #ifdef CONFIG_CIFS_XATTR | ||
3788 | ssize_t | ||
3789 | CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | ||
3790 | const unsigned char *searchName, | ||
3791 | char * EAData, size_t buf_size, | ||
3792 | const struct nls_table *nls_codepage) | ||
3793 | { | ||
3794 | /* BB assumes one setup word */ | ||
3795 | TRANSACTION2_QPI_REQ *pSMB = NULL; | ||
3796 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | ||
3797 | int rc = 0; | ||
3798 | int bytes_returned; | ||
3799 | int name_len; | ||
3800 | struct fea * temp_fea; | ||
3801 | char * temp_ptr; | ||
3802 | __u16 params, byte_count; | ||
3803 | |||
3804 | cFYI(1, ("In Query All EAs path %s", searchName)); | ||
3805 | QAllEAsRetry: | ||
3806 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3807 | (void **) &pSMBr); | ||
3808 | if (rc) | ||
3809 | return rc; | ||
3810 | |||
3811 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
3812 | name_len = | ||
3813 | cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX | ||
3814 | /* find define for this maxpathcomponent */ | ||
3815 | , nls_codepage); | ||
3816 | name_len++; /* trailing null */ | ||
3817 | name_len *= 2; | ||
3818 | } else { /* BB improve the check for buffer overruns BB */ | ||
3819 | name_len = strnlen(searchName, PATH_MAX); | ||
3820 | name_len++; /* trailing null */ | ||
3821 | strncpy(pSMB->FileName, searchName, name_len); | ||
3822 | } | ||
3823 | |||
3824 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ; | ||
3825 | pSMB->TotalDataCount = 0; | ||
3826 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3827 | pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ | ||
3828 | pSMB->MaxSetupCount = 0; | ||
3829 | pSMB->Reserved = 0; | ||
3830 | pSMB->Flags = 0; | ||
3831 | pSMB->Timeout = 0; | ||
3832 | pSMB->Reserved2 = 0; | ||
3833 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
3834 | struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); | ||
3835 | pSMB->DataCount = 0; | ||
3836 | pSMB->DataOffset = 0; | ||
3837 | pSMB->SetupCount = 1; | ||
3838 | pSMB->Reserved3 = 0; | ||
3839 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | ||
3840 | byte_count = params + 1 /* pad */ ; | ||
3841 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
3842 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
3843 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); | ||
3844 | pSMB->Reserved4 = 0; | ||
3845 | pSMB->hdr.smb_buf_length += byte_count; | ||
3846 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3847 | |||
3848 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3849 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3850 | if (rc) { | ||
3851 | cFYI(1, ("Send error in QueryAllEAs = %d", rc)); | ||
3852 | } else { /* decode response */ | ||
3853 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3854 | |||
3855 | /* BB also check enough total bytes returned */ | ||
3856 | /* BB we need to improve the validity checking | ||
3857 | of these trans2 responses */ | ||
3858 | if (rc || (pSMBr->ByteCount < 4)) | ||
3859 | rc = -EIO; /* bad smb */ | ||
3860 | /* else if (pFindData){ | ||
3861 | memcpy((char *) pFindData, | ||
3862 | (char *) &pSMBr->hdr.Protocol + | ||
3863 | data_offset, kl); | ||
3864 | }*/ else { | ||
3865 | /* check that length of list is not more than bcc */ | ||
3866 | /* check that each entry does not go beyond length | ||
3867 | of list */ | ||
3868 | /* check that each element of each entry does not | ||
3869 | go beyond end of list */ | ||
3870 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
3871 | struct fealist * ea_response_data; | ||
3872 | rc = 0; | ||
3873 | /* validate_trans2_offsets() */ | ||
3874 | /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/ | ||
3875 | ea_response_data = (struct fealist *) | ||
3876 | (((char *) &pSMBr->hdr.Protocol) + | ||
3877 | data_offset); | ||
3878 | name_len = le32_to_cpu(ea_response_data->list_len); | ||
3879 | cFYI(1,("ea length %d", name_len)); | ||
3880 | if(name_len <= 8) { | ||
3881 | /* returned EA size zeroed at top of function */ | ||
3882 | cFYI(1,("empty EA list returned from server")); | ||
3883 | } else { | ||
3884 | /* account for ea list len */ | ||
3885 | name_len -= 4; | ||
3886 | temp_fea = ea_response_data->list; | ||
3887 | temp_ptr = (char *)temp_fea; | ||
3888 | while(name_len > 0) { | ||
3889 | __u16 value_len; | ||
3890 | name_len -= 4; | ||
3891 | temp_ptr += 4; | ||
3892 | rc += temp_fea->name_len; | ||
3893 | /* account for prefix user. and trailing null */ | ||
3894 | rc = rc + 5 + 1; | ||
3895 | if(rc<(int)buf_size) { | ||
3896 | memcpy(EAData,"user.",5); | ||
3897 | EAData+=5; | ||
3898 | memcpy(EAData,temp_ptr,temp_fea->name_len); | ||
3899 | EAData+=temp_fea->name_len; | ||
3900 | /* null terminate name */ | ||
3901 | *EAData = 0; | ||
3902 | EAData = EAData + 1; | ||
3903 | } else if(buf_size == 0) { | ||
3904 | /* skip copy - calc size only */ | ||
3905 | } else { | ||
3906 | /* stop before overrun buffer */ | ||
3907 | rc = -ERANGE; | ||
3908 | break; | ||
3909 | } | ||
3910 | name_len -= temp_fea->name_len; | ||
3911 | temp_ptr += temp_fea->name_len; | ||
3912 | /* account for trailing null */ | ||
3913 | name_len--; | ||
3914 | temp_ptr++; | ||
3915 | value_len = le16_to_cpu(temp_fea->value_len); | ||
3916 | name_len -= value_len; | ||
3917 | temp_ptr += value_len; | ||
3918 | /* BB check that temp_ptr is still within smb BB*/ | ||
3919 | /* no trailing null to account for in value len */ | ||
3920 | /* go on to next EA */ | ||
3921 | temp_fea = (struct fea *)temp_ptr; | ||
3922 | } | ||
3923 | } | ||
3924 | } | ||
3925 | } | ||
3926 | if (pSMB) | ||
3927 | cifs_buf_release(pSMB); | ||
3928 | if (rc == -EAGAIN) | ||
3929 | goto QAllEAsRetry; | ||
3930 | |||
3931 | return (ssize_t)rc; | ||
3932 | } | ||
3933 | |||
3934 | ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon, | ||
3935 | const unsigned char * searchName,const unsigned char * ea_name, | ||
3936 | unsigned char * ea_value, size_t buf_size, | ||
3937 | const struct nls_table *nls_codepage) | ||
3938 | { | ||
3939 | TRANSACTION2_QPI_REQ *pSMB = NULL; | ||
3940 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | ||
3941 | int rc = 0; | ||
3942 | int bytes_returned; | ||
3943 | int name_len; | ||
3944 | struct fea * temp_fea; | ||
3945 | char * temp_ptr; | ||
3946 | __u16 params, byte_count; | ||
3947 | |||
3948 | cFYI(1, ("In Query EA path %s", searchName)); | ||
3949 | QEARetry: | ||
3950 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3951 | (void **) &pSMBr); | ||
3952 | if (rc) | ||
3953 | return rc; | ||
3954 | |||
3955 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
3956 | name_len = | ||
3957 | cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX | ||
3958 | /* find define for this maxpathcomponent */ | ||
3959 | , nls_codepage); | ||
3960 | name_len++; /* trailing null */ | ||
3961 | name_len *= 2; | ||
3962 | } else { /* BB improve the check for buffer overruns BB */ | ||
3963 | name_len = strnlen(searchName, PATH_MAX); | ||
3964 | name_len++; /* trailing null */ | ||
3965 | strncpy(pSMB->FileName, searchName, name_len); | ||
3966 | } | ||
3967 | |||
3968 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ; | ||
3969 | pSMB->TotalDataCount = 0; | ||
3970 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3971 | pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ | ||
3972 | pSMB->MaxSetupCount = 0; | ||
3973 | pSMB->Reserved = 0; | ||
3974 | pSMB->Flags = 0; | ||
3975 | pSMB->Timeout = 0; | ||
3976 | pSMB->Reserved2 = 0; | ||
3977 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
3978 | struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); | ||
3979 | pSMB->DataCount = 0; | ||
3980 | pSMB->DataOffset = 0; | ||
3981 | pSMB->SetupCount = 1; | ||
3982 | pSMB->Reserved3 = 0; | ||
3983 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | ||
3984 | byte_count = params + 1 /* pad */ ; | ||
3985 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
3986 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
3987 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); | ||
3988 | pSMB->Reserved4 = 0; | ||
3989 | pSMB->hdr.smb_buf_length += byte_count; | ||
3990 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3991 | |||
3992 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3993 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3994 | if (rc) { | ||
3995 | cFYI(1, ("Send error in Query EA = %d", rc)); | ||
3996 | } else { /* decode response */ | ||
3997 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3998 | |||
3999 | /* BB also check enough total bytes returned */ | ||
4000 | /* BB we need to improve the validity checking | ||
4001 | of these trans2 responses */ | ||
4002 | if (rc || (pSMBr->ByteCount < 4)) | ||
4003 | rc = -EIO; /* bad smb */ | ||
4004 | /* else if (pFindData){ | ||
4005 | memcpy((char *) pFindData, | ||
4006 | (char *) &pSMBr->hdr.Protocol + | ||
4007 | data_offset, kl); | ||
4008 | }*/ else { | ||
4009 | /* check that length of list is not more than bcc */ | ||
4010 | /* check that each entry does not go beyond length | ||
4011 | of list */ | ||
4012 | /* check that each element of each entry does not | ||
4013 | go beyond end of list */ | ||
4014 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
4015 | struct fealist * ea_response_data; | ||
4016 | rc = -ENODATA; | ||
4017 | /* validate_trans2_offsets() */ | ||
4018 | /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/ | ||
4019 | ea_response_data = (struct fealist *) | ||
4020 | (((char *) &pSMBr->hdr.Protocol) + | ||
4021 | data_offset); | ||
4022 | name_len = le32_to_cpu(ea_response_data->list_len); | ||
4023 | cFYI(1,("ea length %d", name_len)); | ||
4024 | if(name_len <= 8) { | ||
4025 | /* returned EA size zeroed at top of function */ | ||
4026 | cFYI(1,("empty EA list returned from server")); | ||
4027 | } else { | ||
4028 | /* account for ea list len */ | ||
4029 | name_len -= 4; | ||
4030 | temp_fea = ea_response_data->list; | ||
4031 | temp_ptr = (char *)temp_fea; | ||
4032 | /* loop through checking if we have a matching | ||
4033 | name and then return the associated value */ | ||
4034 | while(name_len > 0) { | ||
4035 | __u16 value_len; | ||
4036 | name_len -= 4; | ||
4037 | temp_ptr += 4; | ||
4038 | value_len = le16_to_cpu(temp_fea->value_len); | ||
4039 | /* BB validate that value_len falls within SMB, | ||
4040 | even though maximum for name_len is 255 */ | ||
4041 | if(memcmp(temp_fea->name,ea_name, | ||
4042 | temp_fea->name_len) == 0) { | ||
4043 | /* found a match */ | ||
4044 | rc = value_len; | ||
4045 | /* account for prefix user. and trailing null */ | ||
4046 | if(rc<=(int)buf_size) { | ||
4047 | memcpy(ea_value, | ||
4048 | temp_fea->name+temp_fea->name_len+1, | ||
4049 | rc); | ||
4050 | /* ea values, unlike ea names, | ||
4051 | are not null terminated */ | ||
4052 | } else if(buf_size == 0) { | ||
4053 | /* skip copy - calc size only */ | ||
4054 | } else { | ||
4055 | /* stop before overrun buffer */ | ||
4056 | rc = -ERANGE; | ||
4057 | } | ||
4058 | break; | ||
4059 | } | ||
4060 | name_len -= temp_fea->name_len; | ||
4061 | temp_ptr += temp_fea->name_len; | ||
4062 | /* account for trailing null */ | ||
4063 | name_len--; | ||
4064 | temp_ptr++; | ||
4065 | name_len -= value_len; | ||
4066 | temp_ptr += value_len; | ||
4067 | /* no trailing null to account for in value len */ | ||
4068 | /* go on to next EA */ | ||
4069 | temp_fea = (struct fea *)temp_ptr; | ||
4070 | } | ||
4071 | } | ||
4072 | } | ||
4073 | } | ||
4074 | if (pSMB) | ||
4075 | cifs_buf_release(pSMB); | ||
4076 | if (rc == -EAGAIN) | ||
4077 | goto QEARetry; | ||
4078 | |||
4079 | return (ssize_t)rc; | ||
4080 | } | ||
4081 | |||
4082 | int | ||
4083 | CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, | ||
4084 | const char * ea_name, const void * ea_value, | ||
4085 | const __u16 ea_value_len, const struct nls_table *nls_codepage) | ||
4086 | { | ||
4087 | struct smb_com_transaction2_spi_req *pSMB = NULL; | ||
4088 | struct smb_com_transaction2_spi_rsp *pSMBr = NULL; | ||
4089 | struct fealist *parm_data; | ||
4090 | int name_len; | ||
4091 | int rc = 0; | ||
4092 | int bytes_returned = 0; | ||
4093 | __u16 params, param_offset, byte_count, offset, count; | ||
4094 | |||
4095 | cFYI(1, ("In SetEA")); | ||
4096 | SetEARetry: | ||
4097 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
4098 | (void **) &pSMBr); | ||
4099 | if (rc) | ||
4100 | return rc; | ||
4101 | |||
4102 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
4103 | name_len = | ||
4104 | cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX | ||
4105 | /* find define for this maxpathcomponent */ | ||
4106 | , nls_codepage); | ||
4107 | name_len++; /* trailing null */ | ||
4108 | name_len *= 2; | ||
4109 | } else { /* BB improve the check for buffer overruns BB */ | ||
4110 | name_len = strnlen(fileName, PATH_MAX); | ||
4111 | name_len++; /* trailing null */ | ||
4112 | strncpy(pSMB->FileName, fileName, name_len); | ||
4113 | } | ||
4114 | |||
4115 | params = 6 + name_len; | ||
4116 | |||
4117 | /* done calculating parms using name_len of file name, | ||
4118 | now use name_len to calculate length of ea name | ||
4119 | we are going to create in the inode xattrs */ | ||
4120 | if(ea_name == NULL) | ||
4121 | name_len = 0; | ||
4122 | else | ||
4123 | name_len = strnlen(ea_name,255); | ||
4124 | |||
4125 | count = sizeof(*parm_data) + ea_value_len + name_len + 1; | ||
4126 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
4127 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ | ||
4128 | pSMB->MaxSetupCount = 0; | ||
4129 | pSMB->Reserved = 0; | ||
4130 | pSMB->Flags = 0; | ||
4131 | pSMB->Timeout = 0; | ||
4132 | pSMB->Reserved2 = 0; | ||
4133 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | ||
4134 | InformationLevel) - 4; | ||
4135 | offset = param_offset + params; | ||
4136 | pSMB->InformationLevel = | ||
4137 | cpu_to_le16(SMB_SET_FILE_EA); | ||
4138 | |||
4139 | parm_data = | ||
4140 | (struct fealist *) (((char *) &pSMB->hdr.Protocol) + | ||
4141 | offset); | ||
4142 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
4143 | pSMB->DataOffset = cpu_to_le16(offset); | ||
4144 | pSMB->SetupCount = 1; | ||
4145 | pSMB->Reserved3 = 0; | ||
4146 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | ||
4147 | byte_count = 3 /* pad */ + params + count; | ||
4148 | pSMB->DataCount = cpu_to_le16(count); | ||
4149 | parm_data->list_len = cpu_to_le32(count); | ||
4150 | parm_data->list[0].EA_flags = 0; | ||
4151 | /* we checked above that name len is less than 255 */ | ||
4152 | parm_data->list[0].name_len = (__u8)name_len;; | ||
4153 | /* EA names are always ASCII */ | ||
4154 | if(ea_name) | ||
4155 | strncpy(parm_data->list[0].name,ea_name,name_len); | ||
4156 | parm_data->list[0].name[name_len] = 0; | ||
4157 | parm_data->list[0].value_len = cpu_to_le16(ea_value_len); | ||
4158 | /* caller ensures that ea_value_len is less than 64K but | ||
4159 | we need to ensure that it fits within the smb */ | ||
4160 | |||
4161 | /*BB add length check that it would fit in negotiated SMB buffer size BB */ | ||
4162 | /* if(ea_value_len > buffer_size - 512 (enough for header)) */ | ||
4163 | if(ea_value_len) | ||
4164 | memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len); | ||
4165 | |||
4166 | pSMB->TotalDataCount = pSMB->DataCount; | ||
4167 | pSMB->ParameterCount = cpu_to_le16(params); | ||
4168 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
4169 | pSMB->Reserved4 = 0; | ||
4170 | pSMB->hdr.smb_buf_length += byte_count; | ||
4171 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
4172 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
4173 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
4174 | if (rc) { | ||
4175 | cFYI(1, ("SetPathInfo (EA) returned %d", rc)); | ||
4176 | } | ||
4177 | |||
4178 | cifs_buf_release(pSMB); | ||
4179 | |||
4180 | if (rc == -EAGAIN) | ||
4181 | goto SetEARetry; | ||
4182 | |||
4183 | return rc; | ||
4184 | } | ||
4185 | |||
4186 | #endif | ||
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c new file mode 100644 index 000000000000..40470b9d5477 --- /dev/null +++ b/fs/cifs/connect.c | |||
@@ -0,0 +1,3064 @@ | |||
1 | /* | ||
2 | * fs/cifs/connect.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/fs.h> | ||
22 | #include <linux/net.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/list.h> | ||
25 | #include <linux/wait.h> | ||
26 | #include <linux/ipv6.h> | ||
27 | #include <linux/pagemap.h> | ||
28 | #include <linux/ctype.h> | ||
29 | #include <linux/utsname.h> | ||
30 | #include <linux/mempool.h> | ||
31 | #include <asm/uaccess.h> | ||
32 | #include <asm/processor.h> | ||
33 | #include "cifspdu.h" | ||
34 | #include "cifsglob.h" | ||
35 | #include "cifsproto.h" | ||
36 | #include "cifs_unicode.h" | ||
37 | #include "cifs_debug.h" | ||
38 | #include "cifs_fs_sb.h" | ||
39 | #include "ntlmssp.h" | ||
40 | #include "nterr.h" | ||
41 | #include "rfc1002pdu.h" | ||
42 | |||
43 | #define CIFS_PORT 445 | ||
44 | #define RFC1001_PORT 139 | ||
45 | |||
46 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, | ||
47 | unsigned char *p24); | ||
48 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | ||
49 | unsigned char *p24); | ||
50 | |||
51 | extern mempool_t *cifs_req_poolp; | ||
52 | |||
53 | struct smb_vol { | ||
54 | char *username; | ||
55 | char *password; | ||
56 | char *domainname; | ||
57 | char *UNC; | ||
58 | char *UNCip; | ||
59 | char *in6_addr; /* ipv6 address as human readable form of in6_addr */ | ||
60 | char *iocharset; /* local code page for mapping to and from Unicode */ | ||
61 | char source_rfc1001_name[16]; /* netbios name of client */ | ||
62 | uid_t linux_uid; | ||
63 | gid_t linux_gid; | ||
64 | mode_t file_mode; | ||
65 | mode_t dir_mode; | ||
66 | unsigned rw:1; | ||
67 | unsigned retry:1; | ||
68 | unsigned intr:1; | ||
69 | unsigned setuids:1; | ||
70 | unsigned noperm:1; | ||
71 | unsigned no_psx_acl:1; /* set if posix acl support should be disabled */ | ||
72 | unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/ | ||
73 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ | ||
74 | unsigned direct_io:1; | ||
75 | unsigned int rsize; | ||
76 | unsigned int wsize; | ||
77 | unsigned int sockopt; | ||
78 | unsigned short int port; | ||
79 | }; | ||
80 | |||
81 | static int ipv4_connect(struct sockaddr_in *psin_server, | ||
82 | struct socket **csocket, | ||
83 | char * netb_name); | ||
84 | static int ipv6_connect(struct sockaddr_in6 *psin_server, | ||
85 | struct socket **csocket); | ||
86 | |||
87 | |||
88 | /* | ||
89 | * cifs tcp session reconnection | ||
90 | * | ||
91 | * mark tcp session as reconnecting so temporarily locked | ||
92 | * mark all smb sessions as reconnecting for tcp session | ||
93 | * reconnect tcp session | ||
94 | * wake up waiters on reconnection? - (not needed currently) | ||
95 | */ | ||
96 | |||
97 | int | ||
98 | cifs_reconnect(struct TCP_Server_Info *server) | ||
99 | { | ||
100 | int rc = 0; | ||
101 | struct list_head *tmp; | ||
102 | struct cifsSesInfo *ses; | ||
103 | struct cifsTconInfo *tcon; | ||
104 | struct mid_q_entry * mid_entry; | ||
105 | |||
106 | spin_lock(&GlobalMid_Lock); | ||
107 | if(server->tcpStatus == CifsExiting) { | ||
108 | /* the demux thread will exit normally | ||
109 | next time through the loop */ | ||
110 | spin_unlock(&GlobalMid_Lock); | ||
111 | return rc; | ||
112 | } else | ||
113 | server->tcpStatus = CifsNeedReconnect; | ||
114 | spin_unlock(&GlobalMid_Lock); | ||
115 | server->maxBuf = 0; | ||
116 | |||
117 | cFYI(1, ("Reconnecting tcp session ")); | ||
118 | |||
119 | /* before reconnecting the tcp session, mark the smb session (uid) | ||
120 | and the tid bad so they are not used until reconnected */ | ||
121 | read_lock(&GlobalSMBSeslock); | ||
122 | list_for_each(tmp, &GlobalSMBSessionList) { | ||
123 | ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); | ||
124 | if (ses->server) { | ||
125 | if (ses->server == server) { | ||
126 | ses->status = CifsNeedReconnect; | ||
127 | ses->ipc_tid = 0; | ||
128 | } | ||
129 | } | ||
130 | /* else tcp and smb sessions need reconnection */ | ||
131 | } | ||
132 | list_for_each(tmp, &GlobalTreeConnectionList) { | ||
133 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | ||
134 | if((tcon) && (tcon->ses) && (tcon->ses->server == server)) { | ||
135 | tcon->tidStatus = CifsNeedReconnect; | ||
136 | } | ||
137 | } | ||
138 | read_unlock(&GlobalSMBSeslock); | ||
139 | /* do not want to be sending data on a socket we are freeing */ | ||
140 | down(&server->tcpSem); | ||
141 | if(server->ssocket) { | ||
142 | cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state, | ||
143 | server->ssocket->flags)); | ||
144 | server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN); | ||
145 | cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state, | ||
146 | server->ssocket->flags)); | ||
147 | sock_release(server->ssocket); | ||
148 | server->ssocket = NULL; | ||
149 | } | ||
150 | |||
151 | spin_lock(&GlobalMid_Lock); | ||
152 | list_for_each(tmp, &server->pending_mid_q) { | ||
153 | mid_entry = list_entry(tmp, struct | ||
154 | mid_q_entry, | ||
155 | qhead); | ||
156 | if(mid_entry) { | ||
157 | if(mid_entry->midState == MID_REQUEST_SUBMITTED) { | ||
158 | /* Mark other intransit requests as needing retry so | ||
159 | we do not immediately mark the session bad again | ||
160 | (ie after we reconnect below) as they timeout too */ | ||
161 | mid_entry->midState = MID_RETRY_NEEDED; | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | spin_unlock(&GlobalMid_Lock); | ||
166 | up(&server->tcpSem); | ||
167 | |||
168 | while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) | ||
169 | { | ||
170 | if(server->protocolType == IPV6) { | ||
171 | rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket); | ||
172 | } else { | ||
173 | rc = ipv4_connect(&server->addr.sockAddr, | ||
174 | &server->ssocket, | ||
175 | server->workstation_RFC1001_name); | ||
176 | } | ||
177 | if(rc) { | ||
178 | set_current_state(TASK_INTERRUPTIBLE); | ||
179 | schedule_timeout(3 * HZ); | ||
180 | } else { | ||
181 | atomic_inc(&tcpSesReconnectCount); | ||
182 | spin_lock(&GlobalMid_Lock); | ||
183 | if(server->tcpStatus != CifsExiting) | ||
184 | server->tcpStatus = CifsGood; | ||
185 | spin_unlock(&GlobalMid_Lock); | ||
186 | /* atomic_set(&server->inFlight,0);*/ | ||
187 | wake_up(&server->response_q); | ||
188 | } | ||
189 | } | ||
190 | return rc; | ||
191 | } | ||
192 | |||
193 | static int | ||
194 | cifs_demultiplex_thread(struct TCP_Server_Info *server) | ||
195 | { | ||
196 | int length; | ||
197 | unsigned int pdu_length, total_read; | ||
198 | struct smb_hdr *smb_buffer = NULL; | ||
199 | struct msghdr smb_msg; | ||
200 | struct kvec iov; | ||
201 | struct socket *csocket = server->ssocket; | ||
202 | struct list_head *tmp; | ||
203 | struct cifsSesInfo *ses; | ||
204 | struct task_struct *task_to_wake = NULL; | ||
205 | struct mid_q_entry *mid_entry; | ||
206 | char *temp; | ||
207 | |||
208 | daemonize("cifsd"); | ||
209 | allow_signal(SIGKILL); | ||
210 | current->flags |= PF_MEMALLOC; | ||
211 | server->tsk = current; /* save process info to wake at shutdown */ | ||
212 | cFYI(1, ("Demultiplex PID: %d", current->pid)); | ||
213 | write_lock(&GlobalSMBSeslock); | ||
214 | atomic_inc(&tcpSesAllocCount); | ||
215 | length = tcpSesAllocCount.counter; | ||
216 | write_unlock(&GlobalSMBSeslock); | ||
217 | if(length > 1) { | ||
218 | mempool_resize(cifs_req_poolp, | ||
219 | length + cifs_min_rcv, | ||
220 | GFP_KERNEL); | ||
221 | } | ||
222 | |||
223 | while (server->tcpStatus != CifsExiting) { | ||
224 | if (smb_buffer == NULL) | ||
225 | smb_buffer = cifs_buf_get(); | ||
226 | else | ||
227 | memset(smb_buffer, 0, sizeof (struct smb_hdr)); | ||
228 | |||
229 | if (smb_buffer == NULL) { | ||
230 | cERROR(1,("Can not get memory for SMB response")); | ||
231 | set_current_state(TASK_INTERRUPTIBLE); | ||
232 | schedule_timeout(HZ * 3); /* give system time to free memory */ | ||
233 | continue; | ||
234 | } | ||
235 | iov.iov_base = smb_buffer; | ||
236 | iov.iov_len = 4; | ||
237 | smb_msg.msg_control = NULL; | ||
238 | smb_msg.msg_controllen = 0; | ||
239 | length = | ||
240 | kernel_recvmsg(csocket, &smb_msg, | ||
241 | &iov, 1, 4, 0 /* BB see socket.h flags */); | ||
242 | |||
243 | if(server->tcpStatus == CifsExiting) { | ||
244 | break; | ||
245 | } else if (server->tcpStatus == CifsNeedReconnect) { | ||
246 | cFYI(1,("Reconnecting after server stopped responding")); | ||
247 | cifs_reconnect(server); | ||
248 | cFYI(1,("call to reconnect done")); | ||
249 | csocket = server->ssocket; | ||
250 | continue; | ||
251 | } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { | ||
252 | set_current_state(TASK_INTERRUPTIBLE); | ||
253 | schedule_timeout(1); /* minimum sleep to prevent looping | ||
254 | allowing socket to clear and app threads to set | ||
255 | tcpStatus CifsNeedReconnect if server hung */ | ||
256 | continue; | ||
257 | } else if (length <= 0) { | ||
258 | if(server->tcpStatus == CifsNew) { | ||
259 | cFYI(1,("tcp session abended prematurely (after SMBnegprot)")); | ||
260 | /* some servers kill tcp session rather than returning | ||
261 | smb negprot error in which case reconnecting here is | ||
262 | not going to help - return error to mount */ | ||
263 | break; | ||
264 | } | ||
265 | if(length == -EINTR) { | ||
266 | cFYI(1,("cifsd thread killed")); | ||
267 | break; | ||
268 | } | ||
269 | cFYI(1,("Reconnecting after unexpected peek error %d",length)); | ||
270 | cifs_reconnect(server); | ||
271 | csocket = server->ssocket; | ||
272 | wake_up(&server->response_q); | ||
273 | continue; | ||
274 | } else if (length > 3) { | ||
275 | pdu_length = ntohl(smb_buffer->smb_buf_length); | ||
276 | /* Only read pdu_length after below checks for too short (due | ||
277 | to e.g. int overflow) and too long ie beyond end of buf */ | ||
278 | cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); | ||
279 | |||
280 | temp = (char *) smb_buffer; | ||
281 | if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { | ||
282 | cFYI(0,("Received 4 byte keep alive packet")); | ||
283 | } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) { | ||
284 | cFYI(1,("Good RFC 1002 session rsp")); | ||
285 | } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { | ||
286 | /* we get this from Windows 98 instead of error on SMB negprot response */ | ||
287 | cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); | ||
288 | if(server->tcpStatus == CifsNew) { | ||
289 | /* if nack on negprot (rather than | ||
290 | ret of smb negprot error) reconnecting | ||
291 | not going to help, ret error to mount */ | ||
292 | break; | ||
293 | } else { | ||
294 | /* give server a second to | ||
295 | clean up before reconnect attempt */ | ||
296 | set_current_state(TASK_INTERRUPTIBLE); | ||
297 | schedule_timeout(HZ); | ||
298 | /* always try 445 first on reconnect | ||
299 | since we get NACK on some if we ever | ||
300 | connected to port 139 (the NACK is | ||
301 | since we do not begin with RFC1001 | ||
302 | session initialize frame) */ | ||
303 | server->addr.sockAddr.sin_port = htons(CIFS_PORT); | ||
304 | cifs_reconnect(server); | ||
305 | csocket = server->ssocket; | ||
306 | wake_up(&server->response_q); | ||
307 | continue; | ||
308 | } | ||
309 | } else if (temp[0] != (char) 0) { | ||
310 | cERROR(1,("Unknown RFC 1002 frame")); | ||
311 | cifs_dump_mem(" Received Data: ", temp, length); | ||
312 | cifs_reconnect(server); | ||
313 | csocket = server->ssocket; | ||
314 | continue; | ||
315 | } else { | ||
316 | if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) | ||
317 | || (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { | ||
318 | cERROR(1, | ||
319 | ("Invalid size SMB length %d and pdu_length %d", | ||
320 | length, pdu_length+4)); | ||
321 | cifs_reconnect(server); | ||
322 | csocket = server->ssocket; | ||
323 | wake_up(&server->response_q); | ||
324 | continue; | ||
325 | } else { /* length ok */ | ||
326 | length = 0; | ||
327 | iov.iov_base = 4 + (char *)smb_buffer; | ||
328 | iov.iov_len = pdu_length; | ||
329 | for (total_read = 0; | ||
330 | total_read < pdu_length; | ||
331 | total_read += length) { | ||
332 | length = kernel_recvmsg(csocket, &smb_msg, | ||
333 | &iov, 1, | ||
334 | pdu_length - total_read, 0); | ||
335 | if (length == 0) { | ||
336 | cERROR(1, | ||
337 | ("Zero length receive when expecting %d ", | ||
338 | pdu_length - total_read)); | ||
339 | cifs_reconnect(server); | ||
340 | csocket = server->ssocket; | ||
341 | wake_up(&server->response_q); | ||
342 | continue; | ||
343 | } | ||
344 | } | ||
345 | length += 4; /* account for rfc1002 hdr */ | ||
346 | } | ||
347 | |||
348 | dump_smb(smb_buffer, length); | ||
349 | if (checkSMB | ||
350 | (smb_buffer, smb_buffer->Mid, total_read+4)) { | ||
351 | cERROR(1, ("Bad SMB Received ")); | ||
352 | continue; | ||
353 | } | ||
354 | |||
355 | task_to_wake = NULL; | ||
356 | spin_lock(&GlobalMid_Lock); | ||
357 | list_for_each(tmp, &server->pending_mid_q) { | ||
358 | mid_entry = list_entry(tmp, struct | ||
359 | mid_q_entry, | ||
360 | qhead); | ||
361 | |||
362 | if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) { | ||
363 | cFYI(1, | ||
364 | (" Mid 0x%x matched - waking up ",mid_entry->mid)); | ||
365 | task_to_wake = mid_entry->tsk; | ||
366 | mid_entry->resp_buf = | ||
367 | smb_buffer; | ||
368 | mid_entry->midState = | ||
369 | MID_RESPONSE_RECEIVED; | ||
370 | } | ||
371 | } | ||
372 | spin_unlock(&GlobalMid_Lock); | ||
373 | if (task_to_wake) { | ||
374 | smb_buffer = NULL; /* will be freed by users thread after he is done */ | ||
375 | wake_up_process(task_to_wake); | ||
376 | } else if (is_valid_oplock_break(smb_buffer) == FALSE) { | ||
377 | cERROR(1, ("No task to wake, unknown frame rcvd!")); | ||
378 | cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); | ||
379 | } | ||
380 | } | ||
381 | } else { | ||
382 | cFYI(1, | ||
383 | ("Frame less than four bytes received %d bytes long.", | ||
384 | length)); | ||
385 | cifs_reconnect(server); | ||
386 | csocket = server->ssocket; | ||
387 | wake_up(&server->response_q); | ||
388 | continue; | ||
389 | } | ||
390 | } | ||
391 | spin_lock(&GlobalMid_Lock); | ||
392 | server->tcpStatus = CifsExiting; | ||
393 | server->tsk = NULL; | ||
394 | atomic_set(&server->inFlight, 0); | ||
395 | spin_unlock(&GlobalMid_Lock); | ||
396 | /* Although there should not be any requests blocked on | ||
397 | this queue it can not hurt to be paranoid and try to wake up requests | ||
398 | that may haven been blocked when more than 50 at time were on the wire | ||
399 | to the same server - they now will see the session is in exit state | ||
400 | and get out of SendReceive. */ | ||
401 | wake_up_all(&server->request_q); | ||
402 | /* give those requests time to exit */ | ||
403 | set_current_state(TASK_INTERRUPTIBLE); | ||
404 | schedule_timeout(HZ/8); | ||
405 | |||
406 | if(server->ssocket) { | ||
407 | sock_release(csocket); | ||
408 | server->ssocket = NULL; | ||
409 | } | ||
410 | if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ | ||
411 | cifs_buf_release(smb_buffer); | ||
412 | |||
413 | read_lock(&GlobalSMBSeslock); | ||
414 | if (list_empty(&server->pending_mid_q)) { | ||
415 | /* loop through server session structures attached to this and mark them dead */ | ||
416 | list_for_each(tmp, &GlobalSMBSessionList) { | ||
417 | ses = | ||
418 | list_entry(tmp, struct cifsSesInfo, | ||
419 | cifsSessionList); | ||
420 | if (ses->server == server) { | ||
421 | ses->status = CifsExiting; | ||
422 | ses->server = NULL; | ||
423 | } | ||
424 | } | ||
425 | read_unlock(&GlobalSMBSeslock); | ||
426 | } else { | ||
427 | spin_lock(&GlobalMid_Lock); | ||
428 | list_for_each(tmp, &server->pending_mid_q) { | ||
429 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | ||
430 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) { | ||
431 | cFYI(1, | ||
432 | (" Clearing Mid 0x%x - waking up ",mid_entry->mid)); | ||
433 | task_to_wake = mid_entry->tsk; | ||
434 | if(task_to_wake) { | ||
435 | wake_up_process(task_to_wake); | ||
436 | } | ||
437 | } | ||
438 | } | ||
439 | spin_unlock(&GlobalMid_Lock); | ||
440 | read_unlock(&GlobalSMBSeslock); | ||
441 | set_current_state(TASK_INTERRUPTIBLE); | ||
442 | /* 1/8th of sec is more than enough time for them to exit */ | ||
443 | schedule_timeout(HZ/8); | ||
444 | } | ||
445 | |||
446 | if (list_empty(&server->pending_mid_q)) { | ||
447 | /* mpx threads have not exited yet give them | ||
448 | at least the smb send timeout time for long ops */ | ||
449 | cFYI(1, ("Wait for exit from demultiplex thread")); | ||
450 | set_current_state(TASK_INTERRUPTIBLE); | ||
451 | schedule_timeout(46 * HZ); | ||
452 | /* if threads still have not exited they are probably never | ||
453 | coming home not much else we can do but free the memory */ | ||
454 | } | ||
455 | kfree(server); | ||
456 | |||
457 | write_lock(&GlobalSMBSeslock); | ||
458 | atomic_dec(&tcpSesAllocCount); | ||
459 | length = tcpSesAllocCount.counter; | ||
460 | write_unlock(&GlobalSMBSeslock); | ||
461 | if(length > 0) { | ||
462 | mempool_resize(cifs_req_poolp, | ||
463 | length + cifs_min_rcv, | ||
464 | GFP_KERNEL); | ||
465 | } | ||
466 | |||
467 | set_current_state(TASK_INTERRUPTIBLE); | ||
468 | schedule_timeout(HZ/4); | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static void * | ||
473 | cifs_kcalloc(size_t size, unsigned int __nocast type) | ||
474 | { | ||
475 | void *addr; | ||
476 | addr = kmalloc(size, type); | ||
477 | if (addr) | ||
478 | memset(addr, 0, size); | ||
479 | return addr; | ||
480 | } | ||
481 | |||
482 | static int | ||
483 | cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | ||
484 | { | ||
485 | char *value; | ||
486 | char *data; | ||
487 | unsigned int temp_len, i, j; | ||
488 | char separator[2]; | ||
489 | |||
490 | separator[0] = ','; | ||
491 | separator[1] = 0; | ||
492 | |||
493 | memset(vol->source_rfc1001_name,0x20,15); | ||
494 | for(i=0;i < strnlen(system_utsname.nodename,15);i++) { | ||
495 | /* does not have to be a perfect mapping since the field is | ||
496 | informational, only used for servers that do not support | ||
497 | port 445 and it can be overridden at mount time */ | ||
498 | vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]); | ||
499 | } | ||
500 | vol->source_rfc1001_name[15] = 0; | ||
501 | |||
502 | vol->linux_uid = current->uid; /* current->euid instead? */ | ||
503 | vol->linux_gid = current->gid; | ||
504 | vol->dir_mode = S_IRWXUGO; | ||
505 | /* 2767 perms indicate mandatory locking support */ | ||
506 | vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); | ||
507 | |||
508 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ | ||
509 | vol->rw = TRUE; | ||
510 | |||
511 | if (!options) | ||
512 | return 1; | ||
513 | |||
514 | if(strncmp(options,"sep=",4) == 0) { | ||
515 | if(options[4] != 0) { | ||
516 | separator[0] = options[4]; | ||
517 | options += 5; | ||
518 | } else { | ||
519 | cFYI(1,("Null separator not allowed")); | ||
520 | } | ||
521 | } | ||
522 | |||
523 | while ((data = strsep(&options, separator)) != NULL) { | ||
524 | if (!*data) | ||
525 | continue; | ||
526 | if ((value = strchr(data, '=')) != NULL) | ||
527 | *value++ = '\0'; | ||
528 | |||
529 | if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/ | ||
530 | vol->no_xattr = 0; | ||
531 | } else if (strnicmp(data, "nouser_xattr",12) == 0) { | ||
532 | vol->no_xattr = 1; | ||
533 | } else if (strnicmp(data, "user", 4) == 0) { | ||
534 | if (!value || !*value) { | ||
535 | printk(KERN_WARNING | ||
536 | "CIFS: invalid or missing username\n"); | ||
537 | return 1; /* needs_arg; */ | ||
538 | } | ||
539 | if (strnlen(value, 200) < 200) { | ||
540 | vol->username = value; | ||
541 | } else { | ||
542 | printk(KERN_WARNING "CIFS: username too long\n"); | ||
543 | return 1; | ||
544 | } | ||
545 | } else if (strnicmp(data, "pass", 4) == 0) { | ||
546 | if (!value) { | ||
547 | vol->password = NULL; | ||
548 | continue; | ||
549 | } else if(value[0] == 0) { | ||
550 | /* check if string begins with double comma | ||
551 | since that would mean the password really | ||
552 | does start with a comma, and would not | ||
553 | indicate an empty string */ | ||
554 | if(value[1] != separator[0]) { | ||
555 | vol->password = NULL; | ||
556 | continue; | ||
557 | } | ||
558 | } | ||
559 | temp_len = strlen(value); | ||
560 | /* removed password length check, NTLM passwords | ||
561 | can be arbitrarily long */ | ||
562 | |||
563 | /* if comma in password, the string will be | ||
564 | prematurely null terminated. Commas in password are | ||
565 | specified across the cifs mount interface by a double | ||
566 | comma ie ,, and a comma used as in other cases ie ',' | ||
567 | as a parameter delimiter/separator is single and due | ||
568 | to the strsep above is temporarily zeroed. */ | ||
569 | |||
570 | /* NB: password legally can have multiple commas and | ||
571 | the only illegal character in a password is null */ | ||
572 | |||
573 | if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) { | ||
574 | /* reinsert comma */ | ||
575 | value[temp_len] = separator[0]; | ||
576 | temp_len+=2; /* move after the second comma */ | ||
577 | while(value[temp_len] != 0) { | ||
578 | if (value[temp_len] == separator[0]) { | ||
579 | if (value[temp_len+1] == separator[0]) { | ||
580 | temp_len++; /* skip second comma */ | ||
581 | } else { | ||
582 | /* single comma indicating start | ||
583 | of next parm */ | ||
584 | break; | ||
585 | } | ||
586 | } | ||
587 | temp_len++; | ||
588 | } | ||
589 | if(value[temp_len] == 0) { | ||
590 | options = NULL; | ||
591 | } else { | ||
592 | value[temp_len] = 0; | ||
593 | /* point option to start of next parm */ | ||
594 | options = value + temp_len + 1; | ||
595 | } | ||
596 | /* go from value to value + temp_len condensing | ||
597 | double commas to singles. Note that this ends up | ||
598 | allocating a few bytes too many, which is ok */ | ||
599 | vol->password = cifs_kcalloc(temp_len, GFP_KERNEL); | ||
600 | for(i=0,j=0;i<temp_len;i++,j++) { | ||
601 | vol->password[j] = value[i]; | ||
602 | if(value[i] == separator[0] && value[i+1] == separator[0]) { | ||
603 | /* skip second comma */ | ||
604 | i++; | ||
605 | } | ||
606 | } | ||
607 | vol->password[j] = 0; | ||
608 | } else { | ||
609 | vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL); | ||
610 | strcpy(vol->password, value); | ||
611 | } | ||
612 | } else if (strnicmp(data, "ip", 2) == 0) { | ||
613 | if (!value || !*value) { | ||
614 | vol->UNCip = NULL; | ||
615 | } else if (strnlen(value, 35) < 35) { | ||
616 | vol->UNCip = value; | ||
617 | } else { | ||
618 | printk(KERN_WARNING "CIFS: ip address too long\n"); | ||
619 | return 1; | ||
620 | } | ||
621 | } else if ((strnicmp(data, "unc", 3) == 0) | ||
622 | || (strnicmp(data, "target", 6) == 0) | ||
623 | || (strnicmp(data, "path", 4) == 0)) { | ||
624 | if (!value || !*value) { | ||
625 | printk(KERN_WARNING | ||
626 | "CIFS: invalid path to network resource\n"); | ||
627 | return 1; /* needs_arg; */ | ||
628 | } | ||
629 | if ((temp_len = strnlen(value, 300)) < 300) { | ||
630 | vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); | ||
631 | if(vol->UNC == NULL) | ||
632 | return 1; | ||
633 | strcpy(vol->UNC,value); | ||
634 | if (strncmp(vol->UNC, "//", 2) == 0) { | ||
635 | vol->UNC[0] = '\\'; | ||
636 | vol->UNC[1] = '\\'; | ||
637 | } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { | ||
638 | printk(KERN_WARNING | ||
639 | "CIFS: UNC Path does not begin with // or \\\\ \n"); | ||
640 | return 1; | ||
641 | } | ||
642 | } else { | ||
643 | printk(KERN_WARNING "CIFS: UNC name too long\n"); | ||
644 | return 1; | ||
645 | } | ||
646 | } else if ((strnicmp(data, "domain", 3) == 0) | ||
647 | || (strnicmp(data, "workgroup", 5) == 0)) { | ||
648 | if (!value || !*value) { | ||
649 | printk(KERN_WARNING "CIFS: invalid domain name\n"); | ||
650 | return 1; /* needs_arg; */ | ||
651 | } | ||
652 | /* BB are there cases in which a comma can be valid in | ||
653 | a domain name and need special handling? */ | ||
654 | if (strnlen(value, 65) < 65) { | ||
655 | vol->domainname = value; | ||
656 | cFYI(1, ("Domain name set")); | ||
657 | } else { | ||
658 | printk(KERN_WARNING "CIFS: domain name too long\n"); | ||
659 | return 1; | ||
660 | } | ||
661 | } else if (strnicmp(data, "iocharset", 9) == 0) { | ||
662 | if (!value || !*value) { | ||
663 | printk(KERN_WARNING "CIFS: invalid iocharset specified\n"); | ||
664 | return 1; /* needs_arg; */ | ||
665 | } | ||
666 | if (strnlen(value, 65) < 65) { | ||
667 | if(strnicmp(value,"default",7)) | ||
668 | vol->iocharset = value; | ||
669 | /* if iocharset not set load_nls_default used by caller */ | ||
670 | cFYI(1, ("iocharset set to %s",value)); | ||
671 | } else { | ||
672 | printk(KERN_WARNING "CIFS: iocharset name too long.\n"); | ||
673 | return 1; | ||
674 | } | ||
675 | } else if (strnicmp(data, "uid", 3) == 0) { | ||
676 | if (value && *value) { | ||
677 | vol->linux_uid = | ||
678 | simple_strtoul(value, &value, 0); | ||
679 | } | ||
680 | } else if (strnicmp(data, "gid", 3) == 0) { | ||
681 | if (value && *value) { | ||
682 | vol->linux_gid = | ||
683 | simple_strtoul(value, &value, 0); | ||
684 | } | ||
685 | } else if (strnicmp(data, "file_mode", 4) == 0) { | ||
686 | if (value && *value) { | ||
687 | vol->file_mode = | ||
688 | simple_strtoul(value, &value, 0); | ||
689 | } | ||
690 | } else if (strnicmp(data, "dir_mode", 4) == 0) { | ||
691 | if (value && *value) { | ||
692 | vol->dir_mode = | ||
693 | simple_strtoul(value, &value, 0); | ||
694 | } | ||
695 | } else if (strnicmp(data, "dirmode", 4) == 0) { | ||
696 | if (value && *value) { | ||
697 | vol->dir_mode = | ||
698 | simple_strtoul(value, &value, 0); | ||
699 | } | ||
700 | } else if (strnicmp(data, "port", 4) == 0) { | ||
701 | if (value && *value) { | ||
702 | vol->port = | ||
703 | simple_strtoul(value, &value, 0); | ||
704 | } | ||
705 | } else if (strnicmp(data, "rsize", 5) == 0) { | ||
706 | if (value && *value) { | ||
707 | vol->rsize = | ||
708 | simple_strtoul(value, &value, 0); | ||
709 | } | ||
710 | } else if (strnicmp(data, "wsize", 5) == 0) { | ||
711 | if (value && *value) { | ||
712 | vol->wsize = | ||
713 | simple_strtoul(value, &value, 0); | ||
714 | } | ||
715 | } else if (strnicmp(data, "sockopt", 5) == 0) { | ||
716 | if (value && *value) { | ||
717 | vol->sockopt = | ||
718 | simple_strtoul(value, &value, 0); | ||
719 | } | ||
720 | } else if (strnicmp(data, "netbiosname", 4) == 0) { | ||
721 | if (!value || !*value || (*value == ' ')) { | ||
722 | cFYI(1,("invalid (empty) netbiosname specified")); | ||
723 | } else { | ||
724 | memset(vol->source_rfc1001_name,0x20,15); | ||
725 | for(i=0;i<15;i++) { | ||
726 | /* BB are there cases in which a comma can be | ||
727 | valid in this workstation netbios name (and need | ||
728 | special handling)? */ | ||
729 | |||
730 | /* We do not uppercase netbiosname for user */ | ||
731 | if (value[i]==0) | ||
732 | break; | ||
733 | else | ||
734 | vol->source_rfc1001_name[i] = value[i]; | ||
735 | } | ||
736 | /* The string has 16th byte zero still from | ||
737 | set at top of the function */ | ||
738 | if((i==15) && (value[i] != 0)) | ||
739 | printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n"); | ||
740 | } | ||
741 | } else if (strnicmp(data, "credentials", 4) == 0) { | ||
742 | /* ignore */ | ||
743 | } else if (strnicmp(data, "version", 3) == 0) { | ||
744 | /* ignore */ | ||
745 | } else if (strnicmp(data, "guest",5) == 0) { | ||
746 | /* ignore */ | ||
747 | } else if (strnicmp(data, "rw", 2) == 0) { | ||
748 | vol->rw = TRUE; | ||
749 | } else if ((strnicmp(data, "suid", 4) == 0) || | ||
750 | (strnicmp(data, "nosuid", 6) == 0) || | ||
751 | (strnicmp(data, "exec", 4) == 0) || | ||
752 | (strnicmp(data, "noexec", 6) == 0) || | ||
753 | (strnicmp(data, "nodev", 5) == 0) || | ||
754 | (strnicmp(data, "noauto", 6) == 0) || | ||
755 | (strnicmp(data, "dev", 3) == 0)) { | ||
756 | /* The mount tool or mount.cifs helper (if present) | ||
757 | uses these opts to set flags, and the flags are read | ||
758 | by the kernel vfs layer before we get here (ie | ||
759 | before read super) so there is no point trying to | ||
760 | parse these options again and set anything and it | ||
761 | is ok to just ignore them */ | ||
762 | continue; | ||
763 | } else if (strnicmp(data, "ro", 2) == 0) { | ||
764 | vol->rw = FALSE; | ||
765 | } else if (strnicmp(data, "hard", 4) == 0) { | ||
766 | vol->retry = 1; | ||
767 | } else if (strnicmp(data, "soft", 4) == 0) { | ||
768 | vol->retry = 0; | ||
769 | } else if (strnicmp(data, "perm", 4) == 0) { | ||
770 | vol->noperm = 0; | ||
771 | } else if (strnicmp(data, "noperm", 6) == 0) { | ||
772 | vol->noperm = 1; | ||
773 | } else if (strnicmp(data, "setuids", 7) == 0) { | ||
774 | vol->setuids = 1; | ||
775 | } else if (strnicmp(data, "nosetuids", 9) == 0) { | ||
776 | vol->setuids = 0; | ||
777 | } else if (strnicmp(data, "nohard", 6) == 0) { | ||
778 | vol->retry = 0; | ||
779 | } else if (strnicmp(data, "nosoft", 6) == 0) { | ||
780 | vol->retry = 1; | ||
781 | } else if (strnicmp(data, "nointr", 6) == 0) { | ||
782 | vol->intr = 0; | ||
783 | } else if (strnicmp(data, "intr", 4) == 0) { | ||
784 | vol->intr = 1; | ||
785 | } else if (strnicmp(data, "serverino",7) == 0) { | ||
786 | vol->server_ino = 1; | ||
787 | } else if (strnicmp(data, "noserverino",9) == 0) { | ||
788 | vol->server_ino = 0; | ||
789 | } else if (strnicmp(data, "acl",3) == 0) { | ||
790 | vol->no_psx_acl = 0; | ||
791 | } else if (strnicmp(data, "noacl",5) == 0) { | ||
792 | vol->no_psx_acl = 1; | ||
793 | } else if (strnicmp(data, "direct",6) == 0) { | ||
794 | vol->direct_io = 1; | ||
795 | } else if (strnicmp(data, "forcedirectio",13) == 0) { | ||
796 | vol->direct_io = 1; | ||
797 | } else if (strnicmp(data, "in6_addr",8) == 0) { | ||
798 | if (!value || !*value) { | ||
799 | vol->in6_addr = NULL; | ||
800 | } else if (strnlen(value, 49) == 48) { | ||
801 | vol->in6_addr = value; | ||
802 | } else { | ||
803 | printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n"); | ||
804 | return 1; | ||
805 | } | ||
806 | } else if (strnicmp(data, "noac", 4) == 0) { | ||
807 | printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); | ||
808 | } else | ||
809 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); | ||
810 | } | ||
811 | if (vol->UNC == NULL) { | ||
812 | if(devname == NULL) { | ||
813 | printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n"); | ||
814 | return 1; | ||
815 | } | ||
816 | if ((temp_len = strnlen(devname, 300)) < 300) { | ||
817 | vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); | ||
818 | if(vol->UNC == NULL) | ||
819 | return 1; | ||
820 | strcpy(vol->UNC,devname); | ||
821 | if (strncmp(vol->UNC, "//", 2) == 0) { | ||
822 | vol->UNC[0] = '\\'; | ||
823 | vol->UNC[1] = '\\'; | ||
824 | } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { | ||
825 | printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n"); | ||
826 | return 1; | ||
827 | } | ||
828 | } else { | ||
829 | printk(KERN_WARNING "CIFS: UNC name too long\n"); | ||
830 | return 1; | ||
831 | } | ||
832 | } | ||
833 | if(vol->UNCip == NULL) | ||
834 | vol->UNCip = &vol->UNC[2]; | ||
835 | |||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | static struct cifsSesInfo * | ||
840 | cifs_find_tcp_session(struct in_addr * target_ip_addr, | ||
841 | struct in6_addr *target_ip6_addr, | ||
842 | char *userName, struct TCP_Server_Info **psrvTcp) | ||
843 | { | ||
844 | struct list_head *tmp; | ||
845 | struct cifsSesInfo *ses; | ||
846 | *psrvTcp = NULL; | ||
847 | read_lock(&GlobalSMBSeslock); | ||
848 | |||
849 | list_for_each(tmp, &GlobalSMBSessionList) { | ||
850 | ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); | ||
851 | if (ses->server) { | ||
852 | if((target_ip_addr && | ||
853 | (ses->server->addr.sockAddr.sin_addr.s_addr | ||
854 | == target_ip_addr->s_addr)) || (target_ip6_addr | ||
855 | && memcmp(&ses->server->addr.sockAddr6.sin6_addr, | ||
856 | target_ip6_addr,sizeof(*target_ip6_addr)))){ | ||
857 | /* BB lock server and tcp session and increment use count here?? */ | ||
858 | *psrvTcp = ses->server; /* found a match on the TCP session */ | ||
859 | /* BB check if reconnection needed */ | ||
860 | if (strncmp | ||
861 | (ses->userName, userName, | ||
862 | MAX_USERNAME_SIZE) == 0){ | ||
863 | read_unlock(&GlobalSMBSeslock); | ||
864 | return ses; /* found exact match on both tcp and SMB sessions */ | ||
865 | } | ||
866 | } | ||
867 | } | ||
868 | /* else tcp and smb sessions need reconnection */ | ||
869 | } | ||
870 | read_unlock(&GlobalSMBSeslock); | ||
871 | return NULL; | ||
872 | } | ||
873 | |||
874 | static struct cifsTconInfo * | ||
875 | find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) | ||
876 | { | ||
877 | struct list_head *tmp; | ||
878 | struct cifsTconInfo *tcon; | ||
879 | |||
880 | read_lock(&GlobalSMBSeslock); | ||
881 | list_for_each(tmp, &GlobalTreeConnectionList) { | ||
882 | cFYI(1, ("Next tcon - ")); | ||
883 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | ||
884 | if (tcon->ses) { | ||
885 | if (tcon->ses->server) { | ||
886 | cFYI(1, | ||
887 | (" old ip addr: %x == new ip %x ?", | ||
888 | tcon->ses->server->addr.sockAddr.sin_addr. | ||
889 | s_addr, new_target_ip_addr)); | ||
890 | if (tcon->ses->server->addr.sockAddr.sin_addr. | ||
891 | s_addr == new_target_ip_addr) { | ||
892 | /* BB lock tcon and server and tcp session and increment use count here? */ | ||
893 | /* found a match on the TCP session */ | ||
894 | /* BB check if reconnection needed */ | ||
895 | cFYI(1,("Matched ip, old UNC: %s == new: %s ?", | ||
896 | tcon->treeName, uncName)); | ||
897 | if (strncmp | ||
898 | (tcon->treeName, uncName, | ||
899 | MAX_TREE_SIZE) == 0) { | ||
900 | cFYI(1, | ||
901 | ("Matched UNC, old user: %s == new: %s ?", | ||
902 | tcon->treeName, uncName)); | ||
903 | if (strncmp | ||
904 | (tcon->ses->userName, | ||
905 | userName, | ||
906 | MAX_USERNAME_SIZE) == 0) { | ||
907 | read_unlock(&GlobalSMBSeslock); | ||
908 | return tcon;/* also matched user (smb session)*/ | ||
909 | } | ||
910 | } | ||
911 | } | ||
912 | } | ||
913 | } | ||
914 | } | ||
915 | read_unlock(&GlobalSMBSeslock); | ||
916 | return NULL; | ||
917 | } | ||
918 | |||
919 | int | ||
920 | connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | ||
921 | const char *old_path, const struct nls_table *nls_codepage) | ||
922 | { | ||
923 | unsigned char *referrals = NULL; | ||
924 | unsigned int num_referrals; | ||
925 | int rc = 0; | ||
926 | |||
927 | rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, | ||
928 | &num_referrals, &referrals); | ||
929 | |||
930 | /* BB Add in code to: if valid refrl, if not ip address contact | ||
931 | the helper that resolves tcp names, mount to it, try to | ||
932 | tcon to it unmount it if fail */ | ||
933 | |||
934 | if(referrals) | ||
935 | kfree(referrals); | ||
936 | |||
937 | return rc; | ||
938 | } | ||
939 | |||
940 | int | ||
941 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | ||
942 | const char *old_path, const struct nls_table *nls_codepage, | ||
943 | unsigned int *pnum_referrals, unsigned char ** preferrals) | ||
944 | { | ||
945 | char *temp_unc; | ||
946 | int rc = 0; | ||
947 | |||
948 | *pnum_referrals = 0; | ||
949 | |||
950 | if (pSesInfo->ipc_tid == 0) { | ||
951 | temp_unc = kmalloc(2 /* for slashes */ + | ||
952 | strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2) | ||
953 | + 1 + 4 /* slash IPC$ */ + 2, | ||
954 | GFP_KERNEL); | ||
955 | if (temp_unc == NULL) | ||
956 | return -ENOMEM; | ||
957 | temp_unc[0] = '\\'; | ||
958 | temp_unc[1] = '\\'; | ||
959 | strcpy(temp_unc + 2, pSesInfo->serverName); | ||
960 | strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$"); | ||
961 | rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage); | ||
962 | cFYI(1, | ||
963 | ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid)); | ||
964 | kfree(temp_unc); | ||
965 | } | ||
966 | if (rc == 0) | ||
967 | rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, | ||
968 | pnum_referrals, nls_codepage); | ||
969 | |||
970 | return rc; | ||
971 | } | ||
972 | |||
973 | /* See RFC1001 section 14 on representation of Netbios names */ | ||
974 | static void rfc1002mangle(char * target,char * source, unsigned int length) | ||
975 | { | ||
976 | unsigned int i,j; | ||
977 | |||
978 | for(i=0,j=0;i<(length);i++) { | ||
979 | /* mask a nibble at a time and encode */ | ||
980 | target[j] = 'A' + (0x0F & (source[i] >> 4)); | ||
981 | target[j+1] = 'A' + (0x0F & source[i]); | ||
982 | j+=2; | ||
983 | } | ||
984 | |||
985 | } | ||
986 | |||
987 | |||
988 | static int | ||
989 | ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | ||
990 | char * netbios_name) | ||
991 | { | ||
992 | int rc = 0; | ||
993 | int connected = 0; | ||
994 | __be16 orig_port = 0; | ||
995 | |||
996 | if(*csocket == NULL) { | ||
997 | rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket); | ||
998 | if (rc < 0) { | ||
999 | cERROR(1, ("Error %d creating socket",rc)); | ||
1000 | *csocket = NULL; | ||
1001 | return rc; | ||
1002 | } else { | ||
1003 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | ||
1004 | cFYI(1,("Socket created")); | ||
1005 | (*csocket)->sk->sk_allocation = GFP_NOFS; | ||
1006 | } | ||
1007 | } | ||
1008 | |||
1009 | psin_server->sin_family = AF_INET; | ||
1010 | if(psin_server->sin_port) { /* user overrode default port */ | ||
1011 | rc = (*csocket)->ops->connect(*csocket, | ||
1012 | (struct sockaddr *) psin_server, | ||
1013 | sizeof (struct sockaddr_in),0); | ||
1014 | if (rc >= 0) | ||
1015 | connected = 1; | ||
1016 | } | ||
1017 | |||
1018 | if(!connected) { | ||
1019 | /* save original port so we can retry user specified port | ||
1020 | later if fall back ports fail this time */ | ||
1021 | orig_port = psin_server->sin_port; | ||
1022 | |||
1023 | /* do not retry on the same port we just failed on */ | ||
1024 | if(psin_server->sin_port != htons(CIFS_PORT)) { | ||
1025 | psin_server->sin_port = htons(CIFS_PORT); | ||
1026 | |||
1027 | rc = (*csocket)->ops->connect(*csocket, | ||
1028 | (struct sockaddr *) psin_server, | ||
1029 | sizeof (struct sockaddr_in),0); | ||
1030 | if (rc >= 0) | ||
1031 | connected = 1; | ||
1032 | } | ||
1033 | } | ||
1034 | if (!connected) { | ||
1035 | psin_server->sin_port = htons(RFC1001_PORT); | ||
1036 | rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) | ||
1037 | psin_server, sizeof (struct sockaddr_in),0); | ||
1038 | if (rc >= 0) | ||
1039 | connected = 1; | ||
1040 | } | ||
1041 | |||
1042 | /* give up here - unless we want to retry on different | ||
1043 | protocol families some day */ | ||
1044 | if (!connected) { | ||
1045 | if(orig_port) | ||
1046 | psin_server->sin_port = orig_port; | ||
1047 | cFYI(1,("Error %d connecting to server via ipv4",rc)); | ||
1048 | sock_release(*csocket); | ||
1049 | *csocket = NULL; | ||
1050 | return rc; | ||
1051 | } | ||
1052 | /* Eventually check for other socket options to change from | ||
1053 | the default. sock_setsockopt not used because it expects | ||
1054 | user space buffer */ | ||
1055 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; | ||
1056 | |||
1057 | /* send RFC1001 sessinit */ | ||
1058 | |||
1059 | if(psin_server->sin_port == htons(RFC1001_PORT)) { | ||
1060 | /* some servers require RFC1001 sessinit before sending | ||
1061 | negprot - BB check reconnection in case where second | ||
1062 | sessinit is sent but no second negprot */ | ||
1063 | struct rfc1002_session_packet * ses_init_buf; | ||
1064 | struct smb_hdr * smb_buf; | ||
1065 | ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); | ||
1066 | if(ses_init_buf) { | ||
1067 | ses_init_buf->trailer.session_req.called_len = 32; | ||
1068 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, | ||
1069 | DEFAULT_CIFS_CALLED_NAME,16); | ||
1070 | ses_init_buf->trailer.session_req.calling_len = 32; | ||
1071 | /* calling name ends in null (byte 16) from old smb | ||
1072 | convention. */ | ||
1073 | if(netbios_name && (netbios_name[0] !=0)) { | ||
1074 | rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, | ||
1075 | netbios_name,16); | ||
1076 | } else { | ||
1077 | rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, | ||
1078 | "LINUX_CIFS_CLNT",16); | ||
1079 | } | ||
1080 | ses_init_buf->trailer.session_req.scope1 = 0; | ||
1081 | ses_init_buf->trailer.session_req.scope2 = 0; | ||
1082 | smb_buf = (struct smb_hdr *)ses_init_buf; | ||
1083 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | ||
1084 | smb_buf->smb_buf_length = 0x81000044; | ||
1085 | rc = smb_send(*csocket, smb_buf, 0x44, | ||
1086 | (struct sockaddr *)psin_server); | ||
1087 | kfree(ses_init_buf); | ||
1088 | } | ||
1089 | /* else the negprot may still work without this | ||
1090 | even though malloc failed */ | ||
1091 | |||
1092 | } | ||
1093 | |||
1094 | return rc; | ||
1095 | } | ||
1096 | |||
1097 | static int | ||
1098 | ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) | ||
1099 | { | ||
1100 | int rc = 0; | ||
1101 | int connected = 0; | ||
1102 | __be16 orig_port = 0; | ||
1103 | |||
1104 | if(*csocket == NULL) { | ||
1105 | rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket); | ||
1106 | if (rc < 0) { | ||
1107 | cERROR(1, ("Error %d creating ipv6 socket",rc)); | ||
1108 | *csocket = NULL; | ||
1109 | return rc; | ||
1110 | } else { | ||
1111 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | ||
1112 | cFYI(1,("ipv6 Socket created")); | ||
1113 | (*csocket)->sk->sk_allocation = GFP_NOFS; | ||
1114 | } | ||
1115 | } | ||
1116 | |||
1117 | psin_server->sin6_family = AF_INET6; | ||
1118 | |||
1119 | if(psin_server->sin6_port) { /* user overrode default port */ | ||
1120 | rc = (*csocket)->ops->connect(*csocket, | ||
1121 | (struct sockaddr *) psin_server, | ||
1122 | sizeof (struct sockaddr_in6),0); | ||
1123 | if (rc >= 0) | ||
1124 | connected = 1; | ||
1125 | } | ||
1126 | |||
1127 | if(!connected) { | ||
1128 | /* save original port so we can retry user specified port | ||
1129 | later if fall back ports fail this time */ | ||
1130 | |||
1131 | orig_port = psin_server->sin6_port; | ||
1132 | /* do not retry on the same port we just failed on */ | ||
1133 | if(psin_server->sin6_port != htons(CIFS_PORT)) { | ||
1134 | psin_server->sin6_port = htons(CIFS_PORT); | ||
1135 | |||
1136 | rc = (*csocket)->ops->connect(*csocket, | ||
1137 | (struct sockaddr *) psin_server, | ||
1138 | sizeof (struct sockaddr_in6),0); | ||
1139 | if (rc >= 0) | ||
1140 | connected = 1; | ||
1141 | } | ||
1142 | } | ||
1143 | if (!connected) { | ||
1144 | psin_server->sin6_port = htons(RFC1001_PORT); | ||
1145 | rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) | ||
1146 | psin_server, sizeof (struct sockaddr_in6),0); | ||
1147 | if (rc >= 0) | ||
1148 | connected = 1; | ||
1149 | } | ||
1150 | |||
1151 | /* give up here - unless we want to retry on different | ||
1152 | protocol families some day */ | ||
1153 | if (!connected) { | ||
1154 | if(orig_port) | ||
1155 | psin_server->sin6_port = orig_port; | ||
1156 | cFYI(1,("Error %d connecting to server via ipv6",rc)); | ||
1157 | sock_release(*csocket); | ||
1158 | *csocket = NULL; | ||
1159 | return rc; | ||
1160 | } | ||
1161 | /* Eventually check for other socket options to change from | ||
1162 | the default. sock_setsockopt not used because it expects | ||
1163 | user space buffer */ | ||
1164 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; | ||
1165 | |||
1166 | return rc; | ||
1167 | } | ||
1168 | |||
1169 | int | ||
1170 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | ||
1171 | char *mount_data, const char *devname) | ||
1172 | { | ||
1173 | int rc = 0; | ||
1174 | int xid; | ||
1175 | int address_type = AF_INET; | ||
1176 | struct socket *csocket = NULL; | ||
1177 | struct sockaddr_in sin_server; | ||
1178 | struct sockaddr_in6 sin_server6; | ||
1179 | struct smb_vol volume_info; | ||
1180 | struct cifsSesInfo *pSesInfo = NULL; | ||
1181 | struct cifsSesInfo *existingCifsSes = NULL; | ||
1182 | struct cifsTconInfo *tcon = NULL; | ||
1183 | struct TCP_Server_Info *srvTcp = NULL; | ||
1184 | |||
1185 | xid = GetXid(); | ||
1186 | |||
1187 | /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ | ||
1188 | |||
1189 | memset(&volume_info,0,sizeof(struct smb_vol)); | ||
1190 | if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { | ||
1191 | if(volume_info.UNC) | ||
1192 | kfree(volume_info.UNC); | ||
1193 | if(volume_info.password) | ||
1194 | kfree(volume_info.password); | ||
1195 | FreeXid(xid); | ||
1196 | return -EINVAL; | ||
1197 | } | ||
1198 | |||
1199 | if (volume_info.username) { | ||
1200 | /* BB fixme parse for domain name here */ | ||
1201 | cFYI(1, ("Username: %s ", volume_info.username)); | ||
1202 | |||
1203 | } else { | ||
1204 | cifserror("No username specified "); | ||
1205 | /* In userspace mount helper we can get user name from alternate | ||
1206 | locations such as env variables and files on disk */ | ||
1207 | if(volume_info.UNC) | ||
1208 | kfree(volume_info.UNC); | ||
1209 | if(volume_info.password) | ||
1210 | kfree(volume_info.password); | ||
1211 | FreeXid(xid); | ||
1212 | return -EINVAL; | ||
1213 | } | ||
1214 | |||
1215 | if (volume_info.UNCip && volume_info.UNC) { | ||
1216 | rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr); | ||
1217 | |||
1218 | if(rc <= 0) { | ||
1219 | /* not ipv4 address, try ipv6 */ | ||
1220 | rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); | ||
1221 | if(rc > 0) | ||
1222 | address_type = AF_INET6; | ||
1223 | } else { | ||
1224 | address_type = AF_INET; | ||
1225 | } | ||
1226 | |||
1227 | if(rc <= 0) { | ||
1228 | /* we failed translating address */ | ||
1229 | if(volume_info.UNC) | ||
1230 | kfree(volume_info.UNC); | ||
1231 | if(volume_info.password) | ||
1232 | kfree(volume_info.password); | ||
1233 | FreeXid(xid); | ||
1234 | return -EINVAL; | ||
1235 | } | ||
1236 | |||
1237 | cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); | ||
1238 | /* success */ | ||
1239 | rc = 0; | ||
1240 | } else if (volume_info.UNCip){ | ||
1241 | /* BB using ip addr as server name connect to the DFS root below */ | ||
1242 | cERROR(1,("Connecting to DFS root not implemented yet")); | ||
1243 | if(volume_info.UNC) | ||
1244 | kfree(volume_info.UNC); | ||
1245 | if(volume_info.password) | ||
1246 | kfree(volume_info.password); | ||
1247 | FreeXid(xid); | ||
1248 | return -EINVAL; | ||
1249 | } else /* which servers DFS root would we conect to */ { | ||
1250 | cERROR(1, | ||
1251 | ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); | ||
1252 | if(volume_info.UNC) | ||
1253 | kfree(volume_info.UNC); | ||
1254 | if(volume_info.password) | ||
1255 | kfree(volume_info.password); | ||
1256 | FreeXid(xid); | ||
1257 | return -EINVAL; | ||
1258 | } | ||
1259 | |||
1260 | /* this is needed for ASCII cp to Unicode converts */ | ||
1261 | if(volume_info.iocharset == NULL) { | ||
1262 | cifs_sb->local_nls = load_nls_default(); | ||
1263 | /* load_nls_default can not return null */ | ||
1264 | } else { | ||
1265 | cifs_sb->local_nls = load_nls(volume_info.iocharset); | ||
1266 | if(cifs_sb->local_nls == NULL) { | ||
1267 | cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); | ||
1268 | if(volume_info.UNC) | ||
1269 | kfree(volume_info.UNC); | ||
1270 | if(volume_info.password) | ||
1271 | kfree(volume_info.password); | ||
1272 | FreeXid(xid); | ||
1273 | return -ELIBACC; | ||
1274 | } | ||
1275 | } | ||
1276 | |||
1277 | if(address_type == AF_INET) | ||
1278 | existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr, | ||
1279 | NULL /* no ipv6 addr */, | ||
1280 | volume_info.username, &srvTcp); | ||
1281 | else if(address_type == AF_INET6) | ||
1282 | existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */, | ||
1283 | &sin_server6.sin6_addr, | ||
1284 | volume_info.username, &srvTcp); | ||
1285 | else { | ||
1286 | if(volume_info.UNC) | ||
1287 | kfree(volume_info.UNC); | ||
1288 | if(volume_info.password) | ||
1289 | kfree(volume_info.password); | ||
1290 | FreeXid(xid); | ||
1291 | return -EINVAL; | ||
1292 | } | ||
1293 | |||
1294 | |||
1295 | if (srvTcp) { | ||
1296 | cFYI(1, ("Existing tcp session with server found ")); | ||
1297 | } else { /* create socket */ | ||
1298 | if(volume_info.port) | ||
1299 | sin_server.sin_port = htons(volume_info.port); | ||
1300 | else | ||
1301 | sin_server.sin_port = 0; | ||
1302 | rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name); | ||
1303 | if (rc < 0) { | ||
1304 | cERROR(1, | ||
1305 | ("Error connecting to IPv4 socket. Aborting operation")); | ||
1306 | if(csocket != NULL) | ||
1307 | sock_release(csocket); | ||
1308 | if(volume_info.UNC) | ||
1309 | kfree(volume_info.UNC); | ||
1310 | if(volume_info.password) | ||
1311 | kfree(volume_info.password); | ||
1312 | FreeXid(xid); | ||
1313 | return rc; | ||
1314 | } | ||
1315 | |||
1316 | srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL); | ||
1317 | if (srvTcp == NULL) { | ||
1318 | rc = -ENOMEM; | ||
1319 | sock_release(csocket); | ||
1320 | if(volume_info.UNC) | ||
1321 | kfree(volume_info.UNC); | ||
1322 | if(volume_info.password) | ||
1323 | kfree(volume_info.password); | ||
1324 | FreeXid(xid); | ||
1325 | return rc; | ||
1326 | } else { | ||
1327 | memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); | ||
1328 | memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in)); | ||
1329 | atomic_set(&srvTcp->inFlight,0); | ||
1330 | /* BB Add code for ipv6 case too */ | ||
1331 | srvTcp->ssocket = csocket; | ||
1332 | srvTcp->protocolType = IPV4; | ||
1333 | init_waitqueue_head(&srvTcp->response_q); | ||
1334 | init_waitqueue_head(&srvTcp->request_q); | ||
1335 | INIT_LIST_HEAD(&srvTcp->pending_mid_q); | ||
1336 | /* at this point we are the only ones with the pointer | ||
1337 | to the struct since the kernel thread not created yet | ||
1338 | so no need to spinlock this init of tcpStatus */ | ||
1339 | srvTcp->tcpStatus = CifsNew; | ||
1340 | init_MUTEX(&srvTcp->tcpSem); | ||
1341 | rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp, | ||
1342 | CLONE_FS | CLONE_FILES | CLONE_VM); | ||
1343 | if(rc < 0) { | ||
1344 | rc = -ENOMEM; | ||
1345 | sock_release(csocket); | ||
1346 | if(volume_info.UNC) | ||
1347 | kfree(volume_info.UNC); | ||
1348 | if(volume_info.password) | ||
1349 | kfree(volume_info.password); | ||
1350 | FreeXid(xid); | ||
1351 | return rc; | ||
1352 | } else | ||
1353 | rc = 0; | ||
1354 | memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); | ||
1355 | } | ||
1356 | } | ||
1357 | |||
1358 | if (existingCifsSes) { | ||
1359 | pSesInfo = existingCifsSes; | ||
1360 | cFYI(1, ("Existing smb sess found ")); | ||
1361 | if(volume_info.password) | ||
1362 | kfree(volume_info.password); | ||
1363 | /* volume_info.UNC freed at end of function */ | ||
1364 | } else if (!rc) { | ||
1365 | cFYI(1, ("Existing smb sess not found ")); | ||
1366 | pSesInfo = sesInfoAlloc(); | ||
1367 | if (pSesInfo == NULL) | ||
1368 | rc = -ENOMEM; | ||
1369 | else { | ||
1370 | pSesInfo->server = srvTcp; | ||
1371 | sprintf(pSesInfo->serverName, "%u.%u.%u.%u", | ||
1372 | NIPQUAD(sin_server.sin_addr.s_addr)); | ||
1373 | } | ||
1374 | |||
1375 | if (!rc){ | ||
1376 | /* volume_info.password freed at unmount */ | ||
1377 | if (volume_info.password) | ||
1378 | pSesInfo->password = volume_info.password; | ||
1379 | if (volume_info.username) | ||
1380 | strncpy(pSesInfo->userName, | ||
1381 | volume_info.username,MAX_USERNAME_SIZE); | ||
1382 | if (volume_info.domainname) | ||
1383 | strncpy(pSesInfo->domainName, | ||
1384 | volume_info.domainname,MAX_USERNAME_SIZE); | ||
1385 | pSesInfo->linux_uid = volume_info.linux_uid; | ||
1386 | down(&pSesInfo->sesSem); | ||
1387 | rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); | ||
1388 | up(&pSesInfo->sesSem); | ||
1389 | if(!rc) | ||
1390 | atomic_inc(&srvTcp->socketUseCount); | ||
1391 | } else | ||
1392 | if(volume_info.password) | ||
1393 | kfree(volume_info.password); | ||
1394 | } | ||
1395 | |||
1396 | /* search for existing tcon to this server share */ | ||
1397 | if (!rc) { | ||
1398 | if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) | ||
1399 | cifs_sb->rsize = volume_info.rsize; | ||
1400 | else | ||
1401 | cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ | ||
1402 | if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize)) | ||
1403 | cifs_sb->wsize = volume_info.wsize; | ||
1404 | else | ||
1405 | cifs_sb->wsize = CIFSMaxBufSize; /* default */ | ||
1406 | if(cifs_sb->rsize < PAGE_CACHE_SIZE) { | ||
1407 | cifs_sb->rsize = PAGE_CACHE_SIZE; | ||
1408 | cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); | ||
1409 | } | ||
1410 | cifs_sb->mnt_uid = volume_info.linux_uid; | ||
1411 | cifs_sb->mnt_gid = volume_info.linux_gid; | ||
1412 | cifs_sb->mnt_file_mode = volume_info.file_mode; | ||
1413 | cifs_sb->mnt_dir_mode = volume_info.dir_mode; | ||
1414 | cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); | ||
1415 | |||
1416 | if(volume_info.noperm) | ||
1417 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; | ||
1418 | if(volume_info.setuids) | ||
1419 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; | ||
1420 | if(volume_info.server_ino) | ||
1421 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; | ||
1422 | if(volume_info.no_xattr) | ||
1423 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; | ||
1424 | if(volume_info.direct_io) { | ||
1425 | cERROR(1,("mounting share using direct i/o")); | ||
1426 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | ||
1427 | } | ||
1428 | |||
1429 | tcon = | ||
1430 | find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, | ||
1431 | volume_info.username); | ||
1432 | if (tcon) { | ||
1433 | cFYI(1, ("Found match on UNC path ")); | ||
1434 | /* we can have only one retry value for a connection | ||
1435 | to a share so for resources mounted more than once | ||
1436 | to the same server share the last value passed in | ||
1437 | for the retry flag is used */ | ||
1438 | tcon->retry = volume_info.retry; | ||
1439 | } else { | ||
1440 | tcon = tconInfoAlloc(); | ||
1441 | if (tcon == NULL) | ||
1442 | rc = -ENOMEM; | ||
1443 | else { | ||
1444 | /* check for null share name ie connect to dfs root */ | ||
1445 | |||
1446 | /* BB check if this works for exactly length three strings */ | ||
1447 | if ((strchr(volume_info.UNC + 3, '\\') == NULL) | ||
1448 | && (strchr(volume_info.UNC + 3, '/') == | ||
1449 | NULL)) { | ||
1450 | rc = connect_to_dfs_path(xid, | ||
1451 | pSesInfo, | ||
1452 | "", | ||
1453 | cifs_sb-> | ||
1454 | local_nls); | ||
1455 | if(volume_info.UNC) | ||
1456 | kfree(volume_info.UNC); | ||
1457 | FreeXid(xid); | ||
1458 | return -ENODEV; | ||
1459 | } else { | ||
1460 | rc = CIFSTCon(xid, pSesInfo, | ||
1461 | volume_info.UNC, | ||
1462 | tcon, cifs_sb->local_nls); | ||
1463 | cFYI(1, ("CIFS Tcon rc = %d", rc)); | ||
1464 | } | ||
1465 | if (!rc) { | ||
1466 | atomic_inc(&pSesInfo->inUse); | ||
1467 | tcon->retry = volume_info.retry; | ||
1468 | } | ||
1469 | } | ||
1470 | } | ||
1471 | } | ||
1472 | if(pSesInfo) { | ||
1473 | if (pSesInfo->capabilities & CAP_LARGE_FILES) { | ||
1474 | sb->s_maxbytes = (u64) 1 << 63; | ||
1475 | } else | ||
1476 | sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */ | ||
1477 | } | ||
1478 | |||
1479 | sb->s_time_gran = 100; | ||
1480 | |||
1481 | /* on error free sesinfo and tcon struct if needed */ | ||
1482 | if (rc) { | ||
1483 | /* if session setup failed, use count is zero but | ||
1484 | we still need to free cifsd thread */ | ||
1485 | if(atomic_read(&srvTcp->socketUseCount) == 0) { | ||
1486 | spin_lock(&GlobalMid_Lock); | ||
1487 | srvTcp->tcpStatus = CifsExiting; | ||
1488 | spin_unlock(&GlobalMid_Lock); | ||
1489 | if(srvTcp->tsk) | ||
1490 | send_sig(SIGKILL,srvTcp->tsk,1); | ||
1491 | } | ||
1492 | /* If find_unc succeeded then rc == 0 so we can not end */ | ||
1493 | if (tcon) /* up accidently freeing someone elses tcon struct */ | ||
1494 | tconInfoFree(tcon); | ||
1495 | if (existingCifsSes == NULL) { | ||
1496 | if (pSesInfo) { | ||
1497 | if ((pSesInfo->server) && | ||
1498 | (pSesInfo->status == CifsGood)) { | ||
1499 | int temp_rc; | ||
1500 | temp_rc = CIFSSMBLogoff(xid, pSesInfo); | ||
1501 | /* if the socketUseCount is now zero */ | ||
1502 | if((temp_rc == -ESHUTDOWN) && | ||
1503 | (pSesInfo->server->tsk)) | ||
1504 | send_sig(SIGKILL,pSesInfo->server->tsk,1); | ||
1505 | } else | ||
1506 | cFYI(1, ("No session or bad tcon")); | ||
1507 | sesInfoFree(pSesInfo); | ||
1508 | /* pSesInfo = NULL; */ | ||
1509 | } | ||
1510 | } | ||
1511 | } else { | ||
1512 | atomic_inc(&tcon->useCount); | ||
1513 | cifs_sb->tcon = tcon; | ||
1514 | tcon->ses = pSesInfo; | ||
1515 | |||
1516 | /* do not care if following two calls succeed - informational only */ | ||
1517 | CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls); | ||
1518 | CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls); | ||
1519 | if (tcon->ses->capabilities & CAP_UNIX) { | ||
1520 | if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) { | ||
1521 | if(!volume_info.no_psx_acl) { | ||
1522 | if(CIFS_UNIX_POSIX_ACL_CAP & | ||
1523 | le64_to_cpu(tcon->fsUnixInfo.Capability)) | ||
1524 | cFYI(1,("server negotiated posix acl support")); | ||
1525 | sb->s_flags |= MS_POSIXACL; | ||
1526 | } | ||
1527 | } | ||
1528 | } | ||
1529 | } | ||
1530 | |||
1531 | /* volume_info.password is freed above when existing session found | ||
1532 | (in which case it is not needed anymore) but when new sesion is created | ||
1533 | the password ptr is put in the new session structure (in which case the | ||
1534 | password will be freed at unmount time) */ | ||
1535 | if(volume_info.UNC) | ||
1536 | kfree(volume_info.UNC); | ||
1537 | FreeXid(xid); | ||
1538 | return rc; | ||
1539 | } | ||
1540 | |||
1541 | static int | ||
1542 | CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
1543 | char session_key[CIFS_SESSION_KEY_SIZE], | ||
1544 | const struct nls_table *nls_codepage) | ||
1545 | { | ||
1546 | struct smb_hdr *smb_buffer; | ||
1547 | struct smb_hdr *smb_buffer_response; | ||
1548 | SESSION_SETUP_ANDX *pSMB; | ||
1549 | SESSION_SETUP_ANDX *pSMBr; | ||
1550 | char *bcc_ptr; | ||
1551 | char *user; | ||
1552 | char *domain; | ||
1553 | int rc = 0; | ||
1554 | int remaining_words = 0; | ||
1555 | int bytes_returned = 0; | ||
1556 | int len; | ||
1557 | __u32 capabilities; | ||
1558 | __u16 count; | ||
1559 | |||
1560 | cFYI(1, ("In sesssetup ")); | ||
1561 | if(ses == NULL) | ||
1562 | return -EINVAL; | ||
1563 | user = ses->userName; | ||
1564 | domain = ses->domainName; | ||
1565 | smb_buffer = cifs_buf_get(); | ||
1566 | if (smb_buffer == NULL) { | ||
1567 | return -ENOMEM; | ||
1568 | } | ||
1569 | smb_buffer_response = smb_buffer; | ||
1570 | pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
1571 | |||
1572 | /* send SMBsessionSetup here */ | ||
1573 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
1574 | NULL /* no tCon exists yet */ , 13 /* wct */ ); | ||
1575 | |||
1576 | pSMB->req_no_secext.AndXCommand = 0xFF; | ||
1577 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
1578 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
1579 | |||
1580 | if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
1581 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
1582 | |||
1583 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
1584 | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; | ||
1585 | if (ses->capabilities & CAP_UNICODE) { | ||
1586 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
1587 | capabilities |= CAP_UNICODE; | ||
1588 | } | ||
1589 | if (ses->capabilities & CAP_STATUS32) { | ||
1590 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
1591 | capabilities |= CAP_STATUS32; | ||
1592 | } | ||
1593 | if (ses->capabilities & CAP_DFS) { | ||
1594 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
1595 | capabilities |= CAP_DFS; | ||
1596 | } | ||
1597 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
1598 | |||
1599 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | ||
1600 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | ||
1601 | |||
1602 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
1603 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | ||
1604 | bcc_ptr = pByteArea(smb_buffer); | ||
1605 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); | ||
1606 | bcc_ptr += CIFS_SESSION_KEY_SIZE; | ||
1607 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); | ||
1608 | bcc_ptr += CIFS_SESSION_KEY_SIZE; | ||
1609 | |||
1610 | if (ses->capabilities & CAP_UNICODE) { | ||
1611 | if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ | ||
1612 | *bcc_ptr = 0; | ||
1613 | bcc_ptr++; | ||
1614 | } | ||
1615 | if(user == NULL) | ||
1616 | bytes_returned = 0; /* skill null user */ | ||
1617 | else | ||
1618 | bytes_returned = | ||
1619 | cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, | ||
1620 | nls_codepage); | ||
1621 | /* convert number of 16 bit words to bytes */ | ||
1622 | bcc_ptr += 2 * bytes_returned; | ||
1623 | bcc_ptr += 2; /* trailing null */ | ||
1624 | if (domain == NULL) | ||
1625 | bytes_returned = | ||
1626 | cifs_strtoUCS((wchar_t *) bcc_ptr, | ||
1627 | "CIFS_LINUX_DOM", 32, nls_codepage); | ||
1628 | else | ||
1629 | bytes_returned = | ||
1630 | cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, | ||
1631 | nls_codepage); | ||
1632 | bcc_ptr += 2 * bytes_returned; | ||
1633 | bcc_ptr += 2; | ||
1634 | bytes_returned = | ||
1635 | cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", | ||
1636 | 32, nls_codepage); | ||
1637 | bcc_ptr += 2 * bytes_returned; | ||
1638 | bytes_returned = | ||
1639 | cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, | ||
1640 | 32, nls_codepage); | ||
1641 | bcc_ptr += 2 * bytes_returned; | ||
1642 | bcc_ptr += 2; | ||
1643 | bytes_returned = | ||
1644 | cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
1645 | 64, nls_codepage); | ||
1646 | bcc_ptr += 2 * bytes_returned; | ||
1647 | bcc_ptr += 2; | ||
1648 | } else { | ||
1649 | if(user != NULL) { | ||
1650 | strncpy(bcc_ptr, user, 200); | ||
1651 | bcc_ptr += strnlen(user, 200); | ||
1652 | } | ||
1653 | *bcc_ptr = 0; | ||
1654 | bcc_ptr++; | ||
1655 | if (domain == NULL) { | ||
1656 | strcpy(bcc_ptr, "CIFS_LINUX_DOM"); | ||
1657 | bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; | ||
1658 | } else { | ||
1659 | strncpy(bcc_ptr, domain, 64); | ||
1660 | bcc_ptr += strnlen(domain, 64); | ||
1661 | *bcc_ptr = 0; | ||
1662 | bcc_ptr++; | ||
1663 | } | ||
1664 | strcpy(bcc_ptr, "Linux version "); | ||
1665 | bcc_ptr += strlen("Linux version "); | ||
1666 | strcpy(bcc_ptr, system_utsname.release); | ||
1667 | bcc_ptr += strlen(system_utsname.release) + 1; | ||
1668 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
1669 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
1670 | } | ||
1671 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
1672 | smb_buffer->smb_buf_length += count; | ||
1673 | pSMB->req_no_secext.ByteCount = cpu_to_le16(count); | ||
1674 | |||
1675 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
1676 | &bytes_returned, 1); | ||
1677 | if (rc) { | ||
1678 | /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ | ||
1679 | } else if ((smb_buffer_response->WordCount == 3) | ||
1680 | || (smb_buffer_response->WordCount == 4)) { | ||
1681 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
1682 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
1683 | if (action & GUEST_LOGIN) | ||
1684 | cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */ | ||
1685 | ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ | ||
1686 | cFYI(1, ("UID = %d ", ses->Suid)); | ||
1687 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
1688 | bcc_ptr = pByteArea(smb_buffer_response); | ||
1689 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
1690 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
1691 | && (blob_len < pSMBr->resp.ByteCount))) { | ||
1692 | if (pSMBr->resp.hdr.WordCount == 4) | ||
1693 | bcc_ptr += blob_len; | ||
1694 | |||
1695 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
1696 | if ((long) (bcc_ptr) % 2) { | ||
1697 | remaining_words = | ||
1698 | (BCC(smb_buffer_response) - 1) /2; | ||
1699 | bcc_ptr++; /* Unicode strings must be word aligned */ | ||
1700 | } else { | ||
1701 | remaining_words = | ||
1702 | BCC(smb_buffer_response) / 2; | ||
1703 | } | ||
1704 | len = | ||
1705 | UniStrnlen((wchar_t *) bcc_ptr, | ||
1706 | remaining_words - 1); | ||
1707 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
1708 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
1709 | terminating last Unicode string in response */ | ||
1710 | ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL); | ||
1711 | cifs_strfromUCS_le(ses->serverOS, | ||
1712 | (wchar_t *)bcc_ptr, len,nls_codepage); | ||
1713 | bcc_ptr += 2 * (len + 1); | ||
1714 | remaining_words -= len + 1; | ||
1715 | ses->serverOS[2 * len] = 0; | ||
1716 | ses->serverOS[1 + (2 * len)] = 0; | ||
1717 | if (remaining_words > 0) { | ||
1718 | len = UniStrnlen((wchar_t *)bcc_ptr, | ||
1719 | remaining_words-1); | ||
1720 | ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL); | ||
1721 | cifs_strfromUCS_le(ses->serverNOS, | ||
1722 | (wchar_t *)bcc_ptr,len,nls_codepage); | ||
1723 | bcc_ptr += 2 * (len + 1); | ||
1724 | ses->serverNOS[2 * len] = 0; | ||
1725 | ses->serverNOS[1 + (2 * len)] = 0; | ||
1726 | if(strncmp(ses->serverNOS, | ||
1727 | "NT LAN Manager 4",16) == 0) { | ||
1728 | cFYI(1,("NT4 server")); | ||
1729 | ses->flags |= CIFS_SES_NT4; | ||
1730 | } | ||
1731 | remaining_words -= len + 1; | ||
1732 | if (remaining_words > 0) { | ||
1733 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
1734 | /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ | ||
1735 | ses->serverDomain = | ||
1736 | cifs_kcalloc(2*(len+1),GFP_KERNEL); | ||
1737 | cifs_strfromUCS_le(ses->serverDomain, | ||
1738 | (wchar_t *)bcc_ptr,len,nls_codepage); | ||
1739 | bcc_ptr += 2 * (len + 1); | ||
1740 | ses->serverDomain[2*len] = 0; | ||
1741 | ses->serverDomain[1+(2*len)] = 0; | ||
1742 | } /* else no more room so create dummy domain string */ | ||
1743 | else | ||
1744 | ses->serverDomain = | ||
1745 | cifs_kcalloc(2, | ||
1746 | GFP_KERNEL); | ||
1747 | } else { /* no room so create dummy domain and NOS string */ | ||
1748 | ses->serverDomain = | ||
1749 | cifs_kcalloc(2, GFP_KERNEL); | ||
1750 | ses->serverNOS = | ||
1751 | cifs_kcalloc(2, GFP_KERNEL); | ||
1752 | } | ||
1753 | } else { /* ASCII */ | ||
1754 | len = strnlen(bcc_ptr, 1024); | ||
1755 | if (((long) bcc_ptr + len) - (long) | ||
1756 | pByteArea(smb_buffer_response) | ||
1757 | <= BCC(smb_buffer_response)) { | ||
1758 | ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); | ||
1759 | strncpy(ses->serverOS,bcc_ptr, len); | ||
1760 | |||
1761 | bcc_ptr += len; | ||
1762 | bcc_ptr[0] = 0; /* null terminate the string */ | ||
1763 | bcc_ptr++; | ||
1764 | |||
1765 | len = strnlen(bcc_ptr, 1024); | ||
1766 | ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); | ||
1767 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
1768 | bcc_ptr += len; | ||
1769 | bcc_ptr[0] = 0; | ||
1770 | bcc_ptr++; | ||
1771 | |||
1772 | len = strnlen(bcc_ptr, 1024); | ||
1773 | ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL); | ||
1774 | strncpy(ses->serverDomain, bcc_ptr, len); | ||
1775 | bcc_ptr += len; | ||
1776 | bcc_ptr[0] = 0; | ||
1777 | bcc_ptr++; | ||
1778 | } else | ||
1779 | cFYI(1, | ||
1780 | ("Variable field of length %d extends beyond end of smb ", | ||
1781 | len)); | ||
1782 | } | ||
1783 | } else { | ||
1784 | cERROR(1, | ||
1785 | (" Security Blob Length extends beyond end of SMB")); | ||
1786 | } | ||
1787 | } else { | ||
1788 | cERROR(1, | ||
1789 | (" Invalid Word count %d: ", | ||
1790 | smb_buffer_response->WordCount)); | ||
1791 | rc = -EIO; | ||
1792 | } | ||
1793 | |||
1794 | if (smb_buffer) | ||
1795 | cifs_buf_release(smb_buffer); | ||
1796 | |||
1797 | return rc; | ||
1798 | } | ||
1799 | |||
1800 | static int | ||
1801 | CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
1802 | char *SecurityBlob,int SecurityBlobLength, | ||
1803 | const struct nls_table *nls_codepage) | ||
1804 | { | ||
1805 | struct smb_hdr *smb_buffer; | ||
1806 | struct smb_hdr *smb_buffer_response; | ||
1807 | SESSION_SETUP_ANDX *pSMB; | ||
1808 | SESSION_SETUP_ANDX *pSMBr; | ||
1809 | char *bcc_ptr; | ||
1810 | char *user; | ||
1811 | char *domain; | ||
1812 | int rc = 0; | ||
1813 | int remaining_words = 0; | ||
1814 | int bytes_returned = 0; | ||
1815 | int len; | ||
1816 | __u32 capabilities; | ||
1817 | __u16 count; | ||
1818 | |||
1819 | cFYI(1, ("In spnego sesssetup ")); | ||
1820 | if(ses == NULL) | ||
1821 | return -EINVAL; | ||
1822 | user = ses->userName; | ||
1823 | domain = ses->domainName; | ||
1824 | |||
1825 | smb_buffer = cifs_buf_get(); | ||
1826 | if (smb_buffer == NULL) { | ||
1827 | return -ENOMEM; | ||
1828 | } | ||
1829 | smb_buffer_response = smb_buffer; | ||
1830 | pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
1831 | |||
1832 | /* send SMBsessionSetup here */ | ||
1833 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
1834 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
1835 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
1836 | pSMB->req.AndXCommand = 0xFF; | ||
1837 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
1838 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
1839 | |||
1840 | if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
1841 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
1842 | |||
1843 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
1844 | CAP_EXTENDED_SECURITY; | ||
1845 | if (ses->capabilities & CAP_UNICODE) { | ||
1846 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
1847 | capabilities |= CAP_UNICODE; | ||
1848 | } | ||
1849 | if (ses->capabilities & CAP_STATUS32) { | ||
1850 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
1851 | capabilities |= CAP_STATUS32; | ||
1852 | } | ||
1853 | if (ses->capabilities & CAP_DFS) { | ||
1854 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
1855 | capabilities |= CAP_DFS; | ||
1856 | } | ||
1857 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
1858 | |||
1859 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
1860 | bcc_ptr = pByteArea(smb_buffer); | ||
1861 | memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength); | ||
1862 | bcc_ptr += SecurityBlobLength; | ||
1863 | |||
1864 | if (ses->capabilities & CAP_UNICODE) { | ||
1865 | if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */ | ||
1866 | *bcc_ptr = 0; | ||
1867 | bcc_ptr++; | ||
1868 | } | ||
1869 | bytes_returned = | ||
1870 | cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); | ||
1871 | bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */ | ||
1872 | bcc_ptr += 2; /* trailing null */ | ||
1873 | if (domain == NULL) | ||
1874 | bytes_returned = | ||
1875 | cifs_strtoUCS((wchar_t *) bcc_ptr, | ||
1876 | "CIFS_LINUX_DOM", 32, nls_codepage); | ||
1877 | else | ||
1878 | bytes_returned = | ||
1879 | cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, | ||
1880 | nls_codepage); | ||
1881 | bcc_ptr += 2 * bytes_returned; | ||
1882 | bcc_ptr += 2; | ||
1883 | bytes_returned = | ||
1884 | cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", | ||
1885 | 32, nls_codepage); | ||
1886 | bcc_ptr += 2 * bytes_returned; | ||
1887 | bytes_returned = | ||
1888 | cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, | ||
1889 | nls_codepage); | ||
1890 | bcc_ptr += 2 * bytes_returned; | ||
1891 | bcc_ptr += 2; | ||
1892 | bytes_returned = | ||
1893 | cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
1894 | 64, nls_codepage); | ||
1895 | bcc_ptr += 2 * bytes_returned; | ||
1896 | bcc_ptr += 2; | ||
1897 | } else { | ||
1898 | strncpy(bcc_ptr, user, 200); | ||
1899 | bcc_ptr += strnlen(user, 200); | ||
1900 | *bcc_ptr = 0; | ||
1901 | bcc_ptr++; | ||
1902 | if (domain == NULL) { | ||
1903 | strcpy(bcc_ptr, "CIFS_LINUX_DOM"); | ||
1904 | bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; | ||
1905 | } else { | ||
1906 | strncpy(bcc_ptr, domain, 64); | ||
1907 | bcc_ptr += strnlen(domain, 64); | ||
1908 | *bcc_ptr = 0; | ||
1909 | bcc_ptr++; | ||
1910 | } | ||
1911 | strcpy(bcc_ptr, "Linux version "); | ||
1912 | bcc_ptr += strlen("Linux version "); | ||
1913 | strcpy(bcc_ptr, system_utsname.release); | ||
1914 | bcc_ptr += strlen(system_utsname.release) + 1; | ||
1915 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
1916 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
1917 | } | ||
1918 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
1919 | smb_buffer->smb_buf_length += count; | ||
1920 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
1921 | |||
1922 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
1923 | &bytes_returned, 1); | ||
1924 | if (rc) { | ||
1925 | /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ | ||
1926 | } else if ((smb_buffer_response->WordCount == 3) | ||
1927 | || (smb_buffer_response->WordCount == 4)) { | ||
1928 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
1929 | __u16 blob_len = | ||
1930 | le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
1931 | if (action & GUEST_LOGIN) | ||
1932 | cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ | ||
1933 | if (ses) { | ||
1934 | ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ | ||
1935 | cFYI(1, ("UID = %d ", ses->Suid)); | ||
1936 | bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
1937 | |||
1938 | /* BB Fix below to make endian neutral !! */ | ||
1939 | |||
1940 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
1941 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
1942 | && (blob_len < | ||
1943 | pSMBr->resp.ByteCount))) { | ||
1944 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
1945 | bcc_ptr += | ||
1946 | blob_len; | ||
1947 | cFYI(1, | ||
1948 | ("Security Blob Length %d ", | ||
1949 | blob_len)); | ||
1950 | } | ||
1951 | |||
1952 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
1953 | if ((long) (bcc_ptr) % 2) { | ||
1954 | remaining_words = | ||
1955 | (BCC(smb_buffer_response) | ||
1956 | - 1) / 2; | ||
1957 | bcc_ptr++; /* Unicode strings must be word aligned */ | ||
1958 | } else { | ||
1959 | remaining_words = | ||
1960 | BCC | ||
1961 | (smb_buffer_response) / 2; | ||
1962 | } | ||
1963 | len = | ||
1964 | UniStrnlen((wchar_t *) bcc_ptr, | ||
1965 | remaining_words - 1); | ||
1966 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
1967 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
1968 | terminating last Unicode string in response */ | ||
1969 | ses->serverOS = | ||
1970 | cifs_kcalloc(2 * (len + 1), GFP_KERNEL); | ||
1971 | cifs_strfromUCS_le(ses->serverOS, | ||
1972 | (wchar_t *) | ||
1973 | bcc_ptr, len, | ||
1974 | nls_codepage); | ||
1975 | bcc_ptr += 2 * (len + 1); | ||
1976 | remaining_words -= len + 1; | ||
1977 | ses->serverOS[2 * len] = 0; | ||
1978 | ses->serverOS[1 + (2 * len)] = 0; | ||
1979 | if (remaining_words > 0) { | ||
1980 | len = UniStrnlen((wchar_t *)bcc_ptr, | ||
1981 | remaining_words | ||
1982 | - 1); | ||
1983 | ses->serverNOS = | ||
1984 | cifs_kcalloc(2 * (len + 1), | ||
1985 | GFP_KERNEL); | ||
1986 | cifs_strfromUCS_le(ses->serverNOS, | ||
1987 | (wchar_t *)bcc_ptr, | ||
1988 | len, | ||
1989 | nls_codepage); | ||
1990 | bcc_ptr += 2 * (len + 1); | ||
1991 | ses->serverNOS[2 * len] = 0; | ||
1992 | ses->serverNOS[1 + (2 * len)] = 0; | ||
1993 | remaining_words -= len + 1; | ||
1994 | if (remaining_words > 0) { | ||
1995 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
1996 | /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ | ||
1997 | ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL); | ||
1998 | cifs_strfromUCS_le(ses->serverDomain, | ||
1999 | (wchar_t *)bcc_ptr, | ||
2000 | len, | ||
2001 | nls_codepage); | ||
2002 | bcc_ptr += 2*(len+1); | ||
2003 | ses->serverDomain[2*len] = 0; | ||
2004 | ses->serverDomain[1+(2*len)] = 0; | ||
2005 | } /* else no more room so create dummy domain string */ | ||
2006 | else | ||
2007 | ses->serverDomain = | ||
2008 | cifs_kcalloc(2,GFP_KERNEL); | ||
2009 | } else { /* no room so create dummy domain and NOS string */ | ||
2010 | ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); | ||
2011 | ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); | ||
2012 | } | ||
2013 | } else { /* ASCII */ | ||
2014 | |||
2015 | len = strnlen(bcc_ptr, 1024); | ||
2016 | if (((long) bcc_ptr + len) - (long) | ||
2017 | pByteArea(smb_buffer_response) | ||
2018 | <= BCC(smb_buffer_response)) { | ||
2019 | ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL); | ||
2020 | strncpy(ses->serverOS, bcc_ptr, len); | ||
2021 | |||
2022 | bcc_ptr += len; | ||
2023 | bcc_ptr[0] = 0; /* null terminate the string */ | ||
2024 | bcc_ptr++; | ||
2025 | |||
2026 | len = strnlen(bcc_ptr, 1024); | ||
2027 | ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); | ||
2028 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
2029 | bcc_ptr += len; | ||
2030 | bcc_ptr[0] = 0; | ||
2031 | bcc_ptr++; | ||
2032 | |||
2033 | len = strnlen(bcc_ptr, 1024); | ||
2034 | ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL); | ||
2035 | strncpy(ses->serverDomain, bcc_ptr, len); | ||
2036 | bcc_ptr += len; | ||
2037 | bcc_ptr[0] = 0; | ||
2038 | bcc_ptr++; | ||
2039 | } else | ||
2040 | cFYI(1, | ||
2041 | ("Variable field of length %d extends beyond end of smb ", | ||
2042 | len)); | ||
2043 | } | ||
2044 | } else { | ||
2045 | cERROR(1, | ||
2046 | (" Security Blob Length extends beyond end of SMB")); | ||
2047 | } | ||
2048 | } else { | ||
2049 | cERROR(1, ("No session structure passed in.")); | ||
2050 | } | ||
2051 | } else { | ||
2052 | cERROR(1, | ||
2053 | (" Invalid Word count %d: ", | ||
2054 | smb_buffer_response->WordCount)); | ||
2055 | rc = -EIO; | ||
2056 | } | ||
2057 | |||
2058 | if (smb_buffer) | ||
2059 | cifs_buf_release(smb_buffer); | ||
2060 | |||
2061 | return rc; | ||
2062 | } | ||
2063 | |||
2064 | static int | ||
2065 | CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | ||
2066 | struct cifsSesInfo *ses, int * pNTLMv2_flag, | ||
2067 | const struct nls_table *nls_codepage) | ||
2068 | { | ||
2069 | struct smb_hdr *smb_buffer; | ||
2070 | struct smb_hdr *smb_buffer_response; | ||
2071 | SESSION_SETUP_ANDX *pSMB; | ||
2072 | SESSION_SETUP_ANDX *pSMBr; | ||
2073 | char *bcc_ptr; | ||
2074 | char *domain; | ||
2075 | int rc = 0; | ||
2076 | int remaining_words = 0; | ||
2077 | int bytes_returned = 0; | ||
2078 | int len; | ||
2079 | int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE); | ||
2080 | PNEGOTIATE_MESSAGE SecurityBlob; | ||
2081 | PCHALLENGE_MESSAGE SecurityBlob2; | ||
2082 | __u32 negotiate_flags, capabilities; | ||
2083 | __u16 count; | ||
2084 | |||
2085 | cFYI(1, ("In NTLMSSP sesssetup (negotiate) ")); | ||
2086 | if(ses == NULL) | ||
2087 | return -EINVAL; | ||
2088 | domain = ses->domainName; | ||
2089 | *pNTLMv2_flag = FALSE; | ||
2090 | smb_buffer = cifs_buf_get(); | ||
2091 | if (smb_buffer == NULL) { | ||
2092 | return -ENOMEM; | ||
2093 | } | ||
2094 | smb_buffer_response = smb_buffer; | ||
2095 | pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
2096 | pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; | ||
2097 | |||
2098 | /* send SMBsessionSetup here */ | ||
2099 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
2100 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
2101 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
2102 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | ||
2103 | |||
2104 | pSMB->req.AndXCommand = 0xFF; | ||
2105 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
2106 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
2107 | |||
2108 | if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
2109 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
2110 | |||
2111 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
2112 | CAP_EXTENDED_SECURITY; | ||
2113 | if (ses->capabilities & CAP_UNICODE) { | ||
2114 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
2115 | capabilities |= CAP_UNICODE; | ||
2116 | } | ||
2117 | if (ses->capabilities & CAP_STATUS32) { | ||
2118 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
2119 | capabilities |= CAP_STATUS32; | ||
2120 | } | ||
2121 | if (ses->capabilities & CAP_DFS) { | ||
2122 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
2123 | capabilities |= CAP_DFS; | ||
2124 | } | ||
2125 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
2126 | |||
2127 | bcc_ptr = (char *) &pSMB->req.SecurityBlob; | ||
2128 | SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr; | ||
2129 | strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); | ||
2130 | SecurityBlob->MessageType = NtLmNegotiate; | ||
2131 | negotiate_flags = | ||
2132 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | | ||
2133 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 | | ||
2134 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; | ||
2135 | if(sign_CIFS_PDUs) | ||
2136 | negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; | ||
2137 | if(ntlmv2_support) | ||
2138 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; | ||
2139 | /* setup pointers to domain name and workstation name */ | ||
2140 | bcc_ptr += SecurityBlobLength; | ||
2141 | |||
2142 | SecurityBlob->WorkstationName.Buffer = 0; | ||
2143 | SecurityBlob->WorkstationName.Length = 0; | ||
2144 | SecurityBlob->WorkstationName.MaximumLength = 0; | ||
2145 | |||
2146 | if (domain == NULL) { | ||
2147 | SecurityBlob->DomainName.Buffer = 0; | ||
2148 | SecurityBlob->DomainName.Length = 0; | ||
2149 | SecurityBlob->DomainName.MaximumLength = 0; | ||
2150 | } else { | ||
2151 | __u16 len; | ||
2152 | negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; | ||
2153 | strncpy(bcc_ptr, domain, 63); | ||
2154 | len = strnlen(domain, 64); | ||
2155 | SecurityBlob->DomainName.MaximumLength = | ||
2156 | cpu_to_le16(len); | ||
2157 | SecurityBlob->DomainName.Buffer = | ||
2158 | cpu_to_le32((long) &SecurityBlob-> | ||
2159 | DomainString - | ||
2160 | (long) &SecurityBlob->Signature); | ||
2161 | bcc_ptr += len; | ||
2162 | SecurityBlobLength += len; | ||
2163 | SecurityBlob->DomainName.Length = | ||
2164 | cpu_to_le16(len); | ||
2165 | } | ||
2166 | if (ses->capabilities & CAP_UNICODE) { | ||
2167 | if ((long) bcc_ptr % 2) { | ||
2168 | *bcc_ptr = 0; | ||
2169 | bcc_ptr++; | ||
2170 | } | ||
2171 | |||
2172 | bytes_returned = | ||
2173 | cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", | ||
2174 | 32, nls_codepage); | ||
2175 | bcc_ptr += 2 * bytes_returned; | ||
2176 | bytes_returned = | ||
2177 | cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, | ||
2178 | nls_codepage); | ||
2179 | bcc_ptr += 2 * bytes_returned; | ||
2180 | bcc_ptr += 2; /* null terminate Linux version */ | ||
2181 | bytes_returned = | ||
2182 | cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
2183 | 64, nls_codepage); | ||
2184 | bcc_ptr += 2 * bytes_returned; | ||
2185 | *(bcc_ptr + 1) = 0; | ||
2186 | *(bcc_ptr + 2) = 0; | ||
2187 | bcc_ptr += 2; /* null terminate network opsys string */ | ||
2188 | *(bcc_ptr + 1) = 0; | ||
2189 | *(bcc_ptr + 2) = 0; | ||
2190 | bcc_ptr += 2; /* null domain */ | ||
2191 | } else { /* ASCII */ | ||
2192 | strcpy(bcc_ptr, "Linux version "); | ||
2193 | bcc_ptr += strlen("Linux version "); | ||
2194 | strcpy(bcc_ptr, system_utsname.release); | ||
2195 | bcc_ptr += strlen(system_utsname.release) + 1; | ||
2196 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
2197 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
2198 | bcc_ptr++; /* empty domain field */ | ||
2199 | *bcc_ptr = 0; | ||
2200 | } | ||
2201 | SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); | ||
2202 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
2203 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
2204 | smb_buffer->smb_buf_length += count; | ||
2205 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
2206 | |||
2207 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
2208 | &bytes_returned, 1); | ||
2209 | |||
2210 | if (smb_buffer_response->Status.CifsError == | ||
2211 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) | ||
2212 | rc = 0; | ||
2213 | |||
2214 | if (rc) { | ||
2215 | /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ | ||
2216 | } else if ((smb_buffer_response->WordCount == 3) | ||
2217 | || (smb_buffer_response->WordCount == 4)) { | ||
2218 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
2219 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
2220 | |||
2221 | if (action & GUEST_LOGIN) | ||
2222 | cFYI(1, (" Guest login")); | ||
2223 | /* Do we want to set anything in SesInfo struct when guest login? */ | ||
2224 | |||
2225 | bcc_ptr = pByteArea(smb_buffer_response); | ||
2226 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
2227 | |||
2228 | SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; | ||
2229 | if (SecurityBlob2->MessageType != NtLmChallenge) { | ||
2230 | cFYI(1, | ||
2231 | ("Unexpected NTLMSSP message type received %d", | ||
2232 | SecurityBlob2->MessageType)); | ||
2233 | } else if (ses) { | ||
2234 | ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ | ||
2235 | cFYI(1, ("UID = %d ", ses->Suid)); | ||
2236 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
2237 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
2238 | && (blob_len < | ||
2239 | pSMBr->resp.ByteCount))) { | ||
2240 | |||
2241 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
2242 | bcc_ptr += blob_len; | ||
2243 | cFYI(1, | ||
2244 | ("Security Blob Length %d ", | ||
2245 | blob_len)); | ||
2246 | } | ||
2247 | |||
2248 | cFYI(1, ("NTLMSSP Challenge rcvd ")); | ||
2249 | |||
2250 | memcpy(ses->server->cryptKey, | ||
2251 | SecurityBlob2->Challenge, | ||
2252 | CIFS_CRYPTO_KEY_SIZE); | ||
2253 | if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2)) | ||
2254 | *pNTLMv2_flag = TRUE; | ||
2255 | |||
2256 | if((SecurityBlob2->NegotiateFlags & | ||
2257 | cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) | ||
2258 | || (sign_CIFS_PDUs > 1)) | ||
2259 | ses->server->secMode |= | ||
2260 | SECMODE_SIGN_REQUIRED; | ||
2261 | if ((SecurityBlob2->NegotiateFlags & | ||
2262 | cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs)) | ||
2263 | ses->server->secMode |= | ||
2264 | SECMODE_SIGN_ENABLED; | ||
2265 | |||
2266 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
2267 | if ((long) (bcc_ptr) % 2) { | ||
2268 | remaining_words = | ||
2269 | (BCC(smb_buffer_response) | ||
2270 | - 1) / 2; | ||
2271 | bcc_ptr++; /* Unicode strings must be word aligned */ | ||
2272 | } else { | ||
2273 | remaining_words = | ||
2274 | BCC | ||
2275 | (smb_buffer_response) / 2; | ||
2276 | } | ||
2277 | len = | ||
2278 | UniStrnlen((wchar_t *) bcc_ptr, | ||
2279 | remaining_words - 1); | ||
2280 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
2281 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
2282 | terminating last Unicode string in response */ | ||
2283 | ses->serverOS = | ||
2284 | cifs_kcalloc(2 * (len + 1), GFP_KERNEL); | ||
2285 | cifs_strfromUCS_le(ses->serverOS, | ||
2286 | (wchar_t *) | ||
2287 | bcc_ptr, len, | ||
2288 | nls_codepage); | ||
2289 | bcc_ptr += 2 * (len + 1); | ||
2290 | remaining_words -= len + 1; | ||
2291 | ses->serverOS[2 * len] = 0; | ||
2292 | ses->serverOS[1 + (2 * len)] = 0; | ||
2293 | if (remaining_words > 0) { | ||
2294 | len = UniStrnlen((wchar_t *) | ||
2295 | bcc_ptr, | ||
2296 | remaining_words | ||
2297 | - 1); | ||
2298 | ses->serverNOS = | ||
2299 | cifs_kcalloc(2 * (len + 1), | ||
2300 | GFP_KERNEL); | ||
2301 | cifs_strfromUCS_le(ses-> | ||
2302 | serverNOS, | ||
2303 | (wchar_t *) | ||
2304 | bcc_ptr, | ||
2305 | len, | ||
2306 | nls_codepage); | ||
2307 | bcc_ptr += 2 * (len + 1); | ||
2308 | ses->serverNOS[2 * len] = 0; | ||
2309 | ses->serverNOS[1 + | ||
2310 | (2 * len)] = 0; | ||
2311 | remaining_words -= len + 1; | ||
2312 | if (remaining_words > 0) { | ||
2313 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
2314 | /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ | ||
2315 | ses->serverDomain = | ||
2316 | cifs_kcalloc(2 * | ||
2317 | (len + | ||
2318 | 1), | ||
2319 | GFP_KERNEL); | ||
2320 | cifs_strfromUCS_le | ||
2321 | (ses-> | ||
2322 | serverDomain, | ||
2323 | (wchar_t *) | ||
2324 | bcc_ptr, len, | ||
2325 | nls_codepage); | ||
2326 | bcc_ptr += | ||
2327 | 2 * (len + 1); | ||
2328 | ses-> | ||
2329 | serverDomain[2 | ||
2330 | * len] | ||
2331 | = 0; | ||
2332 | ses-> | ||
2333 | serverDomain[1 | ||
2334 | + | ||
2335 | (2 | ||
2336 | * | ||
2337 | len)] | ||
2338 | = 0; | ||
2339 | } /* else no more room so create dummy domain string */ | ||
2340 | else | ||
2341 | ses->serverDomain = | ||
2342 | cifs_kcalloc(2, | ||
2343 | GFP_KERNEL); | ||
2344 | } else { /* no room so create dummy domain and NOS string */ | ||
2345 | ses->serverDomain = | ||
2346 | cifs_kcalloc(2, GFP_KERNEL); | ||
2347 | ses->serverNOS = | ||
2348 | cifs_kcalloc(2, GFP_KERNEL); | ||
2349 | } | ||
2350 | } else { /* ASCII */ | ||
2351 | len = strnlen(bcc_ptr, 1024); | ||
2352 | if (((long) bcc_ptr + len) - (long) | ||
2353 | pByteArea(smb_buffer_response) | ||
2354 | <= BCC(smb_buffer_response)) { | ||
2355 | ses->serverOS = | ||
2356 | cifs_kcalloc(len + 1, | ||
2357 | GFP_KERNEL); | ||
2358 | strncpy(ses->serverOS, | ||
2359 | bcc_ptr, len); | ||
2360 | |||
2361 | bcc_ptr += len; | ||
2362 | bcc_ptr[0] = 0; /* null terminate string */ | ||
2363 | bcc_ptr++; | ||
2364 | |||
2365 | len = strnlen(bcc_ptr, 1024); | ||
2366 | ses->serverNOS = | ||
2367 | cifs_kcalloc(len + 1, | ||
2368 | GFP_KERNEL); | ||
2369 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
2370 | bcc_ptr += len; | ||
2371 | bcc_ptr[0] = 0; | ||
2372 | bcc_ptr++; | ||
2373 | |||
2374 | len = strnlen(bcc_ptr, 1024); | ||
2375 | ses->serverDomain = | ||
2376 | cifs_kcalloc(len + 1, | ||
2377 | GFP_KERNEL); | ||
2378 | strncpy(ses->serverDomain, bcc_ptr, len); | ||
2379 | bcc_ptr += len; | ||
2380 | bcc_ptr[0] = 0; | ||
2381 | bcc_ptr++; | ||
2382 | } else | ||
2383 | cFYI(1, | ||
2384 | ("Variable field of length %d extends beyond end of smb ", | ||
2385 | len)); | ||
2386 | } | ||
2387 | } else { | ||
2388 | cERROR(1, | ||
2389 | (" Security Blob Length extends beyond end of SMB")); | ||
2390 | } | ||
2391 | } else { | ||
2392 | cERROR(1, ("No session structure passed in.")); | ||
2393 | } | ||
2394 | } else { | ||
2395 | cERROR(1, | ||
2396 | (" Invalid Word count %d: ", | ||
2397 | smb_buffer_response->WordCount)); | ||
2398 | rc = -EIO; | ||
2399 | } | ||
2400 | |||
2401 | if (smb_buffer) | ||
2402 | cifs_buf_release(smb_buffer); | ||
2403 | |||
2404 | return rc; | ||
2405 | } | ||
2406 | static int | ||
2407 | CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
2408 | char *ntlm_session_key, int ntlmv2_flag, | ||
2409 | const struct nls_table *nls_codepage) | ||
2410 | { | ||
2411 | struct smb_hdr *smb_buffer; | ||
2412 | struct smb_hdr *smb_buffer_response; | ||
2413 | SESSION_SETUP_ANDX *pSMB; | ||
2414 | SESSION_SETUP_ANDX *pSMBr; | ||
2415 | char *bcc_ptr; | ||
2416 | char *user; | ||
2417 | char *domain; | ||
2418 | int rc = 0; | ||
2419 | int remaining_words = 0; | ||
2420 | int bytes_returned = 0; | ||
2421 | int len; | ||
2422 | int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE); | ||
2423 | PAUTHENTICATE_MESSAGE SecurityBlob; | ||
2424 | __u32 negotiate_flags, capabilities; | ||
2425 | __u16 count; | ||
2426 | |||
2427 | cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); | ||
2428 | if(ses == NULL) | ||
2429 | return -EINVAL; | ||
2430 | user = ses->userName; | ||
2431 | domain = ses->domainName; | ||
2432 | smb_buffer = cifs_buf_get(); | ||
2433 | if (smb_buffer == NULL) { | ||
2434 | return -ENOMEM; | ||
2435 | } | ||
2436 | smb_buffer_response = smb_buffer; | ||
2437 | pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
2438 | pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; | ||
2439 | |||
2440 | /* send SMBsessionSetup here */ | ||
2441 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
2442 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
2443 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | ||
2444 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
2445 | pSMB->req.AndXCommand = 0xFF; | ||
2446 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
2447 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
2448 | |||
2449 | pSMB->req.hdr.Uid = ses->Suid; | ||
2450 | |||
2451 | if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
2452 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
2453 | |||
2454 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
2455 | CAP_EXTENDED_SECURITY; | ||
2456 | if (ses->capabilities & CAP_UNICODE) { | ||
2457 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
2458 | capabilities |= CAP_UNICODE; | ||
2459 | } | ||
2460 | if (ses->capabilities & CAP_STATUS32) { | ||
2461 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
2462 | capabilities |= CAP_STATUS32; | ||
2463 | } | ||
2464 | if (ses->capabilities & CAP_DFS) { | ||
2465 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
2466 | capabilities |= CAP_DFS; | ||
2467 | } | ||
2468 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
2469 | |||
2470 | bcc_ptr = (char *) &pSMB->req.SecurityBlob; | ||
2471 | SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr; | ||
2472 | strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); | ||
2473 | SecurityBlob->MessageType = NtLmAuthenticate; | ||
2474 | bcc_ptr += SecurityBlobLength; | ||
2475 | negotiate_flags = | ||
2476 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | | ||
2477 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | | ||
2478 | 0x80000000 | NTLMSSP_NEGOTIATE_128; | ||
2479 | if(sign_CIFS_PDUs) | ||
2480 | negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; | ||
2481 | if(ntlmv2_flag) | ||
2482 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; | ||
2483 | |||
2484 | /* setup pointers to domain name and workstation name */ | ||
2485 | |||
2486 | SecurityBlob->WorkstationName.Buffer = 0; | ||
2487 | SecurityBlob->WorkstationName.Length = 0; | ||
2488 | SecurityBlob->WorkstationName.MaximumLength = 0; | ||
2489 | SecurityBlob->SessionKey.Length = 0; | ||
2490 | SecurityBlob->SessionKey.MaximumLength = 0; | ||
2491 | SecurityBlob->SessionKey.Buffer = 0; | ||
2492 | |||
2493 | SecurityBlob->LmChallengeResponse.Length = 0; | ||
2494 | SecurityBlob->LmChallengeResponse.MaximumLength = 0; | ||
2495 | SecurityBlob->LmChallengeResponse.Buffer = 0; | ||
2496 | |||
2497 | SecurityBlob->NtChallengeResponse.Length = | ||
2498 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | ||
2499 | SecurityBlob->NtChallengeResponse.MaximumLength = | ||
2500 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | ||
2501 | memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE); | ||
2502 | SecurityBlob->NtChallengeResponse.Buffer = | ||
2503 | cpu_to_le32(SecurityBlobLength); | ||
2504 | SecurityBlobLength += CIFS_SESSION_KEY_SIZE; | ||
2505 | bcc_ptr += CIFS_SESSION_KEY_SIZE; | ||
2506 | |||
2507 | if (ses->capabilities & CAP_UNICODE) { | ||
2508 | if (domain == NULL) { | ||
2509 | SecurityBlob->DomainName.Buffer = 0; | ||
2510 | SecurityBlob->DomainName.Length = 0; | ||
2511 | SecurityBlob->DomainName.MaximumLength = 0; | ||
2512 | } else { | ||
2513 | __u16 len = | ||
2514 | cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, | ||
2515 | nls_codepage); | ||
2516 | len *= 2; | ||
2517 | SecurityBlob->DomainName.MaximumLength = | ||
2518 | cpu_to_le16(len); | ||
2519 | SecurityBlob->DomainName.Buffer = | ||
2520 | cpu_to_le32(SecurityBlobLength); | ||
2521 | bcc_ptr += len; | ||
2522 | SecurityBlobLength += len; | ||
2523 | SecurityBlob->DomainName.Length = | ||
2524 | cpu_to_le16(len); | ||
2525 | } | ||
2526 | if (user == NULL) { | ||
2527 | SecurityBlob->UserName.Buffer = 0; | ||
2528 | SecurityBlob->UserName.Length = 0; | ||
2529 | SecurityBlob->UserName.MaximumLength = 0; | ||
2530 | } else { | ||
2531 | __u16 len = | ||
2532 | cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64, | ||
2533 | nls_codepage); | ||
2534 | len *= 2; | ||
2535 | SecurityBlob->UserName.MaximumLength = | ||
2536 | cpu_to_le16(len); | ||
2537 | SecurityBlob->UserName.Buffer = | ||
2538 | cpu_to_le32(SecurityBlobLength); | ||
2539 | bcc_ptr += len; | ||
2540 | SecurityBlobLength += len; | ||
2541 | SecurityBlob->UserName.Length = | ||
2542 | cpu_to_le16(len); | ||
2543 | } | ||
2544 | |||
2545 | /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage); | ||
2546 | SecurityBlob->WorkstationName.Length *= 2; | ||
2547 | SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length); | ||
2548 | SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength); | ||
2549 | bcc_ptr += SecurityBlob->WorkstationName.Length; | ||
2550 | SecurityBlobLength += SecurityBlob->WorkstationName.Length; | ||
2551 | SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */ | ||
2552 | |||
2553 | if ((long) bcc_ptr % 2) { | ||
2554 | *bcc_ptr = 0; | ||
2555 | bcc_ptr++; | ||
2556 | } | ||
2557 | bytes_returned = | ||
2558 | cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", | ||
2559 | 32, nls_codepage); | ||
2560 | bcc_ptr += 2 * bytes_returned; | ||
2561 | bytes_returned = | ||
2562 | cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, | ||
2563 | nls_codepage); | ||
2564 | bcc_ptr += 2 * bytes_returned; | ||
2565 | bcc_ptr += 2; /* null term version string */ | ||
2566 | bytes_returned = | ||
2567 | cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
2568 | 64, nls_codepage); | ||
2569 | bcc_ptr += 2 * bytes_returned; | ||
2570 | *(bcc_ptr + 1) = 0; | ||
2571 | *(bcc_ptr + 2) = 0; | ||
2572 | bcc_ptr += 2; /* null terminate network opsys string */ | ||
2573 | *(bcc_ptr + 1) = 0; | ||
2574 | *(bcc_ptr + 2) = 0; | ||
2575 | bcc_ptr += 2; /* null domain */ | ||
2576 | } else { /* ASCII */ | ||
2577 | if (domain == NULL) { | ||
2578 | SecurityBlob->DomainName.Buffer = 0; | ||
2579 | SecurityBlob->DomainName.Length = 0; | ||
2580 | SecurityBlob->DomainName.MaximumLength = 0; | ||
2581 | } else { | ||
2582 | __u16 len; | ||
2583 | negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; | ||
2584 | strncpy(bcc_ptr, domain, 63); | ||
2585 | len = strnlen(domain, 64); | ||
2586 | SecurityBlob->DomainName.MaximumLength = | ||
2587 | cpu_to_le16(len); | ||
2588 | SecurityBlob->DomainName.Buffer = | ||
2589 | cpu_to_le32(SecurityBlobLength); | ||
2590 | bcc_ptr += len; | ||
2591 | SecurityBlobLength += len; | ||
2592 | SecurityBlob->DomainName.Length = cpu_to_le16(len); | ||
2593 | } | ||
2594 | if (user == NULL) { | ||
2595 | SecurityBlob->UserName.Buffer = 0; | ||
2596 | SecurityBlob->UserName.Length = 0; | ||
2597 | SecurityBlob->UserName.MaximumLength = 0; | ||
2598 | } else { | ||
2599 | __u16 len; | ||
2600 | strncpy(bcc_ptr, user, 63); | ||
2601 | len = strnlen(user, 64); | ||
2602 | SecurityBlob->UserName.MaximumLength = | ||
2603 | cpu_to_le16(len); | ||
2604 | SecurityBlob->UserName.Buffer = | ||
2605 | cpu_to_le32(SecurityBlobLength); | ||
2606 | bcc_ptr += len; | ||
2607 | SecurityBlobLength += len; | ||
2608 | SecurityBlob->UserName.Length = cpu_to_le16(len); | ||
2609 | } | ||
2610 | /* BB fill in our workstation name if known BB */ | ||
2611 | |||
2612 | strcpy(bcc_ptr, "Linux version "); | ||
2613 | bcc_ptr += strlen("Linux version "); | ||
2614 | strcpy(bcc_ptr, system_utsname.release); | ||
2615 | bcc_ptr += strlen(system_utsname.release) + 1; | ||
2616 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
2617 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
2618 | bcc_ptr++; /* null domain */ | ||
2619 | *bcc_ptr = 0; | ||
2620 | } | ||
2621 | SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); | ||
2622 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
2623 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
2624 | smb_buffer->smb_buf_length += count; | ||
2625 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
2626 | |||
2627 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
2628 | &bytes_returned, 1); | ||
2629 | if (rc) { | ||
2630 | /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ | ||
2631 | } else if ((smb_buffer_response->WordCount == 3) | ||
2632 | || (smb_buffer_response->WordCount == 4)) { | ||
2633 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
2634 | __u16 blob_len = | ||
2635 | le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
2636 | if (action & GUEST_LOGIN) | ||
2637 | cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ | ||
2638 | /* if(SecurityBlob2->MessageType != NtLm??){ | ||
2639 | cFYI("Unexpected message type on auth response is %d ")); | ||
2640 | } */ | ||
2641 | if (ses) { | ||
2642 | cFYI(1, | ||
2643 | ("Does UID on challenge %d match auth response UID %d ", | ||
2644 | ses->Suid, smb_buffer_response->Uid)); | ||
2645 | ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */ | ||
2646 | bcc_ptr = pByteArea(smb_buffer_response); | ||
2647 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
2648 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
2649 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
2650 | && (blob_len < | ||
2651 | pSMBr->resp.ByteCount))) { | ||
2652 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
2653 | bcc_ptr += | ||
2654 | blob_len; | ||
2655 | cFYI(1, | ||
2656 | ("Security Blob Length %d ", | ||
2657 | blob_len)); | ||
2658 | } | ||
2659 | |||
2660 | cFYI(1, | ||
2661 | ("NTLMSSP response to Authenticate ")); | ||
2662 | |||
2663 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
2664 | if ((long) (bcc_ptr) % 2) { | ||
2665 | remaining_words = | ||
2666 | (BCC(smb_buffer_response) | ||
2667 | - 1) / 2; | ||
2668 | bcc_ptr++; /* Unicode strings must be word aligned */ | ||
2669 | } else { | ||
2670 | remaining_words = BCC(smb_buffer_response) / 2; | ||
2671 | } | ||
2672 | len = | ||
2673 | UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1); | ||
2674 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
2675 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
2676 | terminating last Unicode string in response */ | ||
2677 | ses->serverOS = | ||
2678 | cifs_kcalloc(2 * (len + 1), GFP_KERNEL); | ||
2679 | cifs_strfromUCS_le(ses->serverOS, | ||
2680 | (wchar_t *) | ||
2681 | bcc_ptr, len, | ||
2682 | nls_codepage); | ||
2683 | bcc_ptr += 2 * (len + 1); | ||
2684 | remaining_words -= len + 1; | ||
2685 | ses->serverOS[2 * len] = 0; | ||
2686 | ses->serverOS[1 + (2 * len)] = 0; | ||
2687 | if (remaining_words > 0) { | ||
2688 | len = UniStrnlen((wchar_t *) | ||
2689 | bcc_ptr, | ||
2690 | remaining_words | ||
2691 | - 1); | ||
2692 | ses->serverNOS = | ||
2693 | cifs_kcalloc(2 * (len + 1), | ||
2694 | GFP_KERNEL); | ||
2695 | cifs_strfromUCS_le(ses-> | ||
2696 | serverNOS, | ||
2697 | (wchar_t *) | ||
2698 | bcc_ptr, | ||
2699 | len, | ||
2700 | nls_codepage); | ||
2701 | bcc_ptr += 2 * (len + 1); | ||
2702 | ses->serverNOS[2 * len] = 0; | ||
2703 | ses->serverNOS[1+(2*len)] = 0; | ||
2704 | remaining_words -= len + 1; | ||
2705 | if (remaining_words > 0) { | ||
2706 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
2707 | /* last string not always null terminated (e.g. for Windows XP & 2000) */ | ||
2708 | ses->serverDomain = | ||
2709 | cifs_kcalloc(2 * | ||
2710 | (len + | ||
2711 | 1), | ||
2712 | GFP_KERNEL); | ||
2713 | cifs_strfromUCS_le | ||
2714 | (ses-> | ||
2715 | serverDomain, | ||
2716 | (wchar_t *) | ||
2717 | bcc_ptr, len, | ||
2718 | nls_codepage); | ||
2719 | bcc_ptr += | ||
2720 | 2 * (len + 1); | ||
2721 | ses-> | ||
2722 | serverDomain[2 | ||
2723 | * len] | ||
2724 | = 0; | ||
2725 | ses-> | ||
2726 | serverDomain[1 | ||
2727 | + | ||
2728 | (2 | ||
2729 | * | ||
2730 | len)] | ||
2731 | = 0; | ||
2732 | } /* else no more room so create dummy domain string */ | ||
2733 | else | ||
2734 | ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL); | ||
2735 | } else { /* no room so create dummy domain and NOS string */ | ||
2736 | ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); | ||
2737 | ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); | ||
2738 | } | ||
2739 | } else { /* ASCII */ | ||
2740 | len = strnlen(bcc_ptr, 1024); | ||
2741 | if (((long) bcc_ptr + len) - | ||
2742 | (long) pByteArea(smb_buffer_response) | ||
2743 | <= BCC(smb_buffer_response)) { | ||
2744 | ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); | ||
2745 | strncpy(ses->serverOS,bcc_ptr, len); | ||
2746 | |||
2747 | bcc_ptr += len; | ||
2748 | bcc_ptr[0] = 0; /* null terminate the string */ | ||
2749 | bcc_ptr++; | ||
2750 | |||
2751 | len = strnlen(bcc_ptr, 1024); | ||
2752 | ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL); | ||
2753 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
2754 | bcc_ptr += len; | ||
2755 | bcc_ptr[0] = 0; | ||
2756 | bcc_ptr++; | ||
2757 | |||
2758 | len = strnlen(bcc_ptr, 1024); | ||
2759 | ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL); | ||
2760 | strncpy(ses->serverDomain, bcc_ptr, len); | ||
2761 | bcc_ptr += len; | ||
2762 | bcc_ptr[0] = 0; | ||
2763 | bcc_ptr++; | ||
2764 | } else | ||
2765 | cFYI(1, | ||
2766 | ("Variable field of length %d extends beyond end of smb ", | ||
2767 | len)); | ||
2768 | } | ||
2769 | } else { | ||
2770 | cERROR(1, | ||
2771 | (" Security Blob Length extends beyond end of SMB")); | ||
2772 | } | ||
2773 | } else { | ||
2774 | cERROR(1, ("No session structure passed in.")); | ||
2775 | } | ||
2776 | } else { | ||
2777 | cERROR(1, | ||
2778 | (" Invalid Word count %d: ", | ||
2779 | smb_buffer_response->WordCount)); | ||
2780 | rc = -EIO; | ||
2781 | } | ||
2782 | |||
2783 | if (smb_buffer) | ||
2784 | cifs_buf_release(smb_buffer); | ||
2785 | |||
2786 | return rc; | ||
2787 | } | ||
2788 | |||
2789 | int | ||
2790 | CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | ||
2791 | const char *tree, struct cifsTconInfo *tcon, | ||
2792 | const struct nls_table *nls_codepage) | ||
2793 | { | ||
2794 | struct smb_hdr *smb_buffer; | ||
2795 | struct smb_hdr *smb_buffer_response; | ||
2796 | TCONX_REQ *pSMB; | ||
2797 | TCONX_RSP *pSMBr; | ||
2798 | unsigned char *bcc_ptr; | ||
2799 | int rc = 0; | ||
2800 | int length; | ||
2801 | __u16 count; | ||
2802 | |||
2803 | if (ses == NULL) | ||
2804 | return -EIO; | ||
2805 | |||
2806 | smb_buffer = cifs_buf_get(); | ||
2807 | if (smb_buffer == NULL) { | ||
2808 | return -ENOMEM; | ||
2809 | } | ||
2810 | smb_buffer_response = smb_buffer; | ||
2811 | |||
2812 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, | ||
2813 | NULL /*no tid */ , 4 /*wct */ ); | ||
2814 | smb_buffer->Uid = ses->Suid; | ||
2815 | pSMB = (TCONX_REQ *) smb_buffer; | ||
2816 | pSMBr = (TCONX_RSP *) smb_buffer_response; | ||
2817 | |||
2818 | pSMB->AndXCommand = 0xFF; | ||
2819 | pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); | ||
2820 | pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ | ||
2821 | bcc_ptr = &pSMB->Password[0]; | ||
2822 | bcc_ptr++; /* skip password */ | ||
2823 | |||
2824 | if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
2825 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
2826 | |||
2827 | if (ses->capabilities & CAP_STATUS32) { | ||
2828 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
2829 | } | ||
2830 | if (ses->capabilities & CAP_DFS) { | ||
2831 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
2832 | } | ||
2833 | if (ses->capabilities & CAP_UNICODE) { | ||
2834 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
2835 | length = | ||
2836 | cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage); | ||
2837 | bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */ | ||
2838 | bcc_ptr += 2; /* skip trailing null */ | ||
2839 | } else { /* ASCII */ | ||
2840 | |||
2841 | strcpy(bcc_ptr, tree); | ||
2842 | bcc_ptr += strlen(tree) + 1; | ||
2843 | } | ||
2844 | strcpy(bcc_ptr, "?????"); | ||
2845 | bcc_ptr += strlen("?????"); | ||
2846 | bcc_ptr += 1; | ||
2847 | count = bcc_ptr - &pSMB->Password[0]; | ||
2848 | pSMB->hdr.smb_buf_length += count; | ||
2849 | pSMB->ByteCount = cpu_to_le16(count); | ||
2850 | |||
2851 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0); | ||
2852 | |||
2853 | /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ | ||
2854 | /* above now done in SendReceive */ | ||
2855 | if ((rc == 0) && (tcon != NULL)) { | ||
2856 | tcon->tidStatus = CifsGood; | ||
2857 | tcon->tid = smb_buffer_response->Tid; | ||
2858 | bcc_ptr = pByteArea(smb_buffer_response); | ||
2859 | length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); | ||
2860 | /* skip service field (NB: this field is always ASCII) */ | ||
2861 | bcc_ptr += length + 1; | ||
2862 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); | ||
2863 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
2864 | length = UniStrnlen((wchar_t *) bcc_ptr, 512); | ||
2865 | if ((bcc_ptr + (2 * length)) - | ||
2866 | pByteArea(smb_buffer_response) <= | ||
2867 | BCC(smb_buffer_response)) { | ||
2868 | if(tcon->nativeFileSystem) | ||
2869 | kfree(tcon->nativeFileSystem); | ||
2870 | tcon->nativeFileSystem = | ||
2871 | cifs_kcalloc(length + 2, GFP_KERNEL); | ||
2872 | cifs_strfromUCS_le(tcon->nativeFileSystem, | ||
2873 | (wchar_t *) bcc_ptr, | ||
2874 | length, nls_codepage); | ||
2875 | bcc_ptr += 2 * length; | ||
2876 | bcc_ptr[0] = 0; /* null terminate the string */ | ||
2877 | bcc_ptr[1] = 0; | ||
2878 | bcc_ptr += 2; | ||
2879 | } | ||
2880 | /* else do not bother copying these informational fields */ | ||
2881 | } else { | ||
2882 | length = strnlen(bcc_ptr, 1024); | ||
2883 | if ((bcc_ptr + length) - | ||
2884 | pByteArea(smb_buffer_response) <= | ||
2885 | BCC(smb_buffer_response)) { | ||
2886 | if(tcon->nativeFileSystem) | ||
2887 | kfree(tcon->nativeFileSystem); | ||
2888 | tcon->nativeFileSystem = | ||
2889 | cifs_kcalloc(length + 1, GFP_KERNEL); | ||
2890 | strncpy(tcon->nativeFileSystem, bcc_ptr, | ||
2891 | length); | ||
2892 | } | ||
2893 | /* else do not bother copying these informational fields */ | ||
2894 | } | ||
2895 | tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); | ||
2896 | cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags)); | ||
2897 | } else if ((rc == 0) && tcon == NULL) { | ||
2898 | /* all we need to save for IPC$ connection */ | ||
2899 | ses->ipc_tid = smb_buffer_response->Tid; | ||
2900 | } | ||
2901 | |||
2902 | if (smb_buffer) | ||
2903 | cifs_buf_release(smb_buffer); | ||
2904 | return rc; | ||
2905 | } | ||
2906 | |||
2907 | int | ||
2908 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | ||
2909 | { | ||
2910 | int rc = 0; | ||
2911 | int xid; | ||
2912 | struct cifsSesInfo *ses = NULL; | ||
2913 | struct task_struct *cifsd_task; | ||
2914 | |||
2915 | xid = GetXid(); | ||
2916 | |||
2917 | if (cifs_sb->tcon) { | ||
2918 | ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/ | ||
2919 | rc = CIFSSMBTDis(xid, cifs_sb->tcon); | ||
2920 | if (rc == -EBUSY) { | ||
2921 | FreeXid(xid); | ||
2922 | return 0; | ||
2923 | } | ||
2924 | tconInfoFree(cifs_sb->tcon); | ||
2925 | if ((ses) && (ses->server)) { | ||
2926 | /* save off task so we do not refer to ses later */ | ||
2927 | cifsd_task = ses->server->tsk; | ||
2928 | cFYI(1, ("About to do SMBLogoff ")); | ||
2929 | rc = CIFSSMBLogoff(xid, ses); | ||
2930 | if (rc == -EBUSY) { | ||
2931 | FreeXid(xid); | ||
2932 | return 0; | ||
2933 | } else if (rc == -ESHUTDOWN) { | ||
2934 | cFYI(1,("Waking up socket by sending it signal")); | ||
2935 | if(cifsd_task) | ||
2936 | send_sig(SIGKILL,cifsd_task,1); | ||
2937 | rc = 0; | ||
2938 | } /* else - we have an smb session | ||
2939 | left on this socket do not kill cifsd */ | ||
2940 | } else | ||
2941 | cFYI(1, ("No session or bad tcon")); | ||
2942 | } | ||
2943 | |||
2944 | cifs_sb->tcon = NULL; | ||
2945 | if (ses) { | ||
2946 | set_current_state(TASK_INTERRUPTIBLE); | ||
2947 | schedule_timeout(HZ / 2); | ||
2948 | } | ||
2949 | if (ses) | ||
2950 | sesInfoFree(ses); | ||
2951 | |||
2952 | FreeXid(xid); | ||
2953 | return rc; /* BB check if we should always return zero here */ | ||
2954 | } | ||
2955 | |||
2956 | int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | ||
2957 | struct nls_table * nls_info) | ||
2958 | { | ||
2959 | int rc = 0; | ||
2960 | char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; | ||
2961 | int ntlmv2_flag = FALSE; | ||
2962 | |||
2963 | /* what if server changes its buffer size after dropping the session? */ | ||
2964 | if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { | ||
2965 | rc = CIFSSMBNegotiate(xid, pSesInfo); | ||
2966 | if(rc == -EAGAIN) /* retry only once on 1st time connection */ { | ||
2967 | rc = CIFSSMBNegotiate(xid, pSesInfo); | ||
2968 | if(rc == -EAGAIN) | ||
2969 | rc = -EHOSTDOWN; | ||
2970 | } | ||
2971 | if(rc == 0) { | ||
2972 | spin_lock(&GlobalMid_Lock); | ||
2973 | if(pSesInfo->server->tcpStatus != CifsExiting) | ||
2974 | pSesInfo->server->tcpStatus = CifsGood; | ||
2975 | else | ||
2976 | rc = -EHOSTDOWN; | ||
2977 | spin_unlock(&GlobalMid_Lock); | ||
2978 | |||
2979 | } | ||
2980 | } | ||
2981 | if (!rc) { | ||
2982 | pSesInfo->capabilities = pSesInfo->server->capabilities; | ||
2983 | if(linuxExtEnabled == 0) | ||
2984 | pSesInfo->capabilities &= (~CAP_UNIX); | ||
2985 | pSesInfo->sequence_number = 0; | ||
2986 | cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", | ||
2987 | pSesInfo->server->secMode, | ||
2988 | pSesInfo->server->capabilities, | ||
2989 | pSesInfo->server->timeZone)); | ||
2990 | if (extended_security | ||
2991 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
2992 | && (pSesInfo->server->secType == NTLMSSP)) { | ||
2993 | cFYI(1, ("New style sesssetup ")); | ||
2994 | rc = CIFSSpnegoSessSetup(xid, pSesInfo, | ||
2995 | NULL /* security blob */, | ||
2996 | 0 /* blob length */, | ||
2997 | nls_info); | ||
2998 | } else if (extended_security | ||
2999 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
3000 | && (pSesInfo->server->secType == RawNTLMSSP)) { | ||
3001 | cFYI(1, ("NTLMSSP sesssetup ")); | ||
3002 | rc = CIFSNTLMSSPNegotiateSessSetup(xid, | ||
3003 | pSesInfo, | ||
3004 | &ntlmv2_flag, | ||
3005 | nls_info); | ||
3006 | if (!rc) { | ||
3007 | if(ntlmv2_flag) { | ||
3008 | char * v2_response; | ||
3009 | cFYI(1,("Can use more secure NTLM version 2 password hash")); | ||
3010 | if(CalcNTLMv2_partial_mac_key(pSesInfo, | ||
3011 | nls_info)) { | ||
3012 | rc = -ENOMEM; | ||
3013 | goto ss_err_exit; | ||
3014 | } else | ||
3015 | v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); | ||
3016 | if(v2_response) { | ||
3017 | CalcNTLMv2_response(pSesInfo,v2_response); | ||
3018 | /* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ | ||
3019 | kfree(v2_response); | ||
3020 | /* BB Put dummy sig in SessSetup PDU? */ | ||
3021 | } else { | ||
3022 | rc = -ENOMEM; | ||
3023 | goto ss_err_exit; | ||
3024 | } | ||
3025 | |||
3026 | } else { | ||
3027 | SMBNTencrypt(pSesInfo->password, | ||
3028 | pSesInfo->server->cryptKey, | ||
3029 | ntlm_session_key); | ||
3030 | |||
3031 | cifs_calculate_mac_key(pSesInfo->mac_signing_key, | ||
3032 | ntlm_session_key, | ||
3033 | pSesInfo->password); | ||
3034 | } | ||
3035 | /* for better security the weaker lanman hash not sent | ||
3036 | in AuthSessSetup so we no longer calculate it */ | ||
3037 | |||
3038 | rc = CIFSNTLMSSPAuthSessSetup(xid, | ||
3039 | pSesInfo, | ||
3040 | ntlm_session_key, | ||
3041 | ntlmv2_flag, | ||
3042 | nls_info); | ||
3043 | } | ||
3044 | } else { /* old style NTLM 0.12 session setup */ | ||
3045 | SMBNTencrypt(pSesInfo->password, | ||
3046 | pSesInfo->server->cryptKey, | ||
3047 | ntlm_session_key); | ||
3048 | |||
3049 | cifs_calculate_mac_key(pSesInfo->mac_signing_key, | ||
3050 | ntlm_session_key, pSesInfo->password); | ||
3051 | rc = CIFSSessSetup(xid, pSesInfo, | ||
3052 | ntlm_session_key, nls_info); | ||
3053 | } | ||
3054 | if (rc) { | ||
3055 | cERROR(1,("Send error in SessSetup = %d",rc)); | ||
3056 | } else { | ||
3057 | cFYI(1,("CIFS Session Established successfully")); | ||
3058 | pSesInfo->status = CifsGood; | ||
3059 | } | ||
3060 | } | ||
3061 | ss_err_exit: | ||
3062 | return rc; | ||
3063 | } | ||
3064 | |||
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c new file mode 100644 index 000000000000..f54e1866f0f4 --- /dev/null +++ b/fs/cifs/dir.c | |||
@@ -0,0 +1,523 @@ | |||
1 | /* | ||
2 | * fs/cifs/dir.c | ||
3 | * | ||
4 | * vfs operations that deal with dentries | ||
5 | * | ||
6 | * Copyright (C) International Business Machines Corp., 2002,2003 | ||
7 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
8 | * | ||
9 | * This library is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU Lesser General Public License as published | ||
11 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This library is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
17 | * the GNU Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public License | ||
20 | * along with this library; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/stat.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/namei.h> | ||
27 | #include "cifsfs.h" | ||
28 | #include "cifspdu.h" | ||
29 | #include "cifsglob.h" | ||
30 | #include "cifsproto.h" | ||
31 | #include "cifs_debug.h" | ||
32 | #include "cifs_fs_sb.h" | ||
33 | |||
34 | void | ||
35 | renew_parental_timestamps(struct dentry *direntry) | ||
36 | { | ||
37 | /* BB check if there is a way to get the kernel to do this or if we really need this */ | ||
38 | do { | ||
39 | direntry->d_time = jiffies; | ||
40 | direntry = direntry->d_parent; | ||
41 | } while (!IS_ROOT(direntry)); | ||
42 | } | ||
43 | |||
44 | /* Note: caller must free return buffer */ | ||
45 | char * | ||
46 | build_path_from_dentry(struct dentry *direntry) | ||
47 | { | ||
48 | struct dentry *temp; | ||
49 | int namelen = 0; | ||
50 | char *full_path; | ||
51 | |||
52 | if(direntry == NULL) | ||
53 | return NULL; /* not much we can do if dentry is freed and | ||
54 | we need to reopen the file after it was closed implicitly | ||
55 | when the server crashed */ | ||
56 | |||
57 | cifs_bp_rename_retry: | ||
58 | for (temp = direntry; !IS_ROOT(temp);) { | ||
59 | namelen += (1 + temp->d_name.len); | ||
60 | temp = temp->d_parent; | ||
61 | if(temp == NULL) { | ||
62 | cERROR(1,("corrupt dentry")); | ||
63 | return NULL; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | full_path = kmalloc(namelen+1, GFP_KERNEL); | ||
68 | if(full_path == NULL) | ||
69 | return full_path; | ||
70 | full_path[namelen] = 0; /* trailing null */ | ||
71 | |||
72 | for (temp = direntry; !IS_ROOT(temp);) { | ||
73 | namelen -= 1 + temp->d_name.len; | ||
74 | if (namelen < 0) { | ||
75 | break; | ||
76 | } else { | ||
77 | full_path[namelen] = '\\'; | ||
78 | strncpy(full_path + namelen + 1, temp->d_name.name, | ||
79 | temp->d_name.len); | ||
80 | cFYI(0, (" name: %s ", full_path + namelen)); | ||
81 | } | ||
82 | temp = temp->d_parent; | ||
83 | if(temp == NULL) { | ||
84 | cERROR(1,("corrupt dentry")); | ||
85 | kfree(full_path); | ||
86 | return NULL; | ||
87 | } | ||
88 | } | ||
89 | if (namelen != 0) { | ||
90 | cERROR(1, | ||
91 | ("We did not end path lookup where we expected namelen is %d", | ||
92 | namelen)); | ||
93 | /* presumably this is only possible if we were racing with a rename | ||
94 | of one of the parent directories (we can not lock the dentries | ||
95 | above us to prevent this, but retrying should be harmless) */ | ||
96 | kfree(full_path); | ||
97 | namelen = 0; | ||
98 | goto cifs_bp_rename_retry; | ||
99 | } | ||
100 | |||
101 | return full_path; | ||
102 | } | ||
103 | |||
104 | /* Note: caller must free return buffer */ | ||
105 | char * | ||
106 | build_wildcard_path_from_dentry(struct dentry *direntry) | ||
107 | { | ||
108 | struct dentry *temp; | ||
109 | int namelen = 0; | ||
110 | char *full_path; | ||
111 | |||
112 | if(direntry == NULL) | ||
113 | return NULL; /* not much we can do if dentry is freed and | ||
114 | we need to reopen the file after it was closed implicitly | ||
115 | when the server crashed */ | ||
116 | |||
117 | cifs_bwp_rename_retry: | ||
118 | for (temp = direntry; !IS_ROOT(temp);) { | ||
119 | namelen += (1 + temp->d_name.len); | ||
120 | temp = temp->d_parent; | ||
121 | if(temp == NULL) { | ||
122 | cERROR(1,("corrupt dentry")); | ||
123 | return NULL; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | full_path = kmalloc(namelen+3, GFP_KERNEL); | ||
128 | if(full_path == NULL) | ||
129 | return full_path; | ||
130 | |||
131 | full_path[namelen] = '\\'; | ||
132 | full_path[namelen+1] = '*'; | ||
133 | full_path[namelen+2] = 0; /* trailing null */ | ||
134 | |||
135 | for (temp = direntry; !IS_ROOT(temp);) { | ||
136 | namelen -= 1 + temp->d_name.len; | ||
137 | if (namelen < 0) { | ||
138 | break; | ||
139 | } else { | ||
140 | full_path[namelen] = '\\'; | ||
141 | strncpy(full_path + namelen + 1, temp->d_name.name, | ||
142 | temp->d_name.len); | ||
143 | cFYI(0, (" name: %s ", full_path + namelen)); | ||
144 | } | ||
145 | temp = temp->d_parent; | ||
146 | if(temp == NULL) { | ||
147 | cERROR(1,("corrupt dentry")); | ||
148 | kfree(full_path); | ||
149 | return NULL; | ||
150 | } | ||
151 | } | ||
152 | if (namelen != 0) { | ||
153 | cERROR(1, | ||
154 | ("We did not end path lookup where we expected namelen is %d", | ||
155 | namelen)); | ||
156 | /* presumably this is only possible if we were racing with a rename | ||
157 | of one of the parent directories (we can not lock the dentries | ||
158 | above us to prevent this, but retrying should be harmless) */ | ||
159 | kfree(full_path); | ||
160 | namelen = 0; | ||
161 | goto cifs_bwp_rename_retry; | ||
162 | } | ||
163 | |||
164 | return full_path; | ||
165 | } | ||
166 | |||
167 | /* Inode operations in similar order to how they appear in the Linux file fs.h */ | ||
168 | |||
169 | int | ||
170 | cifs_create(struct inode *inode, struct dentry *direntry, int mode, | ||
171 | struct nameidata *nd) | ||
172 | { | ||
173 | int rc = -ENOENT; | ||
174 | int xid; | ||
175 | int oplock = 0; | ||
176 | int desiredAccess = GENERIC_READ | GENERIC_WRITE; | ||
177 | __u16 fileHandle; | ||
178 | struct cifs_sb_info *cifs_sb; | ||
179 | struct cifsTconInfo *pTcon; | ||
180 | char *full_path = NULL; | ||
181 | FILE_ALL_INFO * buf = NULL; | ||
182 | struct inode *newinode = NULL; | ||
183 | struct cifsFileInfo * pCifsFile = NULL; | ||
184 | struct cifsInodeInfo * pCifsInode; | ||
185 | int disposition = FILE_OVERWRITE_IF; | ||
186 | int write_only = FALSE; | ||
187 | |||
188 | xid = GetXid(); | ||
189 | |||
190 | cifs_sb = CIFS_SB(inode->i_sb); | ||
191 | pTcon = cifs_sb->tcon; | ||
192 | |||
193 | down(&direntry->d_sb->s_vfs_rename_sem); | ||
194 | full_path = build_path_from_dentry(direntry); | ||
195 | up(&direntry->d_sb->s_vfs_rename_sem); | ||
196 | if(full_path == NULL) { | ||
197 | FreeXid(xid); | ||
198 | return -ENOMEM; | ||
199 | } | ||
200 | |||
201 | if(nd) { | ||
202 | if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY) | ||
203 | desiredAccess = GENERIC_READ; | ||
204 | else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) { | ||
205 | desiredAccess = GENERIC_WRITE; | ||
206 | write_only = TRUE; | ||
207 | } else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) { | ||
208 | /* GENERIC_ALL is too much permission to request */ | ||
209 | /* can cause unnecessary access denied on create */ | ||
210 | /* desiredAccess = GENERIC_ALL; */ | ||
211 | desiredAccess = GENERIC_READ | GENERIC_WRITE; | ||
212 | } | ||
213 | |||
214 | if((nd->intent.open.flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | ||
215 | disposition = FILE_CREATE; | ||
216 | else if((nd->intent.open.flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) | ||
217 | disposition = FILE_OVERWRITE_IF; | ||
218 | else if((nd->intent.open.flags & O_CREAT) == O_CREAT) | ||
219 | disposition = FILE_OPEN_IF; | ||
220 | else { | ||
221 | cFYI(1,("Create flag not set in create function")); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | /* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */ | ||
226 | if (oplockEnabled) | ||
227 | oplock = REQ_OPLOCK; | ||
228 | |||
229 | buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); | ||
230 | if(buf == NULL) { | ||
231 | kfree(full_path); | ||
232 | FreeXid(xid); | ||
233 | return -ENOMEM; | ||
234 | } | ||
235 | |||
236 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, | ||
237 | desiredAccess, CREATE_NOT_DIR, | ||
238 | &fileHandle, &oplock, buf, cifs_sb->local_nls); | ||
239 | if (rc) { | ||
240 | cFYI(1, ("cifs_create returned 0x%x ", rc)); | ||
241 | } else { | ||
242 | /* If Open reported that we actually created a file | ||
243 | then we now have to set the mode if possible */ | ||
244 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && | ||
245 | (oplock & CIFS_CREATE_ACTION)) | ||
246 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | ||
247 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, | ||
248 | (__u64)current->euid, | ||
249 | (__u64)current->egid, | ||
250 | 0 /* dev */, | ||
251 | cifs_sb->local_nls); | ||
252 | } else { | ||
253 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, | ||
254 | (__u64)-1, | ||
255 | (__u64)-1, | ||
256 | 0 /* dev */, | ||
257 | cifs_sb->local_nls); | ||
258 | } | ||
259 | else { | ||
260 | /* BB implement via Windows security descriptors */ | ||
261 | /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ | ||
262 | /* could set r/o dos attribute if mode & 0222 == 0 */ | ||
263 | } | ||
264 | |||
265 | /* BB server might mask mode so we have to query for Unix case*/ | ||
266 | if (pTcon->ses->capabilities & CAP_UNIX) | ||
267 | rc = cifs_get_inode_info_unix(&newinode, full_path, | ||
268 | inode->i_sb,xid); | ||
269 | else { | ||
270 | rc = cifs_get_inode_info(&newinode, full_path, | ||
271 | buf, inode->i_sb,xid); | ||
272 | if(newinode) | ||
273 | newinode->i_mode = mode; | ||
274 | } | ||
275 | |||
276 | if (rc != 0) { | ||
277 | cFYI(1,("Create worked but get_inode_info failed with rc = %d", | ||
278 | rc)); | ||
279 | } else { | ||
280 | direntry->d_op = &cifs_dentry_ops; | ||
281 | d_instantiate(direntry, newinode); | ||
282 | } | ||
283 | if((nd->flags & LOOKUP_OPEN) == FALSE) { | ||
284 | /* mknod case - do not leave file open */ | ||
285 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
286 | } else if(newinode) { | ||
287 | pCifsFile = (struct cifsFileInfo *) | ||
288 | kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); | ||
289 | |||
290 | if (pCifsFile) { | ||
291 | memset((char *)pCifsFile, 0, | ||
292 | sizeof (struct cifsFileInfo)); | ||
293 | pCifsFile->netfid = fileHandle; | ||
294 | pCifsFile->pid = current->tgid; | ||
295 | pCifsFile->pInode = newinode; | ||
296 | pCifsFile->invalidHandle = FALSE; | ||
297 | pCifsFile->closePend = FALSE; | ||
298 | init_MUTEX(&pCifsFile->fh_sem); | ||
299 | /* put the following in at open now */ | ||
300 | /* pCifsFile->pfile = file; */ | ||
301 | write_lock(&GlobalSMBSeslock); | ||
302 | list_add(&pCifsFile->tlist,&pTcon->openFileList); | ||
303 | pCifsInode = CIFS_I(newinode); | ||
304 | if(pCifsInode) { | ||
305 | /* if readable file instance put first in list*/ | ||
306 | if (write_only == TRUE) { | ||
307 | list_add_tail(&pCifsFile->flist, | ||
308 | &pCifsInode->openFileList); | ||
309 | } else { | ||
310 | list_add(&pCifsFile->flist, | ||
311 | &pCifsInode->openFileList); | ||
312 | } | ||
313 | if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
314 | pCifsInode->clientCanCacheAll = TRUE; | ||
315 | pCifsInode->clientCanCacheRead = TRUE; | ||
316 | cFYI(1,("Exclusive Oplock granted on inode %p", | ||
317 | newinode)); | ||
318 | } else if((oplock & 0xF) == OPLOCK_READ) | ||
319 | pCifsInode->clientCanCacheRead = TRUE; | ||
320 | } | ||
321 | write_unlock(&GlobalSMBSeslock); | ||
322 | } | ||
323 | } | ||
324 | } | ||
325 | |||
326 | if (buf) | ||
327 | kfree(buf); | ||
328 | if (full_path) | ||
329 | kfree(full_path); | ||
330 | FreeXid(xid); | ||
331 | |||
332 | return rc; | ||
333 | } | ||
334 | |||
335 | int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t device_number) | ||
336 | { | ||
337 | int rc = -EPERM; | ||
338 | int xid; | ||
339 | struct cifs_sb_info *cifs_sb; | ||
340 | struct cifsTconInfo *pTcon; | ||
341 | char *full_path = NULL; | ||
342 | struct inode * newinode = NULL; | ||
343 | |||
344 | if (!old_valid_dev(device_number)) | ||
345 | return -EINVAL; | ||
346 | |||
347 | xid = GetXid(); | ||
348 | |||
349 | cifs_sb = CIFS_SB(inode->i_sb); | ||
350 | pTcon = cifs_sb->tcon; | ||
351 | |||
352 | down(&direntry->d_sb->s_vfs_rename_sem); | ||
353 | full_path = build_path_from_dentry(direntry); | ||
354 | up(&direntry->d_sb->s_vfs_rename_sem); | ||
355 | if(full_path == NULL) | ||
356 | rc = -ENOMEM; | ||
357 | |||
358 | if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { | ||
359 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | ||
360 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, | ||
361 | mode,(__u64)current->euid,(__u64)current->egid, | ||
362 | device_number, cifs_sb->local_nls); | ||
363 | } else { | ||
364 | rc = CIFSSMBUnixSetPerms(xid, pTcon, | ||
365 | full_path, mode, (__u64)-1, (__u64)-1, | ||
366 | device_number, cifs_sb->local_nls); | ||
367 | } | ||
368 | |||
369 | if(!rc) { | ||
370 | rc = cifs_get_inode_info_unix(&newinode, full_path, | ||
371 | inode->i_sb,xid); | ||
372 | direntry->d_op = &cifs_dentry_ops; | ||
373 | if(rc == 0) | ||
374 | d_instantiate(direntry, newinode); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | if (full_path) | ||
379 | kfree(full_path); | ||
380 | FreeXid(xid); | ||
381 | |||
382 | return rc; | ||
383 | } | ||
384 | |||
385 | |||
386 | struct dentry * | ||
387 | cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct nameidata *nd) | ||
388 | { | ||
389 | int xid; | ||
390 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ | ||
391 | struct cifs_sb_info *cifs_sb; | ||
392 | struct cifsTconInfo *pTcon; | ||
393 | struct inode *newInode = NULL; | ||
394 | char *full_path = NULL; | ||
395 | |||
396 | xid = GetXid(); | ||
397 | |||
398 | cFYI(1, | ||
399 | (" parent inode = 0x%p name is: %s and dentry = 0x%p", | ||
400 | parent_dir_inode, direntry->d_name.name, direntry)); | ||
401 | |||
402 | /* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */ | ||
403 | |||
404 | /* check whether path exists */ | ||
405 | |||
406 | cifs_sb = CIFS_SB(parent_dir_inode->i_sb); | ||
407 | pTcon = cifs_sb->tcon; | ||
408 | |||
409 | /* can not grab the rename sem here since it would | ||
410 | deadlock in the cases (beginning of sys_rename itself) | ||
411 | in which we already have the sb rename sem */ | ||
412 | full_path = build_path_from_dentry(direntry); | ||
413 | if(full_path == NULL) { | ||
414 | FreeXid(xid); | ||
415 | return ERR_PTR(-ENOMEM); | ||
416 | } | ||
417 | |||
418 | if (direntry->d_inode != NULL) { | ||
419 | cFYI(1, (" non-NULL inode in lookup")); | ||
420 | } else { | ||
421 | cFYI(1, (" NULL inode in lookup")); | ||
422 | } | ||
423 | cFYI(1, | ||
424 | (" Full path: %s inode = 0x%p", full_path, direntry->d_inode)); | ||
425 | |||
426 | if (pTcon->ses->capabilities & CAP_UNIX) | ||
427 | rc = cifs_get_inode_info_unix(&newInode, full_path, | ||
428 | parent_dir_inode->i_sb,xid); | ||
429 | else | ||
430 | rc = cifs_get_inode_info(&newInode, full_path, NULL, | ||
431 | parent_dir_inode->i_sb,xid); | ||
432 | |||
433 | if ((rc == 0) && (newInode != NULL)) { | ||
434 | direntry->d_op = &cifs_dentry_ops; | ||
435 | d_add(direntry, newInode); | ||
436 | |||
437 | /* since paths are not looked up by component - the parent directories are presumed to be good here */ | ||
438 | renew_parental_timestamps(direntry); | ||
439 | |||
440 | } else if (rc == -ENOENT) { | ||
441 | rc = 0; | ||
442 | d_add(direntry, NULL); | ||
443 | } else { | ||
444 | cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc)); | ||
445 | /* BB special case check for Access Denied - watch security | ||
446 | exposure of returning dir info implicitly via different rc | ||
447 | if file exists or not but no access BB */ | ||
448 | } | ||
449 | |||
450 | if (full_path) | ||
451 | kfree(full_path); | ||
452 | FreeXid(xid); | ||
453 | return ERR_PTR(rc); | ||
454 | } | ||
455 | |||
456 | int | ||
457 | cifs_dir_open(struct inode *inode, struct file *file) | ||
458 | { /* NB: currently unused since searches are opened in readdir */ | ||
459 | int rc = 0; | ||
460 | int xid; | ||
461 | struct cifs_sb_info *cifs_sb; | ||
462 | struct cifsTconInfo *pTcon; | ||
463 | char *full_path = NULL; | ||
464 | |||
465 | xid = GetXid(); | ||
466 | |||
467 | cifs_sb = CIFS_SB(inode->i_sb); | ||
468 | pTcon = cifs_sb->tcon; | ||
469 | |||
470 | if(file->f_dentry) { | ||
471 | down(&file->f_dentry->d_sb->s_vfs_rename_sem); | ||
472 | full_path = build_wildcard_path_from_dentry(file->f_dentry); | ||
473 | up(&file->f_dentry->d_sb->s_vfs_rename_sem); | ||
474 | } else { | ||
475 | FreeXid(xid); | ||
476 | return -EIO; | ||
477 | } | ||
478 | |||
479 | cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path)); | ||
480 | |||
481 | if (full_path) | ||
482 | kfree(full_path); | ||
483 | FreeXid(xid); | ||
484 | return rc; | ||
485 | } | ||
486 | |||
487 | static int | ||
488 | cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | ||
489 | { | ||
490 | int isValid = 1; | ||
491 | |||
492 | /* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */ | ||
493 | |||
494 | if (direntry->d_inode) { | ||
495 | if (cifs_revalidate(direntry)) { | ||
496 | /* unlock_kernel(); */ | ||
497 | return 0; | ||
498 | } | ||
499 | } else { | ||
500 | cFYI(1, | ||
501 | ("In cifs_d_revalidate with no inode but name = %s and dentry 0x%p", | ||
502 | direntry->d_name.name, direntry)); | ||
503 | } | ||
504 | |||
505 | /* unlock_kernel(); */ | ||
506 | |||
507 | return isValid; | ||
508 | } | ||
509 | |||
510 | /* static int cifs_d_delete(struct dentry *direntry) | ||
511 | { | ||
512 | int rc = 0; | ||
513 | |||
514 | cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name)); | ||
515 | |||
516 | return rc; | ||
517 | } */ | ||
518 | |||
519 | struct dentry_operations cifs_dentry_ops = { | ||
520 | .d_revalidate = cifs_d_revalidate, | ||
521 | /* d_delete: cifs_d_delete, *//* not needed except for debugging */ | ||
522 | /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ | ||
523 | }; | ||
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c new file mode 100644 index 000000000000..9d24c40f1967 --- /dev/null +++ b/fs/cifs/fcntl.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * fs/cifs/fcntl.c | ||
3 | * | ||
4 | * vfs operations that deal with the file control API | ||
5 | * | ||
6 | * Copyright (C) International Business Machines Corp., 2003,2004 | ||
7 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
8 | * | ||
9 | * This library is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU Lesser General Public License as published | ||
11 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This library is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
17 | * the GNU Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public License | ||
20 | * along with this library; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/stat.h> | ||
25 | #include <linux/fcntl.h> | ||
26 | #include "cifsglob.h" | ||
27 | #include "cifsproto.h" | ||
28 | #include "cifs_unicode.h" | ||
29 | #include "cifs_debug.h" | ||
30 | #include "cifsfs.h" | ||
31 | |||
32 | static __u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags) | ||
33 | { | ||
34 | __u32 cifs_ntfy_flags = 0; | ||
35 | |||
36 | /* No way on Linux VFS to ask to monitor xattr | ||
37 | changes (and no stream support either */ | ||
38 | if(fcntl_notify_flags & DN_ACCESS) { | ||
39 | cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS; | ||
40 | } | ||
41 | if(fcntl_notify_flags & DN_MODIFY) { | ||
42 | /* What does this mean on directories? */ | ||
43 | cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE | | ||
44 | FILE_NOTIFY_CHANGE_SIZE; | ||
45 | } | ||
46 | if(fcntl_notify_flags & DN_CREATE) { | ||
47 | cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_CREATION | | ||
48 | FILE_NOTIFY_CHANGE_LAST_WRITE; | ||
49 | } | ||
50 | if(fcntl_notify_flags & DN_DELETE) { | ||
51 | cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE; | ||
52 | } | ||
53 | if(fcntl_notify_flags & DN_RENAME) { | ||
54 | /* BB review this - checking various server behaviors */ | ||
55 | cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_DIR_NAME | | ||
56 | FILE_NOTIFY_CHANGE_FILE_NAME; | ||
57 | } | ||
58 | if(fcntl_notify_flags & DN_ATTRIB) { | ||
59 | cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_SECURITY | | ||
60 | FILE_NOTIFY_CHANGE_ATTRIBUTES; | ||
61 | } | ||
62 | /* if(fcntl_notify_flags & DN_MULTISHOT) { | ||
63 | cifs_ntfy_flags |= ; | ||
64 | } */ /* BB fixme - not sure how to handle this with CIFS yet */ | ||
65 | |||
66 | |||
67 | return cifs_ntfy_flags; | ||
68 | } | ||
69 | |||
70 | int cifs_dir_notify(struct file * file, unsigned long arg) | ||
71 | { | ||
72 | int xid; | ||
73 | int rc = -EINVAL; | ||
74 | int oplock = FALSE; | ||
75 | struct cifs_sb_info *cifs_sb; | ||
76 | struct cifsTconInfo *pTcon; | ||
77 | char *full_path = NULL; | ||
78 | __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; | ||
79 | __u16 netfid; | ||
80 | |||
81 | xid = GetXid(); | ||
82 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
83 | pTcon = cifs_sb->tcon; | ||
84 | |||
85 | down(&file->f_dentry->d_sb->s_vfs_rename_sem); | ||
86 | full_path = build_path_from_dentry(file->f_dentry); | ||
87 | up(&file->f_dentry->d_sb->s_vfs_rename_sem); | ||
88 | |||
89 | if(full_path == NULL) { | ||
90 | rc = -ENOMEM; | ||
91 | } else { | ||
92 | cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */ | ||
93 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, | ||
94 | GENERIC_READ | SYNCHRONIZE, 0 /* create options */, | ||
95 | &netfid, &oplock,NULL, cifs_sb->local_nls); | ||
96 | /* BB fixme - add this handle to a notify handle list */ | ||
97 | if(rc) { | ||
98 | cERROR(1,("Could not open directory for notify")); /* BB remove BB */ | ||
99 | } else { | ||
100 | filter = convert_to_cifs_notify_flags(arg); | ||
101 | if(filter != 0) { | ||
102 | rc = CIFSSMBNotify(xid, pTcon, 0 /* no subdirs */, netfid, | ||
103 | filter, cifs_sb->local_nls); | ||
104 | } else { | ||
105 | rc = -EINVAL; | ||
106 | } | ||
107 | /* BB add code to close file eventually (at unmount | ||
108 | it would close automatically but may be a way | ||
109 | to do it easily when inode freed or when | ||
110 | notify info is cleared/changed */ | ||
111 | cERROR(1,("notify rc %d",rc)); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | FreeXid(xid); | ||
116 | return rc; | ||
117 | } | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c new file mode 100644 index 000000000000..dcab7cf1b53b --- /dev/null +++ b/fs/cifs/file.c | |||
@@ -0,0 +1,1675 @@ | |||
1 | /* | ||
2 | * fs/cifs/file.c | ||
3 | * | ||
4 | * vfs operations that deal with files | ||
5 | * | ||
6 | * Copyright (C) International Business Machines Corp., 2002,2003 | ||
7 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
8 | * | ||
9 | * This library is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU Lesser General Public License as published | ||
11 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This library is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
17 | * the GNU Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public License | ||
20 | * along with this library; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/stat.h> | ||
25 | #include <linux/fcntl.h> | ||
26 | #include <linux/pagemap.h> | ||
27 | #include <linux/pagevec.h> | ||
28 | #include <linux/smp_lock.h> | ||
29 | #include <asm/div64.h> | ||
30 | #include "cifsfs.h" | ||
31 | #include "cifspdu.h" | ||
32 | #include "cifsglob.h" | ||
33 | #include "cifsproto.h" | ||
34 | #include "cifs_unicode.h" | ||
35 | #include "cifs_debug.h" | ||
36 | #include "cifs_fs_sb.h" | ||
37 | |||
38 | static inline struct cifsFileInfo *cifs_init_private( | ||
39 | struct cifsFileInfo *private_data, struct inode *inode, | ||
40 | struct file *file, __u16 netfid) | ||
41 | { | ||
42 | memset(private_data, 0, sizeof(struct cifsFileInfo)); | ||
43 | private_data->netfid = netfid; | ||
44 | private_data->pid = current->tgid; | ||
45 | init_MUTEX(&private_data->fh_sem); | ||
46 | private_data->pfile = file; /* needed for writepage */ | ||
47 | private_data->pInode = inode; | ||
48 | private_data->invalidHandle = FALSE; | ||
49 | private_data->closePend = FALSE; | ||
50 | |||
51 | return private_data; | ||
52 | } | ||
53 | |||
54 | static inline int cifs_convert_flags(unsigned int flags) | ||
55 | { | ||
56 | if ((flags & O_ACCMODE) == O_RDONLY) | ||
57 | return GENERIC_READ; | ||
58 | else if ((flags & O_ACCMODE) == O_WRONLY) | ||
59 | return GENERIC_WRITE; | ||
60 | else if ((flags & O_ACCMODE) == O_RDWR) { | ||
61 | /* GENERIC_ALL is too much permission to request | ||
62 | can cause unnecessary access denied on create */ | ||
63 | /* return GENERIC_ALL; */ | ||
64 | return (GENERIC_READ | GENERIC_WRITE); | ||
65 | } | ||
66 | |||
67 | return 0x20197; | ||
68 | } | ||
69 | |||
70 | static inline int cifs_get_disposition(unsigned int flags) | ||
71 | { | ||
72 | if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | ||
73 | return FILE_CREATE; | ||
74 | else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) | ||
75 | return FILE_OVERWRITE_IF; | ||
76 | else if ((flags & O_CREAT) == O_CREAT) | ||
77 | return FILE_OPEN_IF; | ||
78 | else | ||
79 | return FILE_OPEN; | ||
80 | } | ||
81 | |||
82 | /* all arguments to this function must be checked for validity in caller */ | ||
83 | static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, | ||
84 | struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile, | ||
85 | struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf, | ||
86 | char *full_path, int xid) | ||
87 | { | ||
88 | struct timespec temp; | ||
89 | int rc; | ||
90 | |||
91 | /* want handles we can use to read with first | ||
92 | in the list so we do not have to walk the | ||
93 | list to search for one in prepare_write */ | ||
94 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | ||
95 | list_add_tail(&pCifsFile->flist, | ||
96 | &pCifsInode->openFileList); | ||
97 | } else { | ||
98 | list_add(&pCifsFile->flist, | ||
99 | &pCifsInode->openFileList); | ||
100 | } | ||
101 | write_unlock(&GlobalSMBSeslock); | ||
102 | write_unlock(&file->f_owner.lock); | ||
103 | if (pCifsInode->clientCanCacheRead) { | ||
104 | /* we have the inode open somewhere else | ||
105 | no need to discard cache data */ | ||
106 | goto client_can_cache; | ||
107 | } | ||
108 | |||
109 | /* BB need same check in cifs_create too? */ | ||
110 | /* if not oplocked, invalidate inode pages if mtime or file | ||
111 | size changed */ | ||
112 | temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime)); | ||
113 | if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) && | ||
114 | (file->f_dentry->d_inode->i_size == | ||
115 | (loff_t)le64_to_cpu(buf->EndOfFile))) { | ||
116 | cFYI(1, ("inode unchanged on server")); | ||
117 | } else { | ||
118 | if (file->f_dentry->d_inode->i_mapping) { | ||
119 | /* BB no need to lock inode until after invalidate | ||
120 | since namei code should already have it locked? */ | ||
121 | filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); | ||
122 | filemap_fdatawait(file->f_dentry->d_inode->i_mapping); | ||
123 | } | ||
124 | cFYI(1, ("invalidating remote inode since open detected it " | ||
125 | "changed")); | ||
126 | invalidate_remote_inode(file->f_dentry->d_inode); | ||
127 | } | ||
128 | |||
129 | client_can_cache: | ||
130 | if (pTcon->ses->capabilities & CAP_UNIX) | ||
131 | rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, | ||
132 | full_path, inode->i_sb, xid); | ||
133 | else | ||
134 | rc = cifs_get_inode_info(&file->f_dentry->d_inode, | ||
135 | full_path, buf, inode->i_sb, xid); | ||
136 | |||
137 | if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
138 | pCifsInode->clientCanCacheAll = TRUE; | ||
139 | pCifsInode->clientCanCacheRead = TRUE; | ||
140 | cFYI(1, ("Exclusive Oplock granted on inode %p", | ||
141 | file->f_dentry->d_inode)); | ||
142 | } else if ((*oplock & 0xF) == OPLOCK_READ) | ||
143 | pCifsInode->clientCanCacheRead = TRUE; | ||
144 | |||
145 | return rc; | ||
146 | } | ||
147 | |||
148 | int cifs_open(struct inode *inode, struct file *file) | ||
149 | { | ||
150 | int rc = -EACCES; | ||
151 | int xid, oplock; | ||
152 | struct cifs_sb_info *cifs_sb; | ||
153 | struct cifsTconInfo *pTcon; | ||
154 | struct cifsFileInfo *pCifsFile; | ||
155 | struct cifsInodeInfo *pCifsInode; | ||
156 | struct list_head *tmp; | ||
157 | char *full_path = NULL; | ||
158 | int desiredAccess; | ||
159 | int disposition; | ||
160 | __u16 netfid; | ||
161 | FILE_ALL_INFO *buf = NULL; | ||
162 | |||
163 | xid = GetXid(); | ||
164 | |||
165 | cifs_sb = CIFS_SB(inode->i_sb); | ||
166 | pTcon = cifs_sb->tcon; | ||
167 | |||
168 | if (file->f_flags & O_CREAT) { | ||
169 | /* search inode for this file and fill in file->private_data */ | ||
170 | pCifsInode = CIFS_I(file->f_dentry->d_inode); | ||
171 | read_lock(&GlobalSMBSeslock); | ||
172 | list_for_each(tmp, &pCifsInode->openFileList) { | ||
173 | pCifsFile = list_entry(tmp, struct cifsFileInfo, | ||
174 | flist); | ||
175 | if ((pCifsFile->pfile == NULL) && | ||
176 | (pCifsFile->pid == current->tgid)) { | ||
177 | /* mode set in cifs_create */ | ||
178 | |||
179 | /* needed for writepage */ | ||
180 | pCifsFile->pfile = file; | ||
181 | |||
182 | file->private_data = pCifsFile; | ||
183 | break; | ||
184 | } | ||
185 | } | ||
186 | read_unlock(&GlobalSMBSeslock); | ||
187 | if (file->private_data != NULL) { | ||
188 | rc = 0; | ||
189 | FreeXid(xid); | ||
190 | return rc; | ||
191 | } else { | ||
192 | if (file->f_flags & O_EXCL) | ||
193 | cERROR(1, ("could not find file instance for " | ||
194 | "new file %p ", file)); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | down(&inode->i_sb->s_vfs_rename_sem); | ||
199 | full_path = build_path_from_dentry(file->f_dentry); | ||
200 | up(&inode->i_sb->s_vfs_rename_sem); | ||
201 | if (full_path == NULL) { | ||
202 | FreeXid(xid); | ||
203 | return -ENOMEM; | ||
204 | } | ||
205 | |||
206 | cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", | ||
207 | inode, file->f_flags, full_path)); | ||
208 | desiredAccess = cifs_convert_flags(file->f_flags); | ||
209 | |||
210 | /********************************************************************* | ||
211 | * open flag mapping table: | ||
212 | * | ||
213 | * POSIX Flag CIFS Disposition | ||
214 | * ---------- ---------------- | ||
215 | * O_CREAT FILE_OPEN_IF | ||
216 | * O_CREAT | O_EXCL FILE_CREATE | ||
217 | * O_CREAT | O_TRUNC FILE_OVERWRITE_IF | ||
218 | * O_TRUNC FILE_OVERWRITE | ||
219 | * none of the above FILE_OPEN | ||
220 | * | ||
221 | * Note that there is not a direct match between disposition | ||
222 | * FILE_SUPERSEDE (ie create whether or not file exists although | ||
223 | * O_CREAT | O_TRUNC is similar but truncates the existing | ||
224 | * file rather than creating a new file as FILE_SUPERSEDE does | ||
225 | * (which uses the attributes / metadata passed in on open call) | ||
226 | *? | ||
227 | *? O_SYNC is a reasonable match to CIFS writethrough flag | ||
228 | *? and the read write flags match reasonably. O_LARGEFILE | ||
229 | *? is irrelevant because largefile support is always used | ||
230 | *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, | ||
231 | * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation | ||
232 | *********************************************************************/ | ||
233 | |||
234 | disposition = cifs_get_disposition(file->f_flags); | ||
235 | |||
236 | if (oplockEnabled) | ||
237 | oplock = REQ_OPLOCK; | ||
238 | else | ||
239 | oplock = FALSE; | ||
240 | |||
241 | /* BB pass O_SYNC flag through on file attributes .. BB */ | ||
242 | |||
243 | /* Also refresh inode by passing in file_info buf returned by SMBOpen | ||
244 | and calling get_inode_info with returned buf (at least helps | ||
245 | non-Unix server case) */ | ||
246 | |||
247 | /* BB we can not do this if this is the second open of a file | ||
248 | and the first handle has writebehind data, we might be | ||
249 | able to simply do a filemap_fdatawrite/filemap_fdatawait first */ | ||
250 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
251 | if (!buf) { | ||
252 | rc = -ENOMEM; | ||
253 | goto out; | ||
254 | } | ||
255 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, | ||
256 | CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
257 | cifs_sb->local_nls); | ||
258 | if (rc) { | ||
259 | cFYI(1, ("cifs_open returned 0x%x ", rc)); | ||
260 | goto out; | ||
261 | } | ||
262 | file->private_data = | ||
263 | kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | ||
264 | if (file->private_data == NULL) { | ||
265 | rc = -ENOMEM; | ||
266 | goto out; | ||
267 | } | ||
268 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); | ||
269 | write_lock(&file->f_owner.lock); | ||
270 | write_lock(&GlobalSMBSeslock); | ||
271 | list_add(&pCifsFile->tlist, &pTcon->openFileList); | ||
272 | |||
273 | pCifsInode = CIFS_I(file->f_dentry->d_inode); | ||
274 | if (pCifsInode) { | ||
275 | rc = cifs_open_inode_helper(inode, file, pCifsInode, | ||
276 | pCifsFile, pTcon, | ||
277 | &oplock, buf, full_path, xid); | ||
278 | } else { | ||
279 | write_unlock(&GlobalSMBSeslock); | ||
280 | write_unlock(&file->f_owner.lock); | ||
281 | } | ||
282 | |||
283 | if (oplock & CIFS_CREATE_ACTION) { | ||
284 | /* time to set mode which we can not set earlier due to | ||
285 | problems creating new read-only files */ | ||
286 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { | ||
287 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | ||
288 | inode->i_mode, | ||
289 | (__u64)-1, (__u64)-1, 0 /* dev */, | ||
290 | cifs_sb->local_nls); | ||
291 | } else { | ||
292 | /* BB implement via Windows security descriptors eg | ||
293 | CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, | ||
294 | -1, -1, local_nls); | ||
295 | in the meantime could set r/o dos attribute when | ||
296 | perms are eg: mode & 0222 == 0 */ | ||
297 | } | ||
298 | } | ||
299 | |||
300 | out: | ||
301 | kfree(buf); | ||
302 | kfree(full_path); | ||
303 | FreeXid(xid); | ||
304 | return rc; | ||
305 | } | ||
306 | |||
307 | /* Try to reaquire byte range locks that were released when session */ | ||
308 | /* to server was lost */ | ||
309 | static int cifs_relock_file(struct cifsFileInfo *cifsFile) | ||
310 | { | ||
311 | int rc = 0; | ||
312 | |||
313 | /* BB list all locks open on this file and relock */ | ||
314 | |||
315 | return rc; | ||
316 | } | ||
317 | |||
318 | static int cifs_reopen_file(struct inode *inode, struct file *file, | ||
319 | int can_flush) | ||
320 | { | ||
321 | int rc = -EACCES; | ||
322 | int xid, oplock; | ||
323 | struct cifs_sb_info *cifs_sb; | ||
324 | struct cifsTconInfo *pTcon; | ||
325 | struct cifsFileInfo *pCifsFile; | ||
326 | struct cifsInodeInfo *pCifsInode; | ||
327 | char *full_path = NULL; | ||
328 | int desiredAccess; | ||
329 | int disposition = FILE_OPEN; | ||
330 | __u16 netfid; | ||
331 | |||
332 | if (inode == NULL) | ||
333 | return -EBADF; | ||
334 | if (file->private_data) { | ||
335 | pCifsFile = (struct cifsFileInfo *)file->private_data; | ||
336 | } else | ||
337 | return -EBADF; | ||
338 | |||
339 | xid = GetXid(); | ||
340 | down(&pCifsFile->fh_sem); | ||
341 | if (pCifsFile->invalidHandle == FALSE) { | ||
342 | up(&pCifsFile->fh_sem); | ||
343 | FreeXid(xid); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | if (file->f_dentry == NULL) { | ||
348 | up(&pCifsFile->fh_sem); | ||
349 | cFYI(1, ("failed file reopen, no valid name if dentry freed")); | ||
350 | FreeXid(xid); | ||
351 | return -EBADF; | ||
352 | } | ||
353 | cifs_sb = CIFS_SB(inode->i_sb); | ||
354 | pTcon = cifs_sb->tcon; | ||
355 | /* can not grab rename sem here because various ops, including | ||
356 | those that already have the rename sem can end up causing writepage | ||
357 | to get called and if the server was down that means we end up here, | ||
358 | and we can never tell if the caller already has the rename_sem */ | ||
359 | full_path = build_path_from_dentry(file->f_dentry); | ||
360 | if (full_path == NULL) { | ||
361 | up(&pCifsFile->fh_sem); | ||
362 | FreeXid(xid); | ||
363 | return -ENOMEM; | ||
364 | } | ||
365 | |||
366 | cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", | ||
367 | inode, file->f_flags,full_path)); | ||
368 | desiredAccess = cifs_convert_flags(file->f_flags); | ||
369 | |||
370 | if (oplockEnabled) | ||
371 | oplock = REQ_OPLOCK; | ||
372 | else | ||
373 | oplock = FALSE; | ||
374 | |||
375 | /* Can not refresh inode by passing in file_info buf to be returned | ||
376 | by SMBOpen and then calling get_inode_info with returned buf | ||
377 | since file might have write behind data that needs to be flushed | ||
378 | and server version of file size can be stale. If we knew for sure | ||
379 | that inode was not dirty locally we could do this */ | ||
380 | |||
381 | /* buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
382 | if (buf == 0) { | ||
383 | up(&pCifsFile->fh_sem); | ||
384 | kfree(full_path); | ||
385 | FreeXid(xid); | ||
386 | return -ENOMEM; | ||
387 | } */ | ||
388 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, | ||
389 | CREATE_NOT_DIR, &netfid, &oplock, NULL, | ||
390 | cifs_sb->local_nls); | ||
391 | if (rc) { | ||
392 | up(&pCifsFile->fh_sem); | ||
393 | cFYI(1, ("cifs_open returned 0x%x ", rc)); | ||
394 | cFYI(1, ("oplock: %d ", oplock)); | ||
395 | } else { | ||
396 | pCifsFile->netfid = netfid; | ||
397 | pCifsFile->invalidHandle = FALSE; | ||
398 | up(&pCifsFile->fh_sem); | ||
399 | pCifsInode = CIFS_I(inode); | ||
400 | if (pCifsInode) { | ||
401 | if (can_flush) { | ||
402 | filemap_fdatawrite(inode->i_mapping); | ||
403 | filemap_fdatawait(inode->i_mapping); | ||
404 | /* temporarily disable caching while we | ||
405 | go to server to get inode info */ | ||
406 | pCifsInode->clientCanCacheAll = FALSE; | ||
407 | pCifsInode->clientCanCacheRead = FALSE; | ||
408 | if (pTcon->ses->capabilities & CAP_UNIX) | ||
409 | rc = cifs_get_inode_info_unix(&inode, | ||
410 | full_path, inode->i_sb, xid); | ||
411 | else | ||
412 | rc = cifs_get_inode_info(&inode, | ||
413 | full_path, NULL, inode->i_sb, | ||
414 | xid); | ||
415 | } /* else we are writing out data to server already | ||
416 | and could deadlock if we tried to flush data, and | ||
417 | since we do not know if we have data that would | ||
418 | invalidate the current end of file on the server | ||
419 | we can not go to the server to get the new inod | ||
420 | info */ | ||
421 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
422 | pCifsInode->clientCanCacheAll = TRUE; | ||
423 | pCifsInode->clientCanCacheRead = TRUE; | ||
424 | cFYI(1, ("Exclusive Oplock granted on inode %p", | ||
425 | file->f_dentry->d_inode)); | ||
426 | } else if ((oplock & 0xF) == OPLOCK_READ) { | ||
427 | pCifsInode->clientCanCacheRead = TRUE; | ||
428 | pCifsInode->clientCanCacheAll = FALSE; | ||
429 | } else { | ||
430 | pCifsInode->clientCanCacheRead = FALSE; | ||
431 | pCifsInode->clientCanCacheAll = FALSE; | ||
432 | } | ||
433 | cifs_relock_file(pCifsFile); | ||
434 | } | ||
435 | } | ||
436 | |||
437 | kfree(full_path); | ||
438 | FreeXid(xid); | ||
439 | return rc; | ||
440 | } | ||
441 | |||
442 | int cifs_close(struct inode *inode, struct file *file) | ||
443 | { | ||
444 | int rc = 0; | ||
445 | int xid; | ||
446 | struct cifs_sb_info *cifs_sb; | ||
447 | struct cifsTconInfo *pTcon; | ||
448 | struct cifsFileInfo *pSMBFile = | ||
449 | (struct cifsFileInfo *)file->private_data; | ||
450 | |||
451 | xid = GetXid(); | ||
452 | |||
453 | cifs_sb = CIFS_SB(inode->i_sb); | ||
454 | pTcon = cifs_sb->tcon; | ||
455 | if (pSMBFile) { | ||
456 | pSMBFile->closePend = TRUE; | ||
457 | write_lock(&file->f_owner.lock); | ||
458 | if (pTcon) { | ||
459 | /* no sense reconnecting to close a file that is | ||
460 | already closed */ | ||
461 | if (pTcon->tidStatus != CifsNeedReconnect) { | ||
462 | write_unlock(&file->f_owner.lock); | ||
463 | rc = CIFSSMBClose(xid, pTcon, | ||
464 | pSMBFile->netfid); | ||
465 | write_lock(&file->f_owner.lock); | ||
466 | } | ||
467 | } | ||
468 | list_del(&pSMBFile->flist); | ||
469 | list_del(&pSMBFile->tlist); | ||
470 | write_unlock(&file->f_owner.lock); | ||
471 | kfree(pSMBFile->search_resume_name); | ||
472 | kfree(file->private_data); | ||
473 | file->private_data = NULL; | ||
474 | } else | ||
475 | rc = -EBADF; | ||
476 | |||
477 | if (list_empty(&(CIFS_I(inode)->openFileList))) { | ||
478 | cFYI(1, ("closing last open instance for inode %p", inode)); | ||
479 | /* if the file is not open we do not know if we can cache info | ||
480 | on this inode, much less write behind and read ahead */ | ||
481 | CIFS_I(inode)->clientCanCacheRead = FALSE; | ||
482 | CIFS_I(inode)->clientCanCacheAll = FALSE; | ||
483 | } | ||
484 | if ((rc ==0) && CIFS_I(inode)->write_behind_rc) | ||
485 | rc = CIFS_I(inode)->write_behind_rc; | ||
486 | FreeXid(xid); | ||
487 | return rc; | ||
488 | } | ||
489 | |||
490 | int cifs_closedir(struct inode *inode, struct file *file) | ||
491 | { | ||
492 | int rc = 0; | ||
493 | int xid; | ||
494 | struct cifsFileInfo *pCFileStruct = | ||
495 | (struct cifsFileInfo *)file->private_data; | ||
496 | char *ptmp; | ||
497 | |||
498 | cFYI(1, ("Closedir inode = 0x%p with ", inode)); | ||
499 | |||
500 | xid = GetXid(); | ||
501 | |||
502 | if (pCFileStruct) { | ||
503 | struct cifsTconInfo *pTcon; | ||
504 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
505 | |||
506 | pTcon = cifs_sb->tcon; | ||
507 | |||
508 | cFYI(1, ("Freeing private data in close dir")); | ||
509 | if (pCFileStruct->srch_inf.endOfSearch == FALSE) { | ||
510 | pCFileStruct->invalidHandle = TRUE; | ||
511 | rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); | ||
512 | cFYI(1, ("Closing uncompleted readdir with rc %d", | ||
513 | rc)); | ||
514 | /* not much we can do if it fails anyway, ignore rc */ | ||
515 | rc = 0; | ||
516 | } | ||
517 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; | ||
518 | if (ptmp) { | ||
519 | /* BB removeme BB */ cFYI(1, ("freeing smb buf in srch struct in closedir")); | ||
520 | pCFileStruct->srch_inf.ntwrk_buf_start = NULL; | ||
521 | cifs_buf_release(ptmp); | ||
522 | } | ||
523 | ptmp = pCFileStruct->search_resume_name; | ||
524 | if (ptmp) { | ||
525 | /* BB removeme BB */ cFYI(1, ("freeing resume name in closedir")); | ||
526 | pCFileStruct->search_resume_name = NULL; | ||
527 | kfree(ptmp); | ||
528 | } | ||
529 | kfree(file->private_data); | ||
530 | file->private_data = NULL; | ||
531 | } | ||
532 | /* BB can we lock the filestruct while this is going on? */ | ||
533 | FreeXid(xid); | ||
534 | return rc; | ||
535 | } | ||
536 | |||
537 | int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | ||
538 | { | ||
539 | int rc, xid; | ||
540 | __u32 lockType = LOCKING_ANDX_LARGE_FILES; | ||
541 | __u32 numLock = 0; | ||
542 | __u32 numUnlock = 0; | ||
543 | __u64 length; | ||
544 | int wait_flag = FALSE; | ||
545 | struct cifs_sb_info *cifs_sb; | ||
546 | struct cifsTconInfo *pTcon; | ||
547 | |||
548 | length = 1 + pfLock->fl_end - pfLock->fl_start; | ||
549 | rc = -EACCES; | ||
550 | xid = GetXid(); | ||
551 | |||
552 | cFYI(1, ("Lock parm: 0x%x flockflags: " | ||
553 | "0x%x flocktype: 0x%x start: %lld end: %lld", | ||
554 | cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start, | ||
555 | pfLock->fl_end)); | ||
556 | |||
557 | if (pfLock->fl_flags & FL_POSIX) | ||
558 | cFYI(1, ("Posix ")); | ||
559 | if (pfLock->fl_flags & FL_FLOCK) | ||
560 | cFYI(1, ("Flock ")); | ||
561 | if (pfLock->fl_flags & FL_SLEEP) { | ||
562 | cFYI(1, ("Blocking lock ")); | ||
563 | wait_flag = TRUE; | ||
564 | } | ||
565 | if (pfLock->fl_flags & FL_ACCESS) | ||
566 | cFYI(1, ("Process suspended by mandatory locking - " | ||
567 | "not implemented yet ")); | ||
568 | if (pfLock->fl_flags & FL_LEASE) | ||
569 | cFYI(1, ("Lease on file - not implemented yet")); | ||
570 | if (pfLock->fl_flags & | ||
571 | (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE))) | ||
572 | cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags)); | ||
573 | |||
574 | if (pfLock->fl_type == F_WRLCK) { | ||
575 | cFYI(1, ("F_WRLCK ")); | ||
576 | numLock = 1; | ||
577 | } else if (pfLock->fl_type == F_UNLCK) { | ||
578 | cFYI(1, ("F_UNLCK ")); | ||
579 | numUnlock = 1; | ||
580 | } else if (pfLock->fl_type == F_RDLCK) { | ||
581 | cFYI(1, ("F_RDLCK ")); | ||
582 | lockType |= LOCKING_ANDX_SHARED_LOCK; | ||
583 | numLock = 1; | ||
584 | } else if (pfLock->fl_type == F_EXLCK) { | ||
585 | cFYI(1, ("F_EXLCK ")); | ||
586 | numLock = 1; | ||
587 | } else if (pfLock->fl_type == F_SHLCK) { | ||
588 | cFYI(1, ("F_SHLCK ")); | ||
589 | lockType |= LOCKING_ANDX_SHARED_LOCK; | ||
590 | numLock = 1; | ||
591 | } else | ||
592 | cFYI(1, ("Unknown type of lock ")); | ||
593 | |||
594 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
595 | pTcon = cifs_sb->tcon; | ||
596 | |||
597 | if (file->private_data == NULL) { | ||
598 | FreeXid(xid); | ||
599 | return -EBADF; | ||
600 | } | ||
601 | |||
602 | if (IS_GETLK(cmd)) { | ||
603 | rc = CIFSSMBLock(xid, pTcon, | ||
604 | ((struct cifsFileInfo *)file-> | ||
605 | private_data)->netfid, | ||
606 | length, | ||
607 | pfLock->fl_start, 0, 1, lockType, | ||
608 | 0 /* wait flag */ ); | ||
609 | if (rc == 0) { | ||
610 | rc = CIFSSMBLock(xid, pTcon, | ||
611 | ((struct cifsFileInfo *) file-> | ||
612 | private_data)->netfid, | ||
613 | length, | ||
614 | pfLock->fl_start, 1 /* numUnlock */ , | ||
615 | 0 /* numLock */ , lockType, | ||
616 | 0 /* wait flag */ ); | ||
617 | pfLock->fl_type = F_UNLCK; | ||
618 | if (rc != 0) | ||
619 | cERROR(1, ("Error unlocking previously locked " | ||
620 | "range %d during test of lock ", | ||
621 | rc)); | ||
622 | rc = 0; | ||
623 | |||
624 | } else { | ||
625 | /* if rc == ERR_SHARING_VIOLATION ? */ | ||
626 | rc = 0; /* do not change lock type to unlock | ||
627 | since range in use */ | ||
628 | } | ||
629 | |||
630 | FreeXid(xid); | ||
631 | return rc; | ||
632 | } | ||
633 | |||
634 | rc = CIFSSMBLock(xid, pTcon, | ||
635 | ((struct cifsFileInfo *) file->private_data)-> | ||
636 | netfid, length, | ||
637 | pfLock->fl_start, numUnlock, numLock, lockType, | ||
638 | wait_flag); | ||
639 | if (rc == 0 && (pfLock->fl_flags & FL_POSIX)) | ||
640 | posix_lock_file_wait(file, pfLock); | ||
641 | FreeXid(xid); | ||
642 | return rc; | ||
643 | } | ||
644 | |||
645 | ssize_t cifs_user_write(struct file *file, const char __user *write_data, | ||
646 | size_t write_size, loff_t *poffset) | ||
647 | { | ||
648 | int rc = 0; | ||
649 | unsigned int bytes_written = 0; | ||
650 | unsigned int total_written; | ||
651 | struct cifs_sb_info *cifs_sb; | ||
652 | struct cifsTconInfo *pTcon; | ||
653 | int xid, long_op; | ||
654 | struct cifsFileInfo *open_file; | ||
655 | |||
656 | if (file->f_dentry == NULL) | ||
657 | return -EBADF; | ||
658 | |||
659 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
660 | if (cifs_sb == NULL) | ||
661 | return -EBADF; | ||
662 | |||
663 | pTcon = cifs_sb->tcon; | ||
664 | |||
665 | /* cFYI(1, | ||
666 | (" write %d bytes to offset %lld of %s", write_size, | ||
667 | *poffset, file->f_dentry->d_name.name)); */ | ||
668 | |||
669 | if (file->private_data == NULL) | ||
670 | return -EBADF; | ||
671 | else | ||
672 | open_file = (struct cifsFileInfo *) file->private_data; | ||
673 | |||
674 | xid = GetXid(); | ||
675 | if (file->f_dentry->d_inode == NULL) { | ||
676 | FreeXid(xid); | ||
677 | return -EBADF; | ||
678 | } | ||
679 | |||
680 | if (*poffset > file->f_dentry->d_inode->i_size) | ||
681 | long_op = 2; /* writes past end of file can take a long time */ | ||
682 | else | ||
683 | long_op = 1; | ||
684 | |||
685 | for (total_written = 0; write_size > total_written; | ||
686 | total_written += bytes_written) { | ||
687 | rc = -EAGAIN; | ||
688 | while (rc == -EAGAIN) { | ||
689 | if (file->private_data == NULL) { | ||
690 | /* file has been closed on us */ | ||
691 | FreeXid(xid); | ||
692 | /* if we have gotten here we have written some data | ||
693 | and blocked, and the file has been freed on us while | ||
694 | we blocked so return what we managed to write */ | ||
695 | return total_written; | ||
696 | } | ||
697 | if (open_file->closePend) { | ||
698 | FreeXid(xid); | ||
699 | if (total_written) | ||
700 | return total_written; | ||
701 | else | ||
702 | return -EBADF; | ||
703 | } | ||
704 | if (open_file->invalidHandle) { | ||
705 | if ((file->f_dentry == NULL) || | ||
706 | (file->f_dentry->d_inode == NULL)) { | ||
707 | FreeXid(xid); | ||
708 | return total_written; | ||
709 | } | ||
710 | /* we could deadlock if we called | ||
711 | filemap_fdatawait from here so tell | ||
712 | reopen_file not to flush data to server | ||
713 | now */ | ||
714 | rc = cifs_reopen_file(file->f_dentry->d_inode, | ||
715 | file, FALSE); | ||
716 | if (rc != 0) | ||
717 | break; | ||
718 | } | ||
719 | |||
720 | rc = CIFSSMBWrite(xid, pTcon, | ||
721 | open_file->netfid, | ||
722 | min_t(const int, cifs_sb->wsize, | ||
723 | write_size - total_written), | ||
724 | *poffset, &bytes_written, | ||
725 | NULL, write_data + total_written, long_op); | ||
726 | } | ||
727 | if (rc || (bytes_written == 0)) { | ||
728 | if (total_written) | ||
729 | break; | ||
730 | else { | ||
731 | FreeXid(xid); | ||
732 | return rc; | ||
733 | } | ||
734 | } else | ||
735 | *poffset += bytes_written; | ||
736 | long_op = FALSE; /* subsequent writes fast - | ||
737 | 15 seconds is plenty */ | ||
738 | } | ||
739 | |||
740 | #ifdef CONFIG_CIFS_STATS | ||
741 | if (total_written > 0) { | ||
742 | atomic_inc(&pTcon->num_writes); | ||
743 | spin_lock(&pTcon->stat_lock); | ||
744 | pTcon->bytes_written += total_written; | ||
745 | spin_unlock(&pTcon->stat_lock); | ||
746 | } | ||
747 | #endif | ||
748 | |||
749 | /* since the write may have blocked check these pointers again */ | ||
750 | if (file->f_dentry) { | ||
751 | if (file->f_dentry->d_inode) { | ||
752 | struct inode *inode = file->f_dentry->d_inode; | ||
753 | inode->i_ctime = inode->i_mtime = | ||
754 | current_fs_time(inode->i_sb); | ||
755 | if (total_written > 0) { | ||
756 | if (*poffset > file->f_dentry->d_inode->i_size) | ||
757 | i_size_write(file->f_dentry->d_inode, | ||
758 | *poffset); | ||
759 | } | ||
760 | mark_inode_dirty_sync(file->f_dentry->d_inode); | ||
761 | } | ||
762 | } | ||
763 | FreeXid(xid); | ||
764 | return total_written; | ||
765 | } | ||
766 | |||
767 | static ssize_t cifs_write(struct file *file, const char *write_data, | ||
768 | size_t write_size, loff_t *poffset) | ||
769 | { | ||
770 | int rc = 0; | ||
771 | unsigned int bytes_written = 0; | ||
772 | unsigned int total_written; | ||
773 | struct cifs_sb_info *cifs_sb; | ||
774 | struct cifsTconInfo *pTcon; | ||
775 | int xid, long_op; | ||
776 | struct cifsFileInfo *open_file; | ||
777 | |||
778 | if (file->f_dentry == NULL) | ||
779 | return -EBADF; | ||
780 | |||
781 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
782 | if (cifs_sb == NULL) | ||
783 | return -EBADF; | ||
784 | |||
785 | pTcon = cifs_sb->tcon; | ||
786 | |||
787 | /* cFYI(1, | ||
788 | (" write %d bytes to offset %lld of %s", write_size, | ||
789 | *poffset, file->f_dentry->d_name.name)); */ | ||
790 | |||
791 | if (file->private_data == NULL) | ||
792 | return -EBADF; | ||
793 | else | ||
794 | open_file = (struct cifsFileInfo *)file->private_data; | ||
795 | |||
796 | xid = GetXid(); | ||
797 | if (file->f_dentry->d_inode == NULL) { | ||
798 | FreeXid(xid); | ||
799 | return -EBADF; | ||
800 | } | ||
801 | |||
802 | if (*poffset > file->f_dentry->d_inode->i_size) | ||
803 | long_op = 2; /* writes past end of file can take a long time */ | ||
804 | else | ||
805 | long_op = 1; | ||
806 | |||
807 | for (total_written = 0; write_size > total_written; | ||
808 | total_written += bytes_written) { | ||
809 | rc = -EAGAIN; | ||
810 | while (rc == -EAGAIN) { | ||
811 | if (file->private_data == NULL) { | ||
812 | /* file has been closed on us */ | ||
813 | FreeXid(xid); | ||
814 | /* if we have gotten here we have written some data | ||
815 | and blocked, and the file has been freed on us | ||
816 | while we blocked so return what we managed to | ||
817 | write */ | ||
818 | return total_written; | ||
819 | } | ||
820 | if (open_file->closePend) { | ||
821 | FreeXid(xid); | ||
822 | if (total_written) | ||
823 | return total_written; | ||
824 | else | ||
825 | return -EBADF; | ||
826 | } | ||
827 | if (open_file->invalidHandle) { | ||
828 | if ((file->f_dentry == NULL) || | ||
829 | (file->f_dentry->d_inode == NULL)) { | ||
830 | FreeXid(xid); | ||
831 | return total_written; | ||
832 | } | ||
833 | /* we could deadlock if we called | ||
834 | filemap_fdatawait from here so tell | ||
835 | reopen_file not to flush data to | ||
836 | server now */ | ||
837 | rc = cifs_reopen_file(file->f_dentry->d_inode, | ||
838 | file, FALSE); | ||
839 | if (rc != 0) | ||
840 | break; | ||
841 | } | ||
842 | |||
843 | rc = CIFSSMBWrite(xid, pTcon, | ||
844 | open_file->netfid, | ||
845 | min_t(const int, cifs_sb->wsize, | ||
846 | write_size - total_written), | ||
847 | *poffset, &bytes_written, | ||
848 | write_data + total_written, NULL, long_op); | ||
849 | } | ||
850 | if (rc || (bytes_written == 0)) { | ||
851 | if (total_written) | ||
852 | break; | ||
853 | else { | ||
854 | FreeXid(xid); | ||
855 | return rc; | ||
856 | } | ||
857 | } else | ||
858 | *poffset += bytes_written; | ||
859 | long_op = FALSE; /* subsequent writes fast - | ||
860 | 15 seconds is plenty */ | ||
861 | } | ||
862 | |||
863 | #ifdef CONFIG_CIFS_STATS | ||
864 | if (total_written > 0) { | ||
865 | atomic_inc(&pTcon->num_writes); | ||
866 | spin_lock(&pTcon->stat_lock); | ||
867 | pTcon->bytes_written += total_written; | ||
868 | spin_unlock(&pTcon->stat_lock); | ||
869 | } | ||
870 | #endif | ||
871 | |||
872 | /* since the write may have blocked check these pointers again */ | ||
873 | if (file->f_dentry) { | ||
874 | if (file->f_dentry->d_inode) { | ||
875 | file->f_dentry->d_inode->i_ctime = | ||
876 | file->f_dentry->d_inode->i_mtime = CURRENT_TIME; | ||
877 | if (total_written > 0) { | ||
878 | if (*poffset > file->f_dentry->d_inode->i_size) | ||
879 | i_size_write(file->f_dentry->d_inode, | ||
880 | *poffset); | ||
881 | } | ||
882 | mark_inode_dirty_sync(file->f_dentry->d_inode); | ||
883 | } | ||
884 | } | ||
885 | FreeXid(xid); | ||
886 | return total_written; | ||
887 | } | ||
888 | |||
889 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | ||
890 | { | ||
891 | struct address_space *mapping = page->mapping; | ||
892 | loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
893 | char *write_data; | ||
894 | int rc = -EFAULT; | ||
895 | int bytes_written = 0; | ||
896 | struct cifs_sb_info *cifs_sb; | ||
897 | struct cifsTconInfo *pTcon; | ||
898 | struct inode *inode; | ||
899 | struct cifsInodeInfo *cifsInode; | ||
900 | struct cifsFileInfo *open_file = NULL; | ||
901 | struct list_head *tmp; | ||
902 | struct list_head *tmp1; | ||
903 | |||
904 | if (!mapping || !mapping->host) | ||
905 | return -EFAULT; | ||
906 | |||
907 | inode = page->mapping->host; | ||
908 | cifs_sb = CIFS_SB(inode->i_sb); | ||
909 | pTcon = cifs_sb->tcon; | ||
910 | |||
911 | offset += (loff_t)from; | ||
912 | write_data = kmap(page); | ||
913 | write_data += from; | ||
914 | |||
915 | if ((to > PAGE_CACHE_SIZE) || (from > to)) { | ||
916 | kunmap(page); | ||
917 | return -EIO; | ||
918 | } | ||
919 | |||
920 | /* racing with truncate? */ | ||
921 | if (offset > mapping->host->i_size) { | ||
922 | kunmap(page); | ||
923 | return 0; /* don't care */ | ||
924 | } | ||
925 | |||
926 | /* check to make sure that we are not extending the file */ | ||
927 | if (mapping->host->i_size - offset < (loff_t)to) | ||
928 | to = (unsigned)(mapping->host->i_size - offset); | ||
929 | |||
930 | cifsInode = CIFS_I(mapping->host); | ||
931 | read_lock(&GlobalSMBSeslock); | ||
932 | /* BB we should start at the end */ | ||
933 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | ||
934 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | ||
935 | if (open_file->closePend) | ||
936 | continue; | ||
937 | /* We check if file is open for writing first */ | ||
938 | if ((open_file->pfile) && | ||
939 | ((open_file->pfile->f_flags & O_RDWR) || | ||
940 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
941 | read_unlock(&GlobalSMBSeslock); | ||
942 | bytes_written = cifs_write(open_file->pfile, | ||
943 | write_data, to-from, | ||
944 | &offset); | ||
945 | read_lock(&GlobalSMBSeslock); | ||
946 | /* Does mm or vfs already set times? */ | ||
947 | inode->i_atime = | ||
948 | inode->i_mtime = current_fs_time(inode->i_sb); | ||
949 | if ((bytes_written > 0) && (offset)) { | ||
950 | rc = 0; | ||
951 | } else if (bytes_written < 0) { | ||
952 | if (rc == -EBADF) { | ||
953 | /* have seen a case in which kernel seemed to | ||
954 | have closed/freed a file even with writes | ||
955 | active so we might as well see if there are | ||
956 | other file structs to try for the same | ||
957 | inode before giving up */ | ||
958 | continue; | ||
959 | } else | ||
960 | rc = bytes_written; | ||
961 | } | ||
962 | break; /* now that we found a valid file handle and | ||
963 | tried to write to it we are done, no sense | ||
964 | continuing to loop looking for another */ | ||
965 | } | ||
966 | if (tmp->next == NULL) { | ||
967 | cFYI(1, ("File instance %p removed", tmp)); | ||
968 | break; | ||
969 | } | ||
970 | } | ||
971 | read_unlock(&GlobalSMBSeslock); | ||
972 | if (open_file == NULL) { | ||
973 | cFYI(1, ("No writeable filehandles for inode")); | ||
974 | rc = -EIO; | ||
975 | } | ||
976 | |||
977 | kunmap(page); | ||
978 | return rc; | ||
979 | } | ||
980 | |||
981 | #if 0 | ||
982 | static int cifs_writepages(struct address_space *mapping, | ||
983 | struct writeback_control *wbc) | ||
984 | { | ||
985 | int rc = -EFAULT; | ||
986 | int xid; | ||
987 | |||
988 | xid = GetXid(); | ||
989 | |||
990 | /* Find contiguous pages then iterate through repeating | ||
991 | call 16K write then Setpageuptodate or if LARGE_WRITE_X | ||
992 | support then send larger writes via kevec so as to eliminate | ||
993 | a memcpy */ | ||
994 | FreeXid(xid); | ||
995 | return rc; | ||
996 | } | ||
997 | #endif | ||
998 | |||
999 | static int cifs_writepage(struct page* page, struct writeback_control *wbc) | ||
1000 | { | ||
1001 | int rc = -EFAULT; | ||
1002 | int xid; | ||
1003 | |||
1004 | xid = GetXid(); | ||
1005 | /* BB add check for wbc flags */ | ||
1006 | page_cache_get(page); | ||
1007 | if (!PageUptodate(page)) { | ||
1008 | cFYI(1, ("ppw - page not up to date")); | ||
1009 | } | ||
1010 | |||
1011 | rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE); | ||
1012 | SetPageUptodate(page); /* BB add check for error and Clearuptodate? */ | ||
1013 | unlock_page(page); | ||
1014 | page_cache_release(page); | ||
1015 | FreeXid(xid); | ||
1016 | return rc; | ||
1017 | } | ||
1018 | |||
1019 | static int cifs_commit_write(struct file *file, struct page *page, | ||
1020 | unsigned offset, unsigned to) | ||
1021 | { | ||
1022 | int xid; | ||
1023 | int rc = 0; | ||
1024 | struct inode *inode = page->mapping->host; | ||
1025 | loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | ||
1026 | char *page_data; | ||
1027 | |||
1028 | xid = GetXid(); | ||
1029 | cFYI(1, ("commit write for page %p up to position %lld for %d", | ||
1030 | page, position, to)); | ||
1031 | if (position > inode->i_size) { | ||
1032 | i_size_write(inode, position); | ||
1033 | /* if (file->private_data == NULL) { | ||
1034 | rc = -EBADF; | ||
1035 | } else { | ||
1036 | open_file = (struct cifsFileInfo *)file->private_data; | ||
1037 | cifs_sb = CIFS_SB(inode->i_sb); | ||
1038 | rc = -EAGAIN; | ||
1039 | while (rc == -EAGAIN) { | ||
1040 | if ((open_file->invalidHandle) && | ||
1041 | (!open_file->closePend)) { | ||
1042 | rc = cifs_reopen_file( | ||
1043 | file->f_dentry->d_inode, file); | ||
1044 | if (rc != 0) | ||
1045 | break; | ||
1046 | } | ||
1047 | if (!open_file->closePend) { | ||
1048 | rc = CIFSSMBSetFileSize(xid, | ||
1049 | cifs_sb->tcon, position, | ||
1050 | open_file->netfid, | ||
1051 | open_file->pid, FALSE); | ||
1052 | } else { | ||
1053 | rc = -EBADF; | ||
1054 | break; | ||
1055 | } | ||
1056 | } | ||
1057 | cFYI(1, (" SetEOF (commit write) rc = %d", rc)); | ||
1058 | } */ | ||
1059 | } | ||
1060 | if (!PageUptodate(page)) { | ||
1061 | position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; | ||
1062 | /* can not rely on (or let) writepage write this data */ | ||
1063 | if (to < offset) { | ||
1064 | cFYI(1, ("Illegal offsets, can not copy from %d to %d", | ||
1065 | offset, to)); | ||
1066 | FreeXid(xid); | ||
1067 | return rc; | ||
1068 | } | ||
1069 | /* this is probably better than directly calling | ||
1070 | partialpage_write since in this function the file handle is | ||
1071 | known which we might as well leverage */ | ||
1072 | /* BB check if anything else missing out of ppw | ||
1073 | such as updating last write time */ | ||
1074 | page_data = kmap(page); | ||
1075 | rc = cifs_write(file, page_data + offset, to-offset, | ||
1076 | &position); | ||
1077 | if (rc > 0) | ||
1078 | rc = 0; | ||
1079 | /* else if (rc < 0) should we set writebehind rc? */ | ||
1080 | kunmap(page); | ||
1081 | } else { | ||
1082 | set_page_dirty(page); | ||
1083 | } | ||
1084 | |||
1085 | FreeXid(xid); | ||
1086 | return rc; | ||
1087 | } | ||
1088 | |||
1089 | int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) | ||
1090 | { | ||
1091 | int xid; | ||
1092 | int rc = 0; | ||
1093 | struct inode *inode = file->f_dentry->d_inode; | ||
1094 | |||
1095 | xid = GetXid(); | ||
1096 | |||
1097 | cFYI(1, ("Sync file - name: %s datasync: 0x%x ", | ||
1098 | dentry->d_name.name, datasync)); | ||
1099 | |||
1100 | rc = filemap_fdatawrite(inode->i_mapping); | ||
1101 | if (rc == 0) | ||
1102 | CIFS_I(inode)->write_behind_rc = 0; | ||
1103 | FreeXid(xid); | ||
1104 | return rc; | ||
1105 | } | ||
1106 | |||
1107 | /* static int cifs_sync_page(struct page *page) | ||
1108 | { | ||
1109 | struct address_space *mapping; | ||
1110 | struct inode *inode; | ||
1111 | unsigned long index = page->index; | ||
1112 | unsigned int rpages = 0; | ||
1113 | int rc = 0; | ||
1114 | |||
1115 | cFYI(1, ("sync page %p",page)); | ||
1116 | mapping = page->mapping; | ||
1117 | if (!mapping) | ||
1118 | return 0; | ||
1119 | inode = mapping->host; | ||
1120 | if (!inode) | ||
1121 | return 0; */ | ||
1122 | |||
1123 | /* fill in rpages then | ||
1124 | result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */ | ||
1125 | |||
1126 | /* cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); | ||
1127 | |||
1128 | if (rc < 0) | ||
1129 | return rc; | ||
1130 | return 0; | ||
1131 | } */ | ||
1132 | |||
1133 | /* | ||
1134 | * As file closes, flush all cached write data for this inode checking | ||
1135 | * for write behind errors. | ||
1136 | */ | ||
1137 | int cifs_flush(struct file *file) | ||
1138 | { | ||
1139 | struct inode * inode = file->f_dentry->d_inode; | ||
1140 | int rc = 0; | ||
1141 | |||
1142 | /* Rather than do the steps manually: | ||
1143 | lock the inode for writing | ||
1144 | loop through pages looking for write behind data (dirty pages) | ||
1145 | coalesce into contiguous 16K (or smaller) chunks to write to server | ||
1146 | send to server (prefer in parallel) | ||
1147 | deal with writebehind errors | ||
1148 | unlock inode for writing | ||
1149 | filemapfdatawrite appears easier for the time being */ | ||
1150 | |||
1151 | rc = filemap_fdatawrite(inode->i_mapping); | ||
1152 | if (!rc) /* reset wb rc if we were able to write out dirty pages */ | ||
1153 | CIFS_I(inode)->write_behind_rc = 0; | ||
1154 | |||
1155 | cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc)); | ||
1156 | |||
1157 | return rc; | ||
1158 | } | ||
1159 | |||
1160 | ssize_t cifs_user_read(struct file *file, char __user *read_data, | ||
1161 | size_t read_size, loff_t *poffset) | ||
1162 | { | ||
1163 | int rc = -EACCES; | ||
1164 | unsigned int bytes_read = 0; | ||
1165 | unsigned int total_read = 0; | ||
1166 | unsigned int current_read_size; | ||
1167 | struct cifs_sb_info *cifs_sb; | ||
1168 | struct cifsTconInfo *pTcon; | ||
1169 | int xid; | ||
1170 | struct cifsFileInfo *open_file; | ||
1171 | char *smb_read_data; | ||
1172 | char __user *current_offset; | ||
1173 | struct smb_com_read_rsp *pSMBr; | ||
1174 | |||
1175 | xid = GetXid(); | ||
1176 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
1177 | pTcon = cifs_sb->tcon; | ||
1178 | |||
1179 | if (file->private_data == NULL) { | ||
1180 | FreeXid(xid); | ||
1181 | return -EBADF; | ||
1182 | } | ||
1183 | open_file = (struct cifsFileInfo *)file->private_data; | ||
1184 | |||
1185 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | ||
1186 | cFYI(1, ("attempting read on write only file instance")); | ||
1187 | } | ||
1188 | for (total_read = 0, current_offset = read_data; | ||
1189 | read_size > total_read; | ||
1190 | total_read += bytes_read, current_offset += bytes_read) { | ||
1191 | current_read_size = min_t(const int, read_size - total_read, | ||
1192 | cifs_sb->rsize); | ||
1193 | rc = -EAGAIN; | ||
1194 | smb_read_data = NULL; | ||
1195 | while (rc == -EAGAIN) { | ||
1196 | if ((open_file->invalidHandle) && | ||
1197 | (!open_file->closePend)) { | ||
1198 | rc = cifs_reopen_file(file->f_dentry->d_inode, | ||
1199 | file, TRUE); | ||
1200 | if (rc != 0) | ||
1201 | break; | ||
1202 | } | ||
1203 | |||
1204 | rc = CIFSSMBRead(xid, pTcon, | ||
1205 | open_file->netfid, | ||
1206 | current_read_size, *poffset, | ||
1207 | &bytes_read, &smb_read_data); | ||
1208 | |||
1209 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | ||
1210 | if (copy_to_user(current_offset, | ||
1211 | smb_read_data + 4 /* RFC1001 hdr */ | ||
1212 | + le16_to_cpu(pSMBr->DataOffset), | ||
1213 | bytes_read)) { | ||
1214 | rc = -EFAULT; | ||
1215 | FreeXid(xid); | ||
1216 | return rc; | ||
1217 | } | ||
1218 | if (smb_read_data) { | ||
1219 | cifs_buf_release(smb_read_data); | ||
1220 | smb_read_data = NULL; | ||
1221 | } | ||
1222 | } | ||
1223 | if (rc || (bytes_read == 0)) { | ||
1224 | if (total_read) { | ||
1225 | break; | ||
1226 | } else { | ||
1227 | FreeXid(xid); | ||
1228 | return rc; | ||
1229 | } | ||
1230 | } else { | ||
1231 | #ifdef CONFIG_CIFS_STATS | ||
1232 | atomic_inc(&pTcon->num_reads); | ||
1233 | spin_lock(&pTcon->stat_lock); | ||
1234 | pTcon->bytes_read += total_read; | ||
1235 | spin_unlock(&pTcon->stat_lock); | ||
1236 | #endif | ||
1237 | *poffset += bytes_read; | ||
1238 | } | ||
1239 | } | ||
1240 | FreeXid(xid); | ||
1241 | return total_read; | ||
1242 | } | ||
1243 | |||
1244 | |||
1245 | static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | ||
1246 | loff_t *poffset) | ||
1247 | { | ||
1248 | int rc = -EACCES; | ||
1249 | unsigned int bytes_read = 0; | ||
1250 | unsigned int total_read; | ||
1251 | unsigned int current_read_size; | ||
1252 | struct cifs_sb_info *cifs_sb; | ||
1253 | struct cifsTconInfo *pTcon; | ||
1254 | int xid; | ||
1255 | char *current_offset; | ||
1256 | struct cifsFileInfo *open_file; | ||
1257 | |||
1258 | xid = GetXid(); | ||
1259 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
1260 | pTcon = cifs_sb->tcon; | ||
1261 | |||
1262 | if (file->private_data == NULL) { | ||
1263 | FreeXid(xid); | ||
1264 | return -EBADF; | ||
1265 | } | ||
1266 | open_file = (struct cifsFileInfo *)file->private_data; | ||
1267 | |||
1268 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | ||
1269 | cFYI(1, ("attempting read on write only file instance")); | ||
1270 | |||
1271 | for (total_read = 0, current_offset = read_data; | ||
1272 | read_size > total_read; | ||
1273 | total_read += bytes_read, current_offset += bytes_read) { | ||
1274 | current_read_size = min_t(const int, read_size - total_read, | ||
1275 | cifs_sb->rsize); | ||
1276 | rc = -EAGAIN; | ||
1277 | while (rc == -EAGAIN) { | ||
1278 | if ((open_file->invalidHandle) && | ||
1279 | (!open_file->closePend)) { | ||
1280 | rc = cifs_reopen_file(file->f_dentry->d_inode, | ||
1281 | file, TRUE); | ||
1282 | if (rc != 0) | ||
1283 | break; | ||
1284 | } | ||
1285 | |||
1286 | rc = CIFSSMBRead(xid, pTcon, | ||
1287 | open_file->netfid, | ||
1288 | current_read_size, *poffset, | ||
1289 | &bytes_read, ¤t_offset); | ||
1290 | } | ||
1291 | if (rc || (bytes_read == 0)) { | ||
1292 | if (total_read) { | ||
1293 | break; | ||
1294 | } else { | ||
1295 | FreeXid(xid); | ||
1296 | return rc; | ||
1297 | } | ||
1298 | } else { | ||
1299 | #ifdef CONFIG_CIFS_STATS | ||
1300 | atomic_inc(&pTcon->num_reads); | ||
1301 | spin_lock(&pTcon->stat_lock); | ||
1302 | pTcon->bytes_read += total_read; | ||
1303 | spin_unlock(&pTcon->stat_lock); | ||
1304 | #endif | ||
1305 | *poffset += bytes_read; | ||
1306 | } | ||
1307 | } | ||
1308 | FreeXid(xid); | ||
1309 | return total_read; | ||
1310 | } | ||
1311 | |||
1312 | int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) | ||
1313 | { | ||
1314 | struct dentry *dentry = file->f_dentry; | ||
1315 | int rc, xid; | ||
1316 | |||
1317 | xid = GetXid(); | ||
1318 | rc = cifs_revalidate(dentry); | ||
1319 | if (rc) { | ||
1320 | cFYI(1, ("Validation prior to mmap failed, error=%d", rc)); | ||
1321 | FreeXid(xid); | ||
1322 | return rc; | ||
1323 | } | ||
1324 | rc = generic_file_mmap(file, vma); | ||
1325 | FreeXid(xid); | ||
1326 | return rc; | ||
1327 | } | ||
1328 | |||
1329 | |||
1330 | static void cifs_copy_cache_pages(struct address_space *mapping, | ||
1331 | struct list_head *pages, int bytes_read, char *data, | ||
1332 | struct pagevec *plru_pvec) | ||
1333 | { | ||
1334 | struct page *page; | ||
1335 | char *target; | ||
1336 | |||
1337 | while (bytes_read > 0) { | ||
1338 | if (list_empty(pages)) | ||
1339 | break; | ||
1340 | |||
1341 | page = list_entry(pages->prev, struct page, lru); | ||
1342 | list_del(&page->lru); | ||
1343 | |||
1344 | if (add_to_page_cache(page, mapping, page->index, | ||
1345 | GFP_KERNEL)) { | ||
1346 | page_cache_release(page); | ||
1347 | cFYI(1, ("Add page cache failed")); | ||
1348 | continue; | ||
1349 | } | ||
1350 | |||
1351 | target = kmap_atomic(page,KM_USER0); | ||
1352 | |||
1353 | if (PAGE_CACHE_SIZE > bytes_read) { | ||
1354 | memcpy(target, data, bytes_read); | ||
1355 | /* zero the tail end of this partial page */ | ||
1356 | memset(target + bytes_read, 0, | ||
1357 | PAGE_CACHE_SIZE - bytes_read); | ||
1358 | bytes_read = 0; | ||
1359 | } else { | ||
1360 | memcpy(target, data, PAGE_CACHE_SIZE); | ||
1361 | bytes_read -= PAGE_CACHE_SIZE; | ||
1362 | } | ||
1363 | kunmap_atomic(target, KM_USER0); | ||
1364 | |||
1365 | flush_dcache_page(page); | ||
1366 | SetPageUptodate(page); | ||
1367 | unlock_page(page); | ||
1368 | if (!pagevec_add(plru_pvec, page)) | ||
1369 | __pagevec_lru_add(plru_pvec); | ||
1370 | data += PAGE_CACHE_SIZE; | ||
1371 | } | ||
1372 | return; | ||
1373 | } | ||
1374 | |||
1375 | static int cifs_readpages(struct file *file, struct address_space *mapping, | ||
1376 | struct list_head *page_list, unsigned num_pages) | ||
1377 | { | ||
1378 | int rc = -EACCES; | ||
1379 | int xid; | ||
1380 | loff_t offset; | ||
1381 | struct page *page; | ||
1382 | struct cifs_sb_info *cifs_sb; | ||
1383 | struct cifsTconInfo *pTcon; | ||
1384 | int bytes_read = 0; | ||
1385 | unsigned int read_size,i; | ||
1386 | char *smb_read_data = NULL; | ||
1387 | struct smb_com_read_rsp *pSMBr; | ||
1388 | struct pagevec lru_pvec; | ||
1389 | struct cifsFileInfo *open_file; | ||
1390 | |||
1391 | xid = GetXid(); | ||
1392 | if (file->private_data == NULL) { | ||
1393 | FreeXid(xid); | ||
1394 | return -EBADF; | ||
1395 | } | ||
1396 | open_file = (struct cifsFileInfo *)file->private_data; | ||
1397 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
1398 | pTcon = cifs_sb->tcon; | ||
1399 | |||
1400 | pagevec_init(&lru_pvec, 0); | ||
1401 | |||
1402 | for (i = 0; i < num_pages; ) { | ||
1403 | unsigned contig_pages; | ||
1404 | struct page *tmp_page; | ||
1405 | unsigned long expected_index; | ||
1406 | |||
1407 | if (list_empty(page_list)) | ||
1408 | break; | ||
1409 | |||
1410 | page = list_entry(page_list->prev, struct page, lru); | ||
1411 | offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
1412 | |||
1413 | /* count adjacent pages that we will read into */ | ||
1414 | contig_pages = 0; | ||
1415 | expected_index = | ||
1416 | list_entry(page_list->prev, struct page, lru)->index; | ||
1417 | list_for_each_entry_reverse(tmp_page,page_list,lru) { | ||
1418 | if (tmp_page->index == expected_index) { | ||
1419 | contig_pages++; | ||
1420 | expected_index++; | ||
1421 | } else | ||
1422 | break; | ||
1423 | } | ||
1424 | if (contig_pages + i > num_pages) | ||
1425 | contig_pages = num_pages - i; | ||
1426 | |||
1427 | /* for reads over a certain size could initiate async | ||
1428 | read ahead */ | ||
1429 | |||
1430 | read_size = contig_pages * PAGE_CACHE_SIZE; | ||
1431 | /* Read size needs to be in multiples of one page */ | ||
1432 | read_size = min_t(const unsigned int, read_size, | ||
1433 | cifs_sb->rsize & PAGE_CACHE_MASK); | ||
1434 | |||
1435 | rc = -EAGAIN; | ||
1436 | while (rc == -EAGAIN) { | ||
1437 | if ((open_file->invalidHandle) && | ||
1438 | (!open_file->closePend)) { | ||
1439 | rc = cifs_reopen_file(file->f_dentry->d_inode, | ||
1440 | file, TRUE); | ||
1441 | if (rc != 0) | ||
1442 | break; | ||
1443 | } | ||
1444 | |||
1445 | rc = CIFSSMBRead(xid, pTcon, | ||
1446 | open_file->netfid, | ||
1447 | read_size, offset, | ||
1448 | &bytes_read, &smb_read_data); | ||
1449 | /* BB need to check return code here */ | ||
1450 | if (rc== -EAGAIN) { | ||
1451 | if (smb_read_data) { | ||
1452 | cifs_buf_release(smb_read_data); | ||
1453 | smb_read_data = NULL; | ||
1454 | } | ||
1455 | } | ||
1456 | } | ||
1457 | if ((rc < 0) || (smb_read_data == NULL)) { | ||
1458 | cFYI(1, ("Read error in readpages: %d", rc)); | ||
1459 | /* clean up remaing pages off list */ | ||
1460 | while (!list_empty(page_list) && (i < num_pages)) { | ||
1461 | page = list_entry(page_list->prev, struct page, | ||
1462 | lru); | ||
1463 | list_del(&page->lru); | ||
1464 | page_cache_release(page); | ||
1465 | } | ||
1466 | break; | ||
1467 | } else if (bytes_read > 0) { | ||
1468 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | ||
1469 | cifs_copy_cache_pages(mapping, page_list, bytes_read, | ||
1470 | smb_read_data + 4 /* RFC1001 hdr */ + | ||
1471 | le16_to_cpu(pSMBr->DataOffset), &lru_pvec); | ||
1472 | |||
1473 | i += bytes_read >> PAGE_CACHE_SHIFT; | ||
1474 | #ifdef CONFIG_CIFS_STATS | ||
1475 | atomic_inc(&pTcon->num_reads); | ||
1476 | spin_lock(&pTcon->stat_lock); | ||
1477 | pTcon->bytes_read += bytes_read; | ||
1478 | spin_unlock(&pTcon->stat_lock); | ||
1479 | #endif | ||
1480 | if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { | ||
1481 | i++; /* account for partial page */ | ||
1482 | |||
1483 | /* server copy of file can have smaller size | ||
1484 | than client */ | ||
1485 | /* BB do we need to verify this common case ? | ||
1486 | this case is ok - if we are at server EOF | ||
1487 | we will hit it on next read */ | ||
1488 | |||
1489 | /* while (!list_empty(page_list) && (i < num_pages)) { | ||
1490 | page = list_entry(page_list->prev, | ||
1491 | struct page, list); | ||
1492 | list_del(&page->list); | ||
1493 | page_cache_release(page); | ||
1494 | } | ||
1495 | break; */ | ||
1496 | } | ||
1497 | } else { | ||
1498 | cFYI(1, ("No bytes read (%d) at offset %lld . " | ||
1499 | "Cleaning remaining pages from readahead list", | ||
1500 | bytes_read, offset)); | ||
1501 | /* BB turn off caching and do new lookup on | ||
1502 | file size at server? */ | ||
1503 | while (!list_empty(page_list) && (i < num_pages)) { | ||
1504 | page = list_entry(page_list->prev, struct page, | ||
1505 | lru); | ||
1506 | list_del(&page->lru); | ||
1507 | |||
1508 | /* BB removeme - replace with zero of page? */ | ||
1509 | page_cache_release(page); | ||
1510 | } | ||
1511 | break; | ||
1512 | } | ||
1513 | if (smb_read_data) { | ||
1514 | cifs_buf_release(smb_read_data); | ||
1515 | smb_read_data = NULL; | ||
1516 | } | ||
1517 | bytes_read = 0; | ||
1518 | } | ||
1519 | |||
1520 | pagevec_lru_add(&lru_pvec); | ||
1521 | |||
1522 | /* need to free smb_read_data buf before exit */ | ||
1523 | if (smb_read_data) { | ||
1524 | cifs_buf_release(smb_read_data); | ||
1525 | smb_read_data = NULL; | ||
1526 | } | ||
1527 | |||
1528 | FreeXid(xid); | ||
1529 | return rc; | ||
1530 | } | ||
1531 | |||
1532 | static int cifs_readpage_worker(struct file *file, struct page *page, | ||
1533 | loff_t *poffset) | ||
1534 | { | ||
1535 | char *read_data; | ||
1536 | int rc; | ||
1537 | |||
1538 | page_cache_get(page); | ||
1539 | read_data = kmap(page); | ||
1540 | /* for reads over a certain size could initiate async read ahead */ | ||
1541 | |||
1542 | rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset); | ||
1543 | |||
1544 | if (rc < 0) | ||
1545 | goto io_error; | ||
1546 | else | ||
1547 | cFYI(1, ("Bytes read %d ",rc)); | ||
1548 | |||
1549 | file->f_dentry->d_inode->i_atime = | ||
1550 | current_fs_time(file->f_dentry->d_inode->i_sb); | ||
1551 | |||
1552 | if (PAGE_CACHE_SIZE > rc) | ||
1553 | memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc); | ||
1554 | |||
1555 | flush_dcache_page(page); | ||
1556 | SetPageUptodate(page); | ||
1557 | rc = 0; | ||
1558 | |||
1559 | io_error: | ||
1560 | kunmap(page); | ||
1561 | page_cache_release(page); | ||
1562 | return rc; | ||
1563 | } | ||
1564 | |||
1565 | static int cifs_readpage(struct file *file, struct page *page) | ||
1566 | { | ||
1567 | loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
1568 | int rc = -EACCES; | ||
1569 | int xid; | ||
1570 | |||
1571 | xid = GetXid(); | ||
1572 | |||
1573 | if (file->private_data == NULL) { | ||
1574 | FreeXid(xid); | ||
1575 | return -EBADF; | ||
1576 | } | ||
1577 | |||
1578 | cFYI(1, ("readpage %p at offset %d 0x%x\n", | ||
1579 | page, (int)offset, (int)offset)); | ||
1580 | |||
1581 | rc = cifs_readpage_worker(file, page, &offset); | ||
1582 | |||
1583 | unlock_page(page); | ||
1584 | |||
1585 | FreeXid(xid); | ||
1586 | return rc; | ||
1587 | } | ||
1588 | |||
1589 | /* We do not want to update the file size from server for inodes | ||
1590 | open for write - to avoid races with writepage extending | ||
1591 | the file - in the future we could consider allowing | ||
1592 | refreshing the inode only on increases in the file size | ||
1593 | but this is tricky to do without racing with writebehind | ||
1594 | page caching in the current Linux kernel design */ | ||
1595 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) | ||
1596 | { | ||
1597 | struct list_head *tmp; | ||
1598 | struct list_head *tmp1; | ||
1599 | struct cifsFileInfo *open_file = NULL; | ||
1600 | int rc = TRUE; | ||
1601 | |||
1602 | if (cifsInode == NULL) | ||
1603 | return rc; | ||
1604 | |||
1605 | read_lock(&GlobalSMBSeslock); | ||
1606 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | ||
1607 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | ||
1608 | if (open_file == NULL) | ||
1609 | break; | ||
1610 | if (open_file->closePend) | ||
1611 | continue; | ||
1612 | /* We check if file is open for writing, | ||
1613 | BB we could supplement this with a check to see if file size | ||
1614 | changes have been flushed to server - ie inode metadata dirty */ | ||
1615 | if ((open_file->pfile) && | ||
1616 | ((open_file->pfile->f_flags & O_RDWR) || | ||
1617 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
1618 | rc = FALSE; | ||
1619 | break; | ||
1620 | } | ||
1621 | if (tmp->next == NULL) { | ||
1622 | cFYI(1, ("File instance %p removed", tmp)); | ||
1623 | break; | ||
1624 | } | ||
1625 | } | ||
1626 | read_unlock(&GlobalSMBSeslock); | ||
1627 | return rc; | ||
1628 | } | ||
1629 | |||
1630 | |||
1631 | static int cifs_prepare_write(struct file *file, struct page *page, | ||
1632 | unsigned from, unsigned to) | ||
1633 | { | ||
1634 | int rc = 0; | ||
1635 | loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
1636 | cFYI(1, ("prepare write for page %p from %d to %d",page,from,to)); | ||
1637 | if (!PageUptodate(page)) { | ||
1638 | /* if (to - from != PAGE_CACHE_SIZE) { | ||
1639 | void *kaddr = kmap_atomic(page, KM_USER0); | ||
1640 | memset(kaddr, 0, from); | ||
1641 | memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); | ||
1642 | flush_dcache_page(page); | ||
1643 | kunmap_atomic(kaddr, KM_USER0); | ||
1644 | } */ | ||
1645 | /* If we are writing a full page it will be up to date, | ||
1646 | no need to read from the server */ | ||
1647 | if ((to == PAGE_CACHE_SIZE) && (from == 0)) | ||
1648 | SetPageUptodate(page); | ||
1649 | |||
1650 | /* might as well read a page, it is fast enough */ | ||
1651 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) { | ||
1652 | rc = cifs_readpage_worker(file, page, &offset); | ||
1653 | } else { | ||
1654 | /* should we try using another file handle if there is one - | ||
1655 | how would we lock it to prevent close of that handle | ||
1656 | racing with this read? | ||
1657 | In any case this will be written out by commit_write */ | ||
1658 | } | ||
1659 | } | ||
1660 | |||
1661 | /* BB should we pass any errors back? | ||
1662 | e.g. if we do not have read access to the file */ | ||
1663 | return 0; | ||
1664 | } | ||
1665 | |||
1666 | struct address_space_operations cifs_addr_ops = { | ||
1667 | .readpage = cifs_readpage, | ||
1668 | .readpages = cifs_readpages, | ||
1669 | .writepage = cifs_writepage, | ||
1670 | .prepare_write = cifs_prepare_write, | ||
1671 | .commit_write = cifs_commit_write, | ||
1672 | .set_page_dirty = __set_page_dirty_nobuffers, | ||
1673 | /* .sync_page = cifs_sync_page, */ | ||
1674 | /* .direct_IO = */ | ||
1675 | }; | ||
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c new file mode 100644 index 000000000000..d73b0aa86775 --- /dev/null +++ b/fs/cifs/inode.c | |||
@@ -0,0 +1,1096 @@ | |||
1 | /* | ||
2 | * fs/cifs/inode.c | ||
3 | * | ||
4 | * Copyright (C) International Business Machines Corp., 2002,2005 | ||
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/fs.h> | ||
22 | #include <linux/buffer_head.h> | ||
23 | #include <linux/stat.h> | ||
24 | #include <linux/pagemap.h> | ||
25 | #include <asm/div64.h> | ||
26 | #include "cifsfs.h" | ||
27 | #include "cifspdu.h" | ||
28 | #include "cifsglob.h" | ||
29 | #include "cifsproto.h" | ||
30 | #include "cifs_debug.h" | ||
31 | #include "cifs_fs_sb.h" | ||
32 | |||
33 | int cifs_get_inode_info_unix(struct inode **pinode, | ||
34 | const unsigned char *search_path, struct super_block *sb, int xid) | ||
35 | { | ||
36 | int rc = 0; | ||
37 | FILE_UNIX_BASIC_INFO findData; | ||
38 | struct cifsTconInfo *pTcon; | ||
39 | struct inode *inode; | ||
40 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
41 | char *tmp_path; | ||
42 | |||
43 | pTcon = cifs_sb->tcon; | ||
44 | cFYI(1, (" Getting info on %s ", search_path)); | ||
45 | /* could have done a find first instead but this returns more info */ | ||
46 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, | ||
47 | cifs_sb->local_nls); | ||
48 | /* dump_mem("\nUnixQPathInfo return data", &findData, | ||
49 | sizeof(findData)); */ | ||
50 | if (rc) { | ||
51 | if (rc == -EREMOTE) { | ||
52 | tmp_path = | ||
53 | kmalloc(strnlen(pTcon->treeName, | ||
54 | MAX_TREE_SIZE + 1) + | ||
55 | strnlen(search_path, MAX_PATHCONF) + 1, | ||
56 | GFP_KERNEL); | ||
57 | if (tmp_path == NULL) { | ||
58 | return -ENOMEM; | ||
59 | } | ||
60 | /* have to skip first of the double backslash of | ||
61 | UNC name */ | ||
62 | strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); | ||
63 | strncat(tmp_path, search_path, MAX_PATHCONF); | ||
64 | rc = connect_to_dfs_path(xid, pTcon->ses, | ||
65 | /* treename + */ tmp_path, | ||
66 | cifs_sb->local_nls); | ||
67 | kfree(tmp_path); | ||
68 | |||
69 | /* BB fix up inode etc. */ | ||
70 | } else if (rc) { | ||
71 | return rc; | ||
72 | } | ||
73 | } else { | ||
74 | struct cifsInodeInfo *cifsInfo; | ||
75 | __u32 type = le32_to_cpu(findData.Type); | ||
76 | __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes); | ||
77 | __u64 end_of_file = le64_to_cpu(findData.EndOfFile); | ||
78 | |||
79 | /* get new inode */ | ||
80 | if (*pinode == NULL) { | ||
81 | *pinode = new_inode(sb); | ||
82 | if(*pinode == NULL) | ||
83 | return -ENOMEM; | ||
84 | /* Is an i_ino of zero legal? */ | ||
85 | /* Are there sanity checks we can use to ensure that | ||
86 | the server is really filling in that field? */ | ||
87 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | ||
88 | (*pinode)->i_ino = | ||
89 | (unsigned long)findData.UniqueId; | ||
90 | } /* note ino incremented to unique num in new_inode */ | ||
91 | insert_inode_hash(*pinode); | ||
92 | } | ||
93 | |||
94 | inode = *pinode; | ||
95 | cifsInfo = CIFS_I(inode); | ||
96 | |||
97 | cFYI(1, (" Old time %ld ", cifsInfo->time)); | ||
98 | cifsInfo->time = jiffies; | ||
99 | cFYI(1, (" New time %ld ", cifsInfo->time)); | ||
100 | /* this is ok to set on every inode revalidate */ | ||
101 | atomic_set(&cifsInfo->inUse,1); | ||
102 | |||
103 | inode->i_atime = | ||
104 | cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime)); | ||
105 | inode->i_mtime = | ||
106 | cifs_NTtimeToUnix(le64_to_cpu | ||
107 | (findData.LastModificationTime)); | ||
108 | inode->i_ctime = | ||
109 | cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange)); | ||
110 | inode->i_mode = le64_to_cpu(findData.Permissions); | ||
111 | if (type == UNIX_FILE) { | ||
112 | inode->i_mode |= S_IFREG; | ||
113 | } else if (type == UNIX_SYMLINK) { | ||
114 | inode->i_mode |= S_IFLNK; | ||
115 | } else if (type == UNIX_DIR) { | ||
116 | inode->i_mode |= S_IFDIR; | ||
117 | } else if (type == UNIX_CHARDEV) { | ||
118 | inode->i_mode |= S_IFCHR; | ||
119 | inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), | ||
120 | le64_to_cpu(findData.DevMinor) & MINORMASK); | ||
121 | } else if (type == UNIX_BLOCKDEV) { | ||
122 | inode->i_mode |= S_IFBLK; | ||
123 | inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), | ||
124 | le64_to_cpu(findData.DevMinor) & MINORMASK); | ||
125 | } else if (type == UNIX_FIFO) { | ||
126 | inode->i_mode |= S_IFIFO; | ||
127 | } else if (type == UNIX_SOCKET) { | ||
128 | inode->i_mode |= S_IFSOCK; | ||
129 | } | ||
130 | inode->i_uid = le64_to_cpu(findData.Uid); | ||
131 | inode->i_gid = le64_to_cpu(findData.Gid); | ||
132 | inode->i_nlink = le64_to_cpu(findData.Nlinks); | ||
133 | |||
134 | if(is_size_safe_to_change(cifsInfo)) { | ||
135 | /* can not safely change the file size here if the | ||
136 | client is writing to it due to potential races */ | ||
137 | |||
138 | i_size_write(inode, end_of_file); | ||
139 | |||
140 | /* blksize needs to be multiple of two. So safer to default to | ||
141 | blksize and blkbits set in superblock so 2**blkbits and blksize | ||
142 | will match rather than setting to: | ||
143 | (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ | ||
144 | |||
145 | /* This seems incredibly stupid but it turns out that i_blocks | ||
146 | is not related to (i_size / i_blksize), instead 512 byte size | ||
147 | is required for calculating num blocks */ | ||
148 | |||
149 | /* 512 bytes (2**9) is the fake blocksize that must be used */ | ||
150 | /* for this calculation */ | ||
151 | inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; | ||
152 | } | ||
153 | |||
154 | if (num_of_bytes < end_of_file) | ||
155 | cFYI(1, ("allocation size less than end of file ")); | ||
156 | cFYI(1, | ||
157 | ("Size %ld and blocks %ld", | ||
158 | (unsigned long) inode->i_size, inode->i_blocks)); | ||
159 | if (S_ISREG(inode->i_mode)) { | ||
160 | cFYI(1, (" File inode ")); | ||
161 | inode->i_op = &cifs_file_inode_ops; | ||
162 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | ||
163 | inode->i_fop = &cifs_file_direct_ops; | ||
164 | else | ||
165 | inode->i_fop = &cifs_file_ops; | ||
166 | inode->i_data.a_ops = &cifs_addr_ops; | ||
167 | } else if (S_ISDIR(inode->i_mode)) { | ||
168 | cFYI(1, (" Directory inode")); | ||
169 | inode->i_op = &cifs_dir_inode_ops; | ||
170 | inode->i_fop = &cifs_dir_ops; | ||
171 | } else if (S_ISLNK(inode->i_mode)) { | ||
172 | cFYI(1, (" Symbolic Link inode ")); | ||
173 | inode->i_op = &cifs_symlink_inode_ops; | ||
174 | /* tmp_inode->i_fop = */ /* do not need to set to anything */ | ||
175 | } else { | ||
176 | cFYI(1, (" Init special inode ")); | ||
177 | init_special_inode(inode, inode->i_mode, | ||
178 | inode->i_rdev); | ||
179 | } | ||
180 | } | ||
181 | return rc; | ||
182 | } | ||
183 | |||
184 | int cifs_get_inode_info(struct inode **pinode, | ||
185 | const unsigned char *search_path, FILE_ALL_INFO *pfindData, | ||
186 | struct super_block *sb, int xid) | ||
187 | { | ||
188 | int rc = 0; | ||
189 | struct cifsTconInfo *pTcon; | ||
190 | struct inode *inode; | ||
191 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
192 | char *tmp_path; | ||
193 | char *buf = NULL; | ||
194 | |||
195 | pTcon = cifs_sb->tcon; | ||
196 | cFYI(1,("Getting info on %s ", search_path)); | ||
197 | |||
198 | if((pfindData == NULL) && (*pinode != NULL)) { | ||
199 | if(CIFS_I(*pinode)->clientCanCacheRead) { | ||
200 | cFYI(1,("No need to revalidate cached inode sizes")); | ||
201 | return rc; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | /* if file info not passed in then get it from server */ | ||
206 | if(pfindData == NULL) { | ||
207 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
208 | if(buf == NULL) | ||
209 | return -ENOMEM; | ||
210 | pfindData = (FILE_ALL_INFO *)buf; | ||
211 | /* could do find first instead but this returns more info */ | ||
212 | rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, | ||
213 | cifs_sb->local_nls); | ||
214 | } | ||
215 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ | ||
216 | if (rc) { | ||
217 | if (rc == -EREMOTE) { | ||
218 | tmp_path = | ||
219 | kmalloc(strnlen | ||
220 | (pTcon->treeName, | ||
221 | MAX_TREE_SIZE + 1) + | ||
222 | strnlen(search_path, MAX_PATHCONF) + 1, | ||
223 | GFP_KERNEL); | ||
224 | if (tmp_path == NULL) { | ||
225 | kfree(buf); | ||
226 | return -ENOMEM; | ||
227 | } | ||
228 | |||
229 | strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); | ||
230 | strncat(tmp_path, search_path, MAX_PATHCONF); | ||
231 | rc = connect_to_dfs_path(xid, pTcon->ses, | ||
232 | /* treename + */ tmp_path, | ||
233 | cifs_sb->local_nls); | ||
234 | kfree(tmp_path); | ||
235 | /* BB fix up inode etc. */ | ||
236 | } else if (rc) { | ||
237 | kfree(buf); | ||
238 | return rc; | ||
239 | } | ||
240 | } else { | ||
241 | struct cifsInodeInfo *cifsInfo; | ||
242 | __u32 attr = le32_to_cpu(pfindData->Attributes); | ||
243 | |||
244 | /* get new inode */ | ||
245 | if (*pinode == NULL) { | ||
246 | *pinode = new_inode(sb); | ||
247 | if (*pinode == NULL) | ||
248 | return -ENOMEM; | ||
249 | /* Is an i_ino of zero legal? Can we use that to check | ||
250 | if the server supports returning inode numbers? Are | ||
251 | there other sanity checks we can use to ensure that | ||
252 | the server is really filling in that field? */ | ||
253 | |||
254 | /* We can not use the IndexNumber field by default from | ||
255 | Windows or Samba (in ALL_INFO buf) but we can request | ||
256 | it explicitly. It may not be unique presumably if | ||
257 | the server has multiple devices mounted under one | ||
258 | share */ | ||
259 | |||
260 | /* There may be higher info levels that work but are | ||
261 | there Windows server or network appliances for which | ||
262 | IndexNumber field is not guaranteed unique? */ | ||
263 | |||
264 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
265 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){ | ||
266 | int rc1 = 0; | ||
267 | __u64 inode_num; | ||
268 | |||
269 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, | ||
270 | search_path, &inode_num, | ||
271 | cifs_sb->local_nls); | ||
272 | if(rc1) { | ||
273 | cFYI(1,("GetSrvInodeNum rc %d", rc1)); | ||
274 | /* BB EOPNOSUPP disable SERVER_INUM? */ | ||
275 | } else /* do we need cast or hash to ino? */ | ||
276 | (*pinode)->i_ino = inode_num; | ||
277 | } /* else ino incremented to unique num in new_inode*/ | ||
278 | #endif /* CIFS_EXPERIMENTAL */ | ||
279 | insert_inode_hash(*pinode); | ||
280 | } | ||
281 | inode = *pinode; | ||
282 | cifsInfo = CIFS_I(inode); | ||
283 | cifsInfo->cifsAttrs = attr; | ||
284 | cFYI(1, (" Old time %ld ", cifsInfo->time)); | ||
285 | cifsInfo->time = jiffies; | ||
286 | cFYI(1, (" New time %ld ", cifsInfo->time)); | ||
287 | |||
288 | /* blksize needs to be multiple of two. So safer to default to | ||
289 | blksize and blkbits set in superblock so 2**blkbits and blksize | ||
290 | will match rather than setting to: | ||
291 | (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ | ||
292 | |||
293 | /* Linux can not store file creation time unfortunately so we ignore it */ | ||
294 | inode->i_atime = | ||
295 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); | ||
296 | inode->i_mtime = | ||
297 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); | ||
298 | inode->i_ctime = | ||
299 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); | ||
300 | cFYI(0, (" Attributes came in as 0x%x ", attr)); | ||
301 | |||
302 | /* set default mode. will override for dirs below */ | ||
303 | if (atomic_read(&cifsInfo->inUse) == 0) | ||
304 | /* new inode, can safely set these fields */ | ||
305 | inode->i_mode = cifs_sb->mnt_file_mode; | ||
306 | |||
307 | /* if (attr & ATTR_REPARSE) */ | ||
308 | /* We no longer handle these as symlinks because we could not | ||
309 | follow them due to the absolute path with drive letter */ | ||
310 | if (attr & ATTR_DIRECTORY) { | ||
311 | /* override default perms since we do not do byte range locking | ||
312 | on dirs */ | ||
313 | inode->i_mode = cifs_sb->mnt_dir_mode; | ||
314 | inode->i_mode |= S_IFDIR; | ||
315 | } else { | ||
316 | inode->i_mode |= S_IFREG; | ||
317 | /* treat the dos attribute of read-only as read-only | ||
318 | mode e.g. 555 */ | ||
319 | if (cifsInfo->cifsAttrs & ATTR_READONLY) | ||
320 | inode->i_mode &= ~(S_IWUGO); | ||
321 | /* BB add code here - | ||
322 | validate if device or weird share or device type? */ | ||
323 | } | ||
324 | if (is_size_safe_to_change(cifsInfo)) { | ||
325 | /* can not safely change the file size here if the | ||
326 | client is writing to it due to potential races */ | ||
327 | i_size_write(inode,le64_to_cpu(pfindData->EndOfFile)); | ||
328 | |||
329 | /* 512 bytes (2**9) is the fake blocksize that must be | ||
330 | used for this calculation */ | ||
331 | inode->i_blocks = (512 - 1 + le64_to_cpu( | ||
332 | pfindData->AllocationSize)) >> 9; | ||
333 | } | ||
334 | |||
335 | inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); | ||
336 | |||
337 | /* BB fill in uid and gid here? with help from winbind? | ||
338 | or retrieve from NTFS stream extended attribute */ | ||
339 | if (atomic_read(&cifsInfo->inUse) == 0) { | ||
340 | inode->i_uid = cifs_sb->mnt_uid; | ||
341 | inode->i_gid = cifs_sb->mnt_gid; | ||
342 | /* set so we do not keep refreshing these fields with | ||
343 | bad data after user has changed them in memory */ | ||
344 | atomic_set(&cifsInfo->inUse,1); | ||
345 | } | ||
346 | |||
347 | if (S_ISREG(inode->i_mode)) { | ||
348 | cFYI(1, (" File inode ")); | ||
349 | inode->i_op = &cifs_file_inode_ops; | ||
350 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | ||
351 | inode->i_fop = &cifs_file_direct_ops; | ||
352 | else | ||
353 | inode->i_fop = &cifs_file_ops; | ||
354 | inode->i_data.a_ops = &cifs_addr_ops; | ||
355 | } else if (S_ISDIR(inode->i_mode)) { | ||
356 | cFYI(1, (" Directory inode ")); | ||
357 | inode->i_op = &cifs_dir_inode_ops; | ||
358 | inode->i_fop = &cifs_dir_ops; | ||
359 | } else if (S_ISLNK(inode->i_mode)) { | ||
360 | cFYI(1, (" Symbolic Link inode ")); | ||
361 | inode->i_op = &cifs_symlink_inode_ops; | ||
362 | } else { | ||
363 | init_special_inode(inode, inode->i_mode, | ||
364 | inode->i_rdev); | ||
365 | } | ||
366 | } | ||
367 | kfree(buf); | ||
368 | return rc; | ||
369 | } | ||
370 | |||
371 | /* gets root inode */ | ||
372 | void cifs_read_inode(struct inode *inode) | ||
373 | { | ||
374 | int xid; | ||
375 | struct cifs_sb_info *cifs_sb; | ||
376 | |||
377 | cifs_sb = CIFS_SB(inode->i_sb); | ||
378 | xid = GetXid(); | ||
379 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) | ||
380 | cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid); | ||
381 | else | ||
382 | cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid); | ||
383 | /* can not call macro FreeXid here since in a void func */ | ||
384 | _FreeXid(xid); | ||
385 | } | ||
386 | |||
387 | int cifs_unlink(struct inode *inode, struct dentry *direntry) | ||
388 | { | ||
389 | int rc = 0; | ||
390 | int xid; | ||
391 | struct cifs_sb_info *cifs_sb; | ||
392 | struct cifsTconInfo *pTcon; | ||
393 | char *full_path = NULL; | ||
394 | struct cifsInodeInfo *cifsInode; | ||
395 | FILE_BASIC_INFO *pinfo_buf; | ||
396 | |||
397 | cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode)); | ||
398 | |||
399 | xid = GetXid(); | ||
400 | |||
401 | cifs_sb = CIFS_SB(inode->i_sb); | ||
402 | pTcon = cifs_sb->tcon; | ||
403 | |||
404 | /* Unlink can be called from rename so we can not grab the sem here | ||
405 | since we deadlock otherwise */ | ||
406 | /* down(&direntry->d_sb->s_vfs_rename_sem);*/ | ||
407 | full_path = build_path_from_dentry(direntry); | ||
408 | /* up(&direntry->d_sb->s_vfs_rename_sem);*/ | ||
409 | if (full_path == NULL) { | ||
410 | FreeXid(xid); | ||
411 | return -ENOMEM; | ||
412 | } | ||
413 | rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls); | ||
414 | |||
415 | if (!rc) { | ||
416 | direntry->d_inode->i_nlink--; | ||
417 | } else if (rc == -ENOENT) { | ||
418 | d_drop(direntry); | ||
419 | } else if (rc == -ETXTBSY) { | ||
420 | int oplock = FALSE; | ||
421 | __u16 netfid; | ||
422 | |||
423 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, | ||
424 | CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, | ||
425 | &netfid, &oplock, NULL, cifs_sb->local_nls); | ||
426 | if (rc==0) { | ||
427 | CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL, | ||
428 | cifs_sb->local_nls); | ||
429 | CIFSSMBClose(xid, pTcon, netfid); | ||
430 | direntry->d_inode->i_nlink--; | ||
431 | } | ||
432 | } else if (rc == -EACCES) { | ||
433 | /* try only if r/o attribute set in local lookup data? */ | ||
434 | pinfo_buf = kmalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL); | ||
435 | if (pinfo_buf) { | ||
436 | memset(pinfo_buf, 0, sizeof(FILE_BASIC_INFO)); | ||
437 | /* ATTRS set to normal clears r/o bit */ | ||
438 | pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); | ||
439 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) | ||
440 | rc = CIFSSMBSetTimes(xid, pTcon, full_path, | ||
441 | pinfo_buf, | ||
442 | cifs_sb->local_nls); | ||
443 | else | ||
444 | rc = -EOPNOTSUPP; | ||
445 | |||
446 | if (rc == -EOPNOTSUPP) { | ||
447 | int oplock = FALSE; | ||
448 | __u16 netfid; | ||
449 | /* rc = CIFSSMBSetAttrLegacy(xid, pTcon, | ||
450 | full_path, | ||
451 | (__u16)ATTR_NORMAL, | ||
452 | cifs_sb->local_nls); | ||
453 | For some strange reason it seems that NT4 eats the | ||
454 | old setattr call without actually setting the | ||
455 | attributes so on to the third attempted workaround | ||
456 | */ | ||
457 | |||
458 | /* BB could scan to see if we already have it open | ||
459 | and pass in pid of opener to function */ | ||
460 | rc = CIFSSMBOpen(xid, pTcon, full_path, | ||
461 | FILE_OPEN, SYNCHRONIZE | | ||
462 | FILE_WRITE_ATTRIBUTES, 0, | ||
463 | &netfid, &oplock, NULL, | ||
464 | cifs_sb->local_nls); | ||
465 | if (rc==0) { | ||
466 | rc = CIFSSMBSetFileTimes(xid, pTcon, | ||
467 | pinfo_buf, | ||
468 | netfid); | ||
469 | CIFSSMBClose(xid, pTcon, netfid); | ||
470 | } | ||
471 | } | ||
472 | kfree(pinfo_buf); | ||
473 | } | ||
474 | if (rc==0) { | ||
475 | rc = CIFSSMBDelFile(xid, pTcon, full_path, | ||
476 | cifs_sb->local_nls); | ||
477 | if (!rc) { | ||
478 | direntry->d_inode->i_nlink--; | ||
479 | } else if (rc == -ETXTBSY) { | ||
480 | int oplock = FALSE; | ||
481 | __u16 netfid; | ||
482 | |||
483 | rc = CIFSSMBOpen(xid, pTcon, full_path, | ||
484 | FILE_OPEN, DELETE, | ||
485 | CREATE_NOT_DIR | | ||
486 | CREATE_DELETE_ON_CLOSE, | ||
487 | &netfid, &oplock, NULL, | ||
488 | cifs_sb->local_nls); | ||
489 | if (rc==0) { | ||
490 | CIFSSMBRenameOpenFile(xid, pTcon, | ||
491 | netfid, NULL, | ||
492 | cifs_sb->local_nls); | ||
493 | CIFSSMBClose(xid, pTcon, netfid); | ||
494 | direntry->d_inode->i_nlink--; | ||
495 | } | ||
496 | /* BB if rc = -ETXTBUSY goto the rename logic BB */ | ||
497 | } | ||
498 | } | ||
499 | } | ||
500 | cifsInode = CIFS_I(direntry->d_inode); | ||
501 | cifsInode->time = 0; /* will force revalidate to get info when | ||
502 | needed */ | ||
503 | direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = | ||
504 | current_fs_time(inode->i_sb); | ||
505 | cifsInode = CIFS_I(inode); | ||
506 | cifsInode->time = 0; /* force revalidate of dir as well */ | ||
507 | |||
508 | kfree(full_path); | ||
509 | FreeXid(xid); | ||
510 | return rc; | ||
511 | } | ||
512 | |||
513 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | ||
514 | { | ||
515 | int rc = 0; | ||
516 | int xid; | ||
517 | struct cifs_sb_info *cifs_sb; | ||
518 | struct cifsTconInfo *pTcon; | ||
519 | char *full_path = NULL; | ||
520 | struct inode *newinode = NULL; | ||
521 | |||
522 | cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode)); | ||
523 | |||
524 | xid = GetXid(); | ||
525 | |||
526 | cifs_sb = CIFS_SB(inode->i_sb); | ||
527 | pTcon = cifs_sb->tcon; | ||
528 | |||
529 | down(&inode->i_sb->s_vfs_rename_sem); | ||
530 | full_path = build_path_from_dentry(direntry); | ||
531 | up(&inode->i_sb->s_vfs_rename_sem); | ||
532 | if (full_path == NULL) { | ||
533 | FreeXid(xid); | ||
534 | return -ENOMEM; | ||
535 | } | ||
536 | /* BB add setting the equivalent of mode via CreateX w/ACLs */ | ||
537 | rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls); | ||
538 | if (rc) { | ||
539 | cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); | ||
540 | d_drop(direntry); | ||
541 | } else { | ||
542 | inode->i_nlink++; | ||
543 | if (pTcon->ses->capabilities & CAP_UNIX) | ||
544 | rc = cifs_get_inode_info_unix(&newinode, full_path, | ||
545 | inode->i_sb,xid); | ||
546 | else | ||
547 | rc = cifs_get_inode_info(&newinode, full_path, NULL, | ||
548 | inode->i_sb,xid); | ||
549 | |||
550 | direntry->d_op = &cifs_dentry_ops; | ||
551 | d_instantiate(direntry, newinode); | ||
552 | if (direntry->d_inode) | ||
553 | direntry->d_inode->i_nlink = 2; | ||
554 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) | ||
555 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | ||
556 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | ||
557 | mode, | ||
558 | (__u64)current->euid, | ||
559 | (__u64)current->egid, | ||
560 | 0 /* dev_t */, | ||
561 | cifs_sb->local_nls); | ||
562 | } else { | ||
563 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | ||
564 | mode, (__u64)-1, | ||
565 | (__u64)-1, 0 /* dev_t */, | ||
566 | cifs_sb->local_nls); | ||
567 | } | ||
568 | else { | ||
569 | /* BB to be implemented via Windows secrty descriptors | ||
570 | eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, | ||
571 | -1, -1, local_nls); */ | ||
572 | } | ||
573 | } | ||
574 | kfree(full_path); | ||
575 | FreeXid(xid); | ||
576 | return rc; | ||
577 | } | ||
578 | |||
579 | int cifs_rmdir(struct inode *inode, struct dentry *direntry) | ||
580 | { | ||
581 | int rc = 0; | ||
582 | int xid; | ||
583 | struct cifs_sb_info *cifs_sb; | ||
584 | struct cifsTconInfo *pTcon; | ||
585 | char *full_path = NULL; | ||
586 | struct cifsInodeInfo *cifsInode; | ||
587 | |||
588 | cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode)); | ||
589 | |||
590 | xid = GetXid(); | ||
591 | |||
592 | cifs_sb = CIFS_SB(inode->i_sb); | ||
593 | pTcon = cifs_sb->tcon; | ||
594 | |||
595 | down(&inode->i_sb->s_vfs_rename_sem); | ||
596 | full_path = build_path_from_dentry(direntry); | ||
597 | up(&inode->i_sb->s_vfs_rename_sem); | ||
598 | if (full_path == NULL) { | ||
599 | FreeXid(xid); | ||
600 | return -ENOMEM; | ||
601 | } | ||
602 | |||
603 | rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls); | ||
604 | |||
605 | if (!rc) { | ||
606 | inode->i_nlink--; | ||
607 | i_size_write(direntry->d_inode,0); | ||
608 | direntry->d_inode->i_nlink = 0; | ||
609 | } | ||
610 | |||
611 | cifsInode = CIFS_I(direntry->d_inode); | ||
612 | cifsInode->time = 0; /* force revalidate to go get info when | ||
613 | needed */ | ||
614 | direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = | ||
615 | current_fs_time(inode->i_sb); | ||
616 | |||
617 | kfree(full_path); | ||
618 | FreeXid(xid); | ||
619 | return rc; | ||
620 | } | ||
621 | |||
622 | int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, | ||
623 | struct inode *target_inode, struct dentry *target_direntry) | ||
624 | { | ||
625 | char *fromName; | ||
626 | char *toName; | ||
627 | struct cifs_sb_info *cifs_sb_source; | ||
628 | struct cifs_sb_info *cifs_sb_target; | ||
629 | struct cifsTconInfo *pTcon; | ||
630 | int xid; | ||
631 | int rc = 0; | ||
632 | |||
633 | xid = GetXid(); | ||
634 | |||
635 | cifs_sb_target = CIFS_SB(target_inode->i_sb); | ||
636 | cifs_sb_source = CIFS_SB(source_inode->i_sb); | ||
637 | pTcon = cifs_sb_source->tcon; | ||
638 | |||
639 | if (pTcon != cifs_sb_target->tcon) { | ||
640 | FreeXid(xid); | ||
641 | return -EXDEV; /* BB actually could be allowed if same server, | ||
642 | but different share. | ||
643 | Might eventually add support for this */ | ||
644 | } | ||
645 | |||
646 | /* we already have the rename sem so we do not need to grab it again | ||
647 | here to protect the path integrity */ | ||
648 | fromName = build_path_from_dentry(source_direntry); | ||
649 | toName = build_path_from_dentry(target_direntry); | ||
650 | if ((fromName == NULL) || (toName == NULL)) { | ||
651 | rc = -ENOMEM; | ||
652 | goto cifs_rename_exit; | ||
653 | } | ||
654 | |||
655 | rc = CIFSSMBRename(xid, pTcon, fromName, toName, | ||
656 | cifs_sb_source->local_nls); | ||
657 | if (rc == -EEXIST) { | ||
658 | /* check if they are the same file because rename of hardlinked | ||
659 | files is a noop */ | ||
660 | FILE_UNIX_BASIC_INFO *info_buf_source; | ||
661 | FILE_UNIX_BASIC_INFO *info_buf_target; | ||
662 | |||
663 | info_buf_source = | ||
664 | kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | ||
665 | if (info_buf_source != NULL) { | ||
666 | info_buf_target = info_buf_source + 1; | ||
667 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, | ||
668 | info_buf_source, cifs_sb_source->local_nls); | ||
669 | if (rc == 0) { | ||
670 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName, | ||
671 | info_buf_target, | ||
672 | cifs_sb_target->local_nls); | ||
673 | } | ||
674 | if ((rc == 0) && | ||
675 | (info_buf_source->UniqueId == | ||
676 | info_buf_target->UniqueId)) { | ||
677 | /* do not rename since the files are hardlinked which | ||
678 | is a noop */ | ||
679 | } else { | ||
680 | /* we either can not tell the files are hardlinked | ||
681 | (as with Windows servers) or files are not | ||
682 | hardlinked so delete the target manually before | ||
683 | renaming to follow POSIX rather than Windows | ||
684 | semantics */ | ||
685 | cifs_unlink(target_inode, target_direntry); | ||
686 | rc = CIFSSMBRename(xid, pTcon, fromName, | ||
687 | toName, | ||
688 | cifs_sb_source->local_nls); | ||
689 | } | ||
690 | kfree(info_buf_source); | ||
691 | } /* if we can not get memory just leave rc as EEXIST */ | ||
692 | } | ||
693 | |||
694 | if (rc) { | ||
695 | cFYI(1, ("rename rc %d", rc)); | ||
696 | } | ||
697 | |||
698 | if ((rc == -EIO) || (rc == -EEXIST)) { | ||
699 | int oplock = FALSE; | ||
700 | __u16 netfid; | ||
701 | |||
702 | /* BB FIXME Is Generic Read correct for rename? */ | ||
703 | /* if renaming directory - we should not say CREATE_NOT_DIR, | ||
704 | need to test renaming open directory, also GENERIC_READ | ||
705 | might not right be right access to request */ | ||
706 | rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, | ||
707 | CREATE_NOT_DIR, &netfid, &oplock, NULL, | ||
708 | cifs_sb_source->local_nls); | ||
709 | if (rc==0) { | ||
710 | CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName, | ||
711 | cifs_sb_source->local_nls); | ||
712 | CIFSSMBClose(xid, pTcon, netfid); | ||
713 | } | ||
714 | } | ||
715 | |||
716 | cifs_rename_exit: | ||
717 | kfree(fromName); | ||
718 | kfree(toName); | ||
719 | FreeXid(xid); | ||
720 | return rc; | ||
721 | } | ||
722 | |||
723 | int cifs_revalidate(struct dentry *direntry) | ||
724 | { | ||
725 | int xid; | ||
726 | int rc = 0; | ||
727 | char *full_path; | ||
728 | struct cifs_sb_info *cifs_sb; | ||
729 | struct cifsInodeInfo *cifsInode; | ||
730 | loff_t local_size; | ||
731 | struct timespec local_mtime; | ||
732 | int invalidate_inode = FALSE; | ||
733 | |||
734 | if (direntry->d_inode == NULL) | ||
735 | return -ENOENT; | ||
736 | |||
737 | cifsInode = CIFS_I(direntry->d_inode); | ||
738 | |||
739 | if (cifsInode == NULL) | ||
740 | return -ENOENT; | ||
741 | |||
742 | /* no sense revalidating inode info on file that no one can write */ | ||
743 | if (CIFS_I(direntry->d_inode)->clientCanCacheRead) | ||
744 | return rc; | ||
745 | |||
746 | xid = GetXid(); | ||
747 | |||
748 | cifs_sb = CIFS_SB(direntry->d_sb); | ||
749 | |||
750 | /* can not safely grab the rename sem here if rename calls revalidate | ||
751 | since that would deadlock */ | ||
752 | full_path = build_path_from_dentry(direntry); | ||
753 | if (full_path == NULL) { | ||
754 | FreeXid(xid); | ||
755 | return -ENOMEM; | ||
756 | } | ||
757 | cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " | ||
758 | "jiffies %ld", full_path, direntry->d_inode, | ||
759 | direntry->d_inode->i_count.counter, direntry, | ||
760 | direntry->d_time, jiffies)); | ||
761 | |||
762 | if (cifsInode->time == 0) { | ||
763 | /* was set to zero previously to force revalidate */ | ||
764 | } else if (time_before(jiffies, cifsInode->time + HZ) && | ||
765 | lookupCacheEnabled) { | ||
766 | if ((S_ISREG(direntry->d_inode->i_mode) == 0) || | ||
767 | (direntry->d_inode->i_nlink == 1)) { | ||
768 | kfree(full_path); | ||
769 | FreeXid(xid); | ||
770 | return rc; | ||
771 | } else { | ||
772 | cFYI(1, ("Have to revalidate file due to hardlinks")); | ||
773 | } | ||
774 | } | ||
775 | |||
776 | /* save mtime and size */ | ||
777 | local_mtime = direntry->d_inode->i_mtime; | ||
778 | local_size = direntry->d_inode->i_size; | ||
779 | |||
780 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { | ||
781 | rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path, | ||
782 | direntry->d_sb,xid); | ||
783 | if (rc) { | ||
784 | cFYI(1, ("error on getting revalidate info %d", rc)); | ||
785 | /* if (rc != -ENOENT) | ||
786 | rc = 0; */ /* BB should we cache info on | ||
787 | certain errors? */ | ||
788 | } | ||
789 | } else { | ||
790 | rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, | ||
791 | direntry->d_sb,xid); | ||
792 | if (rc) { | ||
793 | cFYI(1, ("error on getting revalidate info %d", rc)); | ||
794 | /* if (rc != -ENOENT) | ||
795 | rc = 0; */ /* BB should we cache info on | ||
796 | certain errors? */ | ||
797 | } | ||
798 | } | ||
799 | /* should we remap certain errors, access denied?, to zero */ | ||
800 | |||
801 | /* if not oplocked, we invalidate inode pages if mtime or file size | ||
802 | had changed on server */ | ||
803 | |||
804 | if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && | ||
805 | (local_size == direntry->d_inode->i_size)) { | ||
806 | cFYI(1, ("cifs_revalidate - inode unchanged")); | ||
807 | } else { | ||
808 | /* file may have changed on server */ | ||
809 | if (cifsInode->clientCanCacheRead) { | ||
810 | /* no need to invalidate inode pages since we were the | ||
811 | only ones who could have modified the file and the | ||
812 | server copy is staler than ours */ | ||
813 | } else { | ||
814 | invalidate_inode = TRUE; | ||
815 | } | ||
816 | } | ||
817 | |||
818 | /* can not grab this sem since kernel filesys locking documentation | ||
819 | indicates i_sem may be taken by the kernel on lookup and rename | ||
820 | which could deadlock if we grab the i_sem here as well */ | ||
821 | /* down(&direntry->d_inode->i_sem);*/ | ||
822 | /* need to write out dirty pages here */ | ||
823 | if (direntry->d_inode->i_mapping) { | ||
824 | /* do we need to lock inode until after invalidate completes | ||
825 | below? */ | ||
826 | filemap_fdatawrite(direntry->d_inode->i_mapping); | ||
827 | } | ||
828 | if (invalidate_inode) { | ||
829 | if (direntry->d_inode->i_mapping) | ||
830 | filemap_fdatawait(direntry->d_inode->i_mapping); | ||
831 | /* may eventually have to do this for open files too */ | ||
832 | if (list_empty(&(cifsInode->openFileList))) { | ||
833 | /* Has changed on server - flush read ahead pages */ | ||
834 | cFYI(1, ("Invalidating read ahead data on " | ||
835 | "closed file")); | ||
836 | invalidate_remote_inode(direntry->d_inode); | ||
837 | } | ||
838 | } | ||
839 | /* up(&direntry->d_inode->i_sem); */ | ||
840 | |||
841 | kfree(full_path); | ||
842 | FreeXid(xid); | ||
843 | return rc; | ||
844 | } | ||
845 | |||
846 | int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, | ||
847 | struct kstat *stat) | ||
848 | { | ||
849 | int err = cifs_revalidate(dentry); | ||
850 | if (!err) | ||
851 | generic_fillattr(dentry->d_inode, stat); | ||
852 | return err; | ||
853 | } | ||
854 | |||
855 | static int cifs_truncate_page(struct address_space *mapping, loff_t from) | ||
856 | { | ||
857 | pgoff_t index = from >> PAGE_CACHE_SHIFT; | ||
858 | unsigned offset = from & (PAGE_CACHE_SIZE - 1); | ||
859 | struct page *page; | ||
860 | char *kaddr; | ||
861 | int rc = 0; | ||
862 | |||
863 | page = grab_cache_page(mapping, index); | ||
864 | if (!page) | ||
865 | return -ENOMEM; | ||
866 | |||
867 | kaddr = kmap_atomic(page, KM_USER0); | ||
868 | memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); | ||
869 | flush_dcache_page(page); | ||
870 | kunmap_atomic(kaddr, KM_USER0); | ||
871 | unlock_page(page); | ||
872 | page_cache_release(page); | ||
873 | return rc; | ||
874 | } | ||
875 | |||
876 | int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | ||
877 | { | ||
878 | int xid; | ||
879 | struct cifs_sb_info *cifs_sb; | ||
880 | struct cifsTconInfo *pTcon; | ||
881 | char *full_path = NULL; | ||
882 | int rc = -EACCES; | ||
883 | int found = FALSE; | ||
884 | struct cifsFileInfo *open_file = NULL; | ||
885 | FILE_BASIC_INFO time_buf; | ||
886 | int set_time = FALSE; | ||
887 | __u64 mode = 0xFFFFFFFFFFFFFFFFULL; | ||
888 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; | ||
889 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; | ||
890 | struct cifsInodeInfo *cifsInode; | ||
891 | struct list_head *tmp; | ||
892 | |||
893 | xid = GetXid(); | ||
894 | |||
895 | cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ", | ||
896 | direntry->d_name.name, attrs->ia_valid)); | ||
897 | cifs_sb = CIFS_SB(direntry->d_inode->i_sb); | ||
898 | pTcon = cifs_sb->tcon; | ||
899 | |||
900 | down(&direntry->d_sb->s_vfs_rename_sem); | ||
901 | full_path = build_path_from_dentry(direntry); | ||
902 | up(&direntry->d_sb->s_vfs_rename_sem); | ||
903 | if (full_path == NULL) { | ||
904 | FreeXid(xid); | ||
905 | return -ENOMEM; | ||
906 | } | ||
907 | cifsInode = CIFS_I(direntry->d_inode); | ||
908 | |||
909 | /* BB check if we need to refresh inode from server now ? BB */ | ||
910 | |||
911 | /* need to flush data before changing file size on server */ | ||
912 | filemap_fdatawrite(direntry->d_inode->i_mapping); | ||
913 | filemap_fdatawait(direntry->d_inode->i_mapping); | ||
914 | |||
915 | if (attrs->ia_valid & ATTR_SIZE) { | ||
916 | read_lock(&GlobalSMBSeslock); | ||
917 | /* To avoid spurious oplock breaks from server, in the case of | ||
918 | inodes that we already have open, avoid doing path based | ||
919 | setting of file size if we can do it by handle. | ||
920 | This keeps our caching token (oplock) and avoids timeouts | ||
921 | when the local oplock break takes longer to flush | ||
922 | writebehind data than the SMB timeout for the SetPathInfo | ||
923 | request would allow */ | ||
924 | list_for_each(tmp, &cifsInode->openFileList) { | ||
925 | open_file = list_entry(tmp, struct cifsFileInfo, | ||
926 | flist); | ||
927 | /* We check if file is open for writing first */ | ||
928 | if ((open_file->pfile) && | ||
929 | ((open_file->pfile->f_flags & O_RDWR) || | ||
930 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
931 | if (open_file->invalidHandle == FALSE) { | ||
932 | /* we found a valid, writeable network | ||
933 | file handle to use to try to set the | ||
934 | file size */ | ||
935 | __u16 nfid = open_file->netfid; | ||
936 | __u32 npid = open_file->pid; | ||
937 | read_unlock(&GlobalSMBSeslock); | ||
938 | found = TRUE; | ||
939 | rc = CIFSSMBSetFileSize(xid, pTcon, | ||
940 | attrs->ia_size, nfid, npid, | ||
941 | FALSE); | ||
942 | cFYI(1, ("SetFileSize by handle " | ||
943 | "(setattrs) rc = %d", rc)); | ||
944 | /* Do not need reopen and retry on | ||
945 | EAGAIN since we will retry by | ||
946 | pathname below */ | ||
947 | |||
948 | /* now that we found one valid file | ||
949 | handle no sense continuing to loop | ||
950 | trying others, so break here */ | ||
951 | break; | ||
952 | } | ||
953 | } | ||
954 | } | ||
955 | if (found == FALSE) | ||
956 | read_unlock(&GlobalSMBSeslock); | ||
957 | |||
958 | if (rc != 0) { | ||
959 | /* Set file size by pathname rather than by handle | ||
960 | either because no valid, writeable file handle for | ||
961 | it was found or because there was an error setting | ||
962 | it by handle */ | ||
963 | rc = CIFSSMBSetEOF(xid, pTcon, full_path, | ||
964 | attrs->ia_size, FALSE, | ||
965 | cifs_sb->local_nls); | ||
966 | cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); | ||
967 | } | ||
968 | |||
969 | /* Server is ok setting allocation size implicitly - no need | ||
970 | to call: | ||
971 | CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, | ||
972 | cifs_sb->local_nls); | ||
973 | */ | ||
974 | |||
975 | if (rc == 0) { | ||
976 | rc = vmtruncate(direntry->d_inode, attrs->ia_size); | ||
977 | cifs_truncate_page(direntry->d_inode->i_mapping, | ||
978 | direntry->d_inode->i_size); | ||
979 | } | ||
980 | } | ||
981 | if (attrs->ia_valid & ATTR_UID) { | ||
982 | cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); | ||
983 | uid = attrs->ia_uid; | ||
984 | /* entry->uid = cpu_to_le16(attr->ia_uid); */ | ||
985 | } | ||
986 | if (attrs->ia_valid & ATTR_GID) { | ||
987 | cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); | ||
988 | gid = attrs->ia_gid; | ||
989 | /* entry->gid = cpu_to_le16(attr->ia_gid); */ | ||
990 | } | ||
991 | |||
992 | time_buf.Attributes = 0; | ||
993 | if (attrs->ia_valid & ATTR_MODE) { | ||
994 | cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); | ||
995 | mode = attrs->ia_mode; | ||
996 | /* entry->mode = cpu_to_le16(attr->ia_mode); */ | ||
997 | } | ||
998 | |||
999 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) | ||
1000 | && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) | ||
1001 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, | ||
1002 | 0 /* dev_t */, cifs_sb->local_nls); | ||
1003 | else if (attrs->ia_valid & ATTR_MODE) { | ||
1004 | if ((mode & S_IWUGO) == 0) /* not writeable */ { | ||
1005 | if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) | ||
1006 | time_buf.Attributes = | ||
1007 | cpu_to_le32(cifsInode->cifsAttrs | | ||
1008 | ATTR_READONLY); | ||
1009 | } else if ((mode & S_IWUGO) == S_IWUGO) { | ||
1010 | if (cifsInode->cifsAttrs & ATTR_READONLY) | ||
1011 | time_buf.Attributes = | ||
1012 | cpu_to_le32(cifsInode->cifsAttrs & | ||
1013 | (~ATTR_READONLY)); | ||
1014 | } | ||
1015 | /* BB to be implemented - | ||
1016 | via Windows security descriptors or streams */ | ||
1017 | /* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid, | ||
1018 | cifs_sb->local_nls); */ | ||
1019 | } | ||
1020 | |||
1021 | if (attrs->ia_valid & ATTR_ATIME) { | ||
1022 | set_time = TRUE; | ||
1023 | time_buf.LastAccessTime = | ||
1024 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); | ||
1025 | } else | ||
1026 | time_buf.LastAccessTime = 0; | ||
1027 | |||
1028 | if (attrs->ia_valid & ATTR_MTIME) { | ||
1029 | set_time = TRUE; | ||
1030 | time_buf.LastWriteTime = | ||
1031 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | ||
1032 | } else | ||
1033 | time_buf.LastWriteTime = 0; | ||
1034 | |||
1035 | if (attrs->ia_valid & ATTR_CTIME) { | ||
1036 | set_time = TRUE; | ||
1037 | cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */ | ||
1038 | time_buf.ChangeTime = | ||
1039 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | ||
1040 | } else | ||
1041 | time_buf.ChangeTime = 0; | ||
1042 | |||
1043 | if (set_time || time_buf.Attributes) { | ||
1044 | /* BB what if setting one attribute fails (such as size) but | ||
1045 | time setting works? */ | ||
1046 | time_buf.CreationTime = 0; /* do not change */ | ||
1047 | /* In the future we should experiment - try setting timestamps | ||
1048 | via Handle (SetFileInfo) instead of by path */ | ||
1049 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) | ||
1050 | rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, | ||
1051 | cifs_sb->local_nls); | ||
1052 | else | ||
1053 | rc = -EOPNOTSUPP; | ||
1054 | |||
1055 | if (rc == -EOPNOTSUPP) { | ||
1056 | int oplock = FALSE; | ||
1057 | __u16 netfid; | ||
1058 | |||
1059 | cFYI(1, ("calling SetFileInfo since SetPathInfo for " | ||
1060 | "times not supported by this server")); | ||
1061 | /* BB we could scan to see if we already have it open | ||
1062 | and pass in pid of opener to function */ | ||
1063 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, | ||
1064 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
1065 | CREATE_NOT_DIR, &netfid, &oplock, | ||
1066 | NULL, cifs_sb->local_nls); | ||
1067 | if (rc==0) { | ||
1068 | rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf, | ||
1069 | netfid); | ||
1070 | CIFSSMBClose(xid, pTcon, netfid); | ||
1071 | } else { | ||
1072 | /* BB For even older servers we could convert time_buf | ||
1073 | into old DOS style which uses two second | ||
1074 | granularity */ | ||
1075 | |||
1076 | /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path, | ||
1077 | &time_buf, cifs_sb->local_nls); */ | ||
1078 | } | ||
1079 | } | ||
1080 | } | ||
1081 | |||
1082 | /* do not need local check to inode_check_ok since the server does | ||
1083 | that */ | ||
1084 | if (!rc) | ||
1085 | rc = inode_setattr(direntry->d_inode, attrs); | ||
1086 | kfree(full_path); | ||
1087 | FreeXid(xid); | ||
1088 | return rc; | ||
1089 | } | ||
1090 | |||
1091 | void cifs_delete_inode(struct inode *inode) | ||
1092 | { | ||
1093 | cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode)); | ||
1094 | /* may have to add back in if and when safe distributed caching of | ||
1095 | directories added e.g. via FindNotify */ | ||
1096 | } | ||
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c new file mode 100644 index 000000000000..b4b8e201d428 --- /dev/null +++ b/fs/cifs/ioctl.c | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * fs/cifs/ioctl.c | ||
3 | * | ||
4 | * vfs operations that deal with io control | ||
5 | * | ||
6 | * Copyright (C) International Business Machines Corp., 2005 | ||
7 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
8 | * | ||
9 | * This library is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU Lesser General Public License as published | ||
11 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This library is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
17 | * the GNU Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public License | ||
20 | * along with this library; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/ext2_fs.h> | ||
25 | #include "cifspdu.h" | ||
26 | #include "cifsglob.h" | ||
27 | #include "cifsproto.h" | ||
28 | #include "cifs_debug.h" | ||
29 | |||
30 | int cifs_ioctl (struct inode * inode, struct file * filep, | ||
31 | unsigned int command, unsigned long arg) | ||
32 | { | ||
33 | int rc = -ENOTTY; /* strange error - but the precedent */ | ||
34 | #ifdef CONFIG_CIFS_POSIX | ||
35 | cFYI(1,("ioctl file %p cmd %u arg %lu",filep,command,arg)); | ||
36 | switch(command) { | ||
37 | case EXT2_IOC_GETFLAGS: | ||
38 | cFYI(1,("get flags not implemented yet")); | ||
39 | return -EOPNOTSUPP; | ||
40 | case EXT2_IOC_SETFLAGS: | ||
41 | cFYI(1,("set flags not implemented yet")); | ||
42 | return -EOPNOTSUPP; | ||
43 | default: | ||
44 | cFYI(1,("unsupported ioctl")); | ||
45 | return rc; | ||
46 | } | ||
47 | #endif /* CONFIG_CIFS_POSIX */ | ||
48 | return rc; | ||
49 | } | ||
diff --git a/fs/cifs/link.c b/fs/cifs/link.c new file mode 100644 index 000000000000..1455810ba1cb --- /dev/null +++ b/fs/cifs/link.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | * fs/cifs/link.c | ||
3 | * | ||
4 | * Copyright (C) International Business Machines Corp., 2002,2003 | ||
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/fs.h> | ||
22 | #include <linux/stat.h> | ||
23 | #include <linux/namei.h> | ||
24 | #include "cifsfs.h" | ||
25 | #include "cifspdu.h" | ||
26 | #include "cifsglob.h" | ||
27 | #include "cifsproto.h" | ||
28 | #include "cifs_debug.h" | ||
29 | #include "cifs_fs_sb.h" | ||
30 | |||
31 | int | ||
32 | cifs_hardlink(struct dentry *old_file, struct inode *inode, | ||
33 | struct dentry *direntry) | ||
34 | { | ||
35 | int rc = -EACCES; | ||
36 | int xid; | ||
37 | char *fromName = NULL; | ||
38 | char *toName = NULL; | ||
39 | struct cifs_sb_info *cifs_sb_target; | ||
40 | struct cifsTconInfo *pTcon; | ||
41 | struct cifsInodeInfo *cifsInode; | ||
42 | |||
43 | xid = GetXid(); | ||
44 | |||
45 | cifs_sb_target = CIFS_SB(inode->i_sb); | ||
46 | pTcon = cifs_sb_target->tcon; | ||
47 | |||
48 | /* No need to check for cross device links since server will do that | ||
49 | BB note DFS case in future though (when we may have to check) */ | ||
50 | |||
51 | down(&inode->i_sb->s_vfs_rename_sem); | ||
52 | fromName = build_path_from_dentry(old_file); | ||
53 | toName = build_path_from_dentry(direntry); | ||
54 | up(&inode->i_sb->s_vfs_rename_sem); | ||
55 | if((fromName == NULL) || (toName == NULL)) { | ||
56 | rc = -ENOMEM; | ||
57 | goto cifs_hl_exit; | ||
58 | } | ||
59 | |||
60 | if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX) | ||
61 | rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, | ||
62 | cifs_sb_target->local_nls); | ||
63 | else { | ||
64 | rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, | ||
65 | cifs_sb_target->local_nls); | ||
66 | if(rc == -EIO) | ||
67 | rc = -EOPNOTSUPP; | ||
68 | } | ||
69 | |||
70 | /* if (!rc) */ | ||
71 | { | ||
72 | /* renew_parental_timestamps(old_file); | ||
73 | inode->i_nlink++; | ||
74 | mark_inode_dirty(inode); | ||
75 | d_instantiate(direntry, inode); */ | ||
76 | /* BB add call to either mark inode dirty or refresh its data and timestamp to current time */ | ||
77 | } | ||
78 | d_drop(direntry); /* force new lookup from server */ | ||
79 | cifsInode = CIFS_I(old_file->d_inode); | ||
80 | cifsInode->time = 0; /* will force revalidate to go get info when needed */ | ||
81 | |||
82 | cifs_hl_exit: | ||
83 | if (fromName) | ||
84 | kfree(fromName); | ||
85 | if (toName) | ||
86 | kfree(toName); | ||
87 | FreeXid(xid); | ||
88 | return rc; | ||
89 | } | ||
90 | |||
91 | int | ||
92 | cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | ||
93 | { | ||
94 | struct inode *inode = direntry->d_inode; | ||
95 | int rc = -EACCES; | ||
96 | int xid; | ||
97 | char *full_path = NULL; | ||
98 | char * target_path = ERR_PTR(-ENOMEM); | ||
99 | struct cifs_sb_info *cifs_sb; | ||
100 | struct cifsTconInfo *pTcon; | ||
101 | |||
102 | xid = GetXid(); | ||
103 | |||
104 | down(&direntry->d_sb->s_vfs_rename_sem); | ||
105 | full_path = build_path_from_dentry(direntry); | ||
106 | up(&direntry->d_sb->s_vfs_rename_sem); | ||
107 | |||
108 | if (!full_path) | ||
109 | goto out_no_free; | ||
110 | |||
111 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); | ||
112 | cifs_sb = CIFS_SB(inode->i_sb); | ||
113 | pTcon = cifs_sb->tcon; | ||
114 | target_path = kmalloc(PATH_MAX, GFP_KERNEL); | ||
115 | if (!target_path) { | ||
116 | target_path = ERR_PTR(-ENOMEM); | ||
117 | goto out; | ||
118 | } | ||
119 | |||
120 | /* BB add read reparse point symlink code and Unix extensions symlink code here BB */ | ||
121 | if (pTcon->ses->capabilities & CAP_UNIX) | ||
122 | rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, | ||
123 | target_path, | ||
124 | PATH_MAX-1, | ||
125 | cifs_sb->local_nls); | ||
126 | else { | ||
127 | /* rc = CIFSSMBQueryReparseLinkInfo */ | ||
128 | /* BB Add code to Query ReparsePoint info */ | ||
129 | /* BB Add MAC style xsymlink check here if enabled */ | ||
130 | } | ||
131 | |||
132 | if (rc == 0) { | ||
133 | |||
134 | /* BB Add special case check for Samba DFS symlinks */ | ||
135 | |||
136 | target_path[PATH_MAX-1] = 0; | ||
137 | } else { | ||
138 | kfree(target_path); | ||
139 | target_path = ERR_PTR(rc); | ||
140 | } | ||
141 | |||
142 | out: | ||
143 | kfree(full_path); | ||
144 | out_no_free: | ||
145 | FreeXid(xid); | ||
146 | nd_set_link(nd, target_path); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | int | ||
151 | cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | ||
152 | { | ||
153 | int rc = -EOPNOTSUPP; | ||
154 | int xid; | ||
155 | struct cifs_sb_info *cifs_sb; | ||
156 | struct cifsTconInfo *pTcon; | ||
157 | char *full_path = NULL; | ||
158 | struct inode *newinode = NULL; | ||
159 | |||
160 | xid = GetXid(); | ||
161 | |||
162 | cifs_sb = CIFS_SB(inode->i_sb); | ||
163 | pTcon = cifs_sb->tcon; | ||
164 | |||
165 | down(&inode->i_sb->s_vfs_rename_sem); | ||
166 | full_path = build_path_from_dentry(direntry); | ||
167 | up(&inode->i_sb->s_vfs_rename_sem); | ||
168 | |||
169 | if(full_path == NULL) { | ||
170 | FreeXid(xid); | ||
171 | return -ENOMEM; | ||
172 | } | ||
173 | |||
174 | cFYI(1, ("Full path: %s ", full_path)); | ||
175 | cFYI(1, ("symname is %s", symname)); | ||
176 | |||
177 | /* BB what if DFS and this volume is on different share? BB */ | ||
178 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) | ||
179 | rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, | ||
180 | cifs_sb->local_nls); | ||
181 | /* else | ||
182 | rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */ | ||
183 | |||
184 | if (rc == 0) { | ||
185 | if (pTcon->ses->capabilities & CAP_UNIX) | ||
186 | rc = cifs_get_inode_info_unix(&newinode, full_path, | ||
187 | inode->i_sb,xid); | ||
188 | else | ||
189 | rc = cifs_get_inode_info(&newinode, full_path, NULL, | ||
190 | inode->i_sb,xid); | ||
191 | |||
192 | if (rc != 0) { | ||
193 | cFYI(1, | ||
194 | ("Create symlink worked but get_inode_info failed with rc = %d ", | ||
195 | rc)); | ||
196 | } else { | ||
197 | direntry->d_op = &cifs_dentry_ops; | ||
198 | d_instantiate(direntry, newinode); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | if (full_path) | ||
203 | kfree(full_path); | ||
204 | FreeXid(xid); | ||
205 | return rc; | ||
206 | } | ||
207 | |||
208 | int | ||
209 | cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) | ||
210 | { | ||
211 | struct inode *inode = direntry->d_inode; | ||
212 | int rc = -EACCES; | ||
213 | int xid; | ||
214 | int oplock = FALSE; | ||
215 | struct cifs_sb_info *cifs_sb; | ||
216 | struct cifsTconInfo *pTcon; | ||
217 | char *full_path = NULL; | ||
218 | char *tmp_path = NULL; | ||
219 | char * tmpbuffer; | ||
220 | unsigned char * referrals = NULL; | ||
221 | int num_referrals = 0; | ||
222 | int len; | ||
223 | __u16 fid; | ||
224 | |||
225 | xid = GetXid(); | ||
226 | cifs_sb = CIFS_SB(inode->i_sb); | ||
227 | pTcon = cifs_sb->tcon; | ||
228 | |||
229 | /* BB would it be safe against deadlock to grab this sem | ||
230 | even though rename itself grabs the sem and calls lookup? */ | ||
231 | /* down(&inode->i_sb->s_vfs_rename_sem);*/ | ||
232 | full_path = build_path_from_dentry(direntry); | ||
233 | /* up(&inode->i_sb->s_vfs_rename_sem);*/ | ||
234 | |||
235 | if(full_path == NULL) { | ||
236 | FreeXid(xid); | ||
237 | return -ENOMEM; | ||
238 | } | ||
239 | |||
240 | cFYI(1, | ||
241 | ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d", | ||
242 | full_path, inode, pBuffer, buflen)); | ||
243 | if(buflen > PATH_MAX) | ||
244 | len = PATH_MAX; | ||
245 | else | ||
246 | len = buflen; | ||
247 | tmpbuffer = kmalloc(len,GFP_KERNEL); | ||
248 | if(tmpbuffer == NULL) { | ||
249 | if (full_path) | ||
250 | kfree(full_path); | ||
251 | FreeXid(xid); | ||
252 | return -ENOMEM; | ||
253 | } | ||
254 | |||
255 | /* BB add read reparse point symlink code and Unix extensions symlink code here BB */ | ||
256 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) | ||
257 | rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, | ||
258 | tmpbuffer, | ||
259 | len - 1, | ||
260 | cifs_sb->local_nls); | ||
261 | else { | ||
262 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, | ||
263 | OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls); | ||
264 | if(!rc) { | ||
265 | rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, | ||
266 | tmpbuffer, | ||
267 | len - 1, | ||
268 | fid, | ||
269 | cifs_sb->local_nls); | ||
270 | if(CIFSSMBClose(xid, pTcon, fid)) { | ||
271 | cFYI(1,("Error closing junction point (open for ioctl)")); | ||
272 | } | ||
273 | if(rc == -EIO) { | ||
274 | /* Query if DFS Junction */ | ||
275 | tmp_path = | ||
276 | kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1, | ||
277 | GFP_KERNEL); | ||
278 | if (tmp_path) { | ||
279 | strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); | ||
280 | strncat(tmp_path, full_path, MAX_PATHCONF); | ||
281 | rc = get_dfs_path(xid, pTcon->ses, tmp_path, | ||
282 | cifs_sb->local_nls, &num_referrals, &referrals); | ||
283 | cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc)); | ||
284 | if((num_referrals == 0) && (rc == 0)) | ||
285 | rc = -EACCES; | ||
286 | else { | ||
287 | cFYI(1,("num referral: %d",num_referrals)); | ||
288 | if(referrals) { | ||
289 | cFYI(1,("referral string: %s ",referrals)); | ||
290 | strncpy(tmpbuffer, referrals, len-1); | ||
291 | } | ||
292 | } | ||
293 | if(referrals) | ||
294 | kfree(referrals); | ||
295 | kfree(tmp_path); | ||
296 | } | ||
297 | /* BB add code like else decode referrals then memcpy to | ||
298 | tmpbuffer and free referrals string array BB */ | ||
299 | } | ||
300 | } | ||
301 | } | ||
302 | /* BB Anything else to do to handle recursive links? */ | ||
303 | /* BB Should we be using page ops here? */ | ||
304 | |||
305 | /* BB null terminate returned string in pBuffer? BB */ | ||
306 | if (rc == 0) { | ||
307 | rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer); | ||
308 | cFYI(1, | ||
309 | ("vfs_readlink called from cifs_readlink returned %d", | ||
310 | rc)); | ||
311 | } | ||
312 | |||
313 | if (tmpbuffer) { | ||
314 | kfree(tmpbuffer); | ||
315 | } | ||
316 | if (full_path) { | ||
317 | kfree(full_path); | ||
318 | } | ||
319 | FreeXid(xid); | ||
320 | return rc; | ||
321 | } | ||
322 | |||
323 | void cifs_put_link(struct dentry *direntry, struct nameidata *nd) | ||
324 | { | ||
325 | char *p = nd_get_link(nd); | ||
326 | if (!IS_ERR(p)) | ||
327 | kfree(p); | ||
328 | } | ||
diff --git a/fs/cifs/md4.c b/fs/cifs/md4.c new file mode 100644 index 000000000000..46d62c9dda0f --- /dev/null +++ b/fs/cifs/md4.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | Unix SMB/Netbios implementation. | ||
3 | Version 1.9. | ||
4 | a implementation of MD4 designed for use in the SMB authentication protocol | ||
5 | Copyright (C) Andrew Tridgell 1997-1998. | ||
6 | Modified by Steve French (sfrench@us.ibm.com) 2002-2003 | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include "cifsencrypt.h" | ||
25 | |||
26 | /* NOTE: This code makes no attempt to be fast! */ | ||
27 | |||
28 | static __u32 | ||
29 | F(__u32 X, __u32 Y, __u32 Z) | ||
30 | { | ||
31 | return (X & Y) | ((~X) & Z); | ||
32 | } | ||
33 | |||
34 | static __u32 | ||
35 | G(__u32 X, __u32 Y, __u32 Z) | ||
36 | { | ||
37 | return (X & Y) | (X & Z) | (Y & Z); | ||
38 | } | ||
39 | |||
40 | static __u32 | ||
41 | H(__u32 X, __u32 Y, __u32 Z) | ||
42 | { | ||
43 | return X ^ Y ^ Z; | ||
44 | } | ||
45 | |||
46 | static __u32 | ||
47 | lshift(__u32 x, int s) | ||
48 | { | ||
49 | x &= 0xFFFFFFFF; | ||
50 | return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); | ||
51 | } | ||
52 | |||
53 | #define ROUND1(a,b,c,d,k,s) (*a) = lshift((*a) + F(*b,*c,*d) + X[k], s) | ||
54 | #define ROUND2(a,b,c,d,k,s) (*a) = lshift((*a) + G(*b,*c,*d) + X[k] + (__u32)0x5A827999,s) | ||
55 | #define ROUND3(a,b,c,d,k,s) (*a) = lshift((*a) + H(*b,*c,*d) + X[k] + (__u32)0x6ED9EBA1,s) | ||
56 | |||
57 | /* this applies md4 to 64 byte chunks */ | ||
58 | static void | ||
59 | mdfour64(__u32 * M, __u32 * A, __u32 *B, __u32 * C, __u32 *D) | ||
60 | { | ||
61 | int j; | ||
62 | __u32 AA, BB, CC, DD; | ||
63 | __u32 X[16]; | ||
64 | |||
65 | |||
66 | for (j = 0; j < 16; j++) | ||
67 | X[j] = M[j]; | ||
68 | |||
69 | AA = *A; | ||
70 | BB = *B; | ||
71 | CC = *C; | ||
72 | DD = *D; | ||
73 | |||
74 | ROUND1(A, B, C, D, 0, 3); | ||
75 | ROUND1(D, A, B, C, 1, 7); | ||
76 | ROUND1(C, D, A, B, 2, 11); | ||
77 | ROUND1(B, C, D, A, 3, 19); | ||
78 | ROUND1(A, B, C, D, 4, 3); | ||
79 | ROUND1(D, A, B, C, 5, 7); | ||
80 | ROUND1(C, D, A, B, 6, 11); | ||
81 | ROUND1(B, C, D, A, 7, 19); | ||
82 | ROUND1(A, B, C, D, 8, 3); | ||
83 | ROUND1(D, A, B, C, 9, 7); | ||
84 | ROUND1(C, D, A, B, 10, 11); | ||
85 | ROUND1(B, C, D, A, 11, 19); | ||
86 | ROUND1(A, B, C, D, 12, 3); | ||
87 | ROUND1(D, A, B, C, 13, 7); | ||
88 | ROUND1(C, D, A, B, 14, 11); | ||
89 | ROUND1(B, C, D, A, 15, 19); | ||
90 | |||
91 | ROUND2(A, B, C, D, 0, 3); | ||
92 | ROUND2(D, A, B, C, 4, 5); | ||
93 | ROUND2(C, D, A, B, 8, 9); | ||
94 | ROUND2(B, C, D, A, 12, 13); | ||
95 | ROUND2(A, B, C, D, 1, 3); | ||
96 | ROUND2(D, A, B, C, 5, 5); | ||
97 | ROUND2(C, D, A, B, 9, 9); | ||
98 | ROUND2(B, C, D, A, 13, 13); | ||
99 | ROUND2(A, B, C, D, 2, 3); | ||
100 | ROUND2(D, A, B, C, 6, 5); | ||
101 | ROUND2(C, D, A, B, 10, 9); | ||
102 | ROUND2(B, C, D, A, 14, 13); | ||
103 | ROUND2(A, B, C, D, 3, 3); | ||
104 | ROUND2(D, A, B, C, 7, 5); | ||
105 | ROUND2(C, D, A, B, 11, 9); | ||
106 | ROUND2(B, C, D, A, 15, 13); | ||
107 | |||
108 | ROUND3(A, B, C, D, 0, 3); | ||
109 | ROUND3(D, A, B, C, 8, 9); | ||
110 | ROUND3(C, D, A, B, 4, 11); | ||
111 | ROUND3(B, C, D, A, 12, 15); | ||
112 | ROUND3(A, B, C, D, 2, 3); | ||
113 | ROUND3(D, A, B, C, 10, 9); | ||
114 | ROUND3(C, D, A, B, 6, 11); | ||
115 | ROUND3(B, C, D, A, 14, 15); | ||
116 | ROUND3(A, B, C, D, 1, 3); | ||
117 | ROUND3(D, A, B, C, 9, 9); | ||
118 | ROUND3(C, D, A, B, 5, 11); | ||
119 | ROUND3(B, C, D, A, 13, 15); | ||
120 | ROUND3(A, B, C, D, 3, 3); | ||
121 | ROUND3(D, A, B, C, 11, 9); | ||
122 | ROUND3(C, D, A, B, 7, 11); | ||
123 | ROUND3(B, C, D, A, 15, 15); | ||
124 | |||
125 | *A += AA; | ||
126 | *B += BB; | ||
127 | *C += CC; | ||
128 | *D += DD; | ||
129 | |||
130 | *A &= 0xFFFFFFFF; | ||
131 | *B &= 0xFFFFFFFF; | ||
132 | *C &= 0xFFFFFFFF; | ||
133 | *D &= 0xFFFFFFFF; | ||
134 | |||
135 | for (j = 0; j < 16; j++) | ||
136 | X[j] = 0; | ||
137 | } | ||
138 | |||
139 | static void | ||
140 | copy64(__u32 * M, unsigned char *in) | ||
141 | { | ||
142 | int i; | ||
143 | |||
144 | for (i = 0; i < 16; i++) | ||
145 | M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) | | ||
146 | (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0); | ||
147 | } | ||
148 | |||
149 | static void | ||
150 | copy4(unsigned char *out, __u32 x) | ||
151 | { | ||
152 | out[0] = x & 0xFF; | ||
153 | out[1] = (x >> 8) & 0xFF; | ||
154 | out[2] = (x >> 16) & 0xFF; | ||
155 | out[3] = (x >> 24) & 0xFF; | ||
156 | } | ||
157 | |||
158 | /* produce a md4 message digest from data of length n bytes */ | ||
159 | void | ||
160 | mdfour(unsigned char *out, unsigned char *in, int n) | ||
161 | { | ||
162 | unsigned char buf[128]; | ||
163 | __u32 M[16]; | ||
164 | __u32 b = n * 8; | ||
165 | int i; | ||
166 | __u32 A = 0x67452301; | ||
167 | __u32 B = 0xefcdab89; | ||
168 | __u32 C = 0x98badcfe; | ||
169 | __u32 D = 0x10325476; | ||
170 | |||
171 | while (n > 64) { | ||
172 | copy64(M, in); | ||
173 | mdfour64(M,&A,&B, &C, &D); | ||
174 | in += 64; | ||
175 | n -= 64; | ||
176 | } | ||
177 | |||
178 | for (i = 0; i < 128; i++) | ||
179 | buf[i] = 0; | ||
180 | memcpy(buf, in, n); | ||
181 | buf[n] = 0x80; | ||
182 | |||
183 | if (n <= 55) { | ||
184 | copy4(buf + 56, b); | ||
185 | copy64(M, buf); | ||
186 | mdfour64(M, &A, &B, &C, &D); | ||
187 | } else { | ||
188 | copy4(buf + 120, b); | ||
189 | copy64(M, buf); | ||
190 | mdfour64(M, &A, &B, &C, &D); | ||
191 | copy64(M, buf + 64); | ||
192 | mdfour64(M, &A, &B, &C, &D); | ||
193 | } | ||
194 | |||
195 | for (i = 0; i < 128; i++) | ||
196 | buf[i] = 0; | ||
197 | copy64(M, buf); | ||
198 | |||
199 | copy4(out, A); | ||
200 | copy4(out + 4, B); | ||
201 | copy4(out + 8, C); | ||
202 | copy4(out + 12, D); | ||
203 | |||
204 | A = B = C = D = 0; | ||
205 | } | ||
diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c new file mode 100644 index 000000000000..7aa23490541f --- /dev/null +++ b/fs/cifs/md5.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * This code implements the MD5 message-digest algorithm. | ||
3 | * The algorithm is due to Ron Rivest. This code was | ||
4 | * written by Colin Plumb in 1993, no copyright is claimed. | ||
5 | * This code is in the public domain; do with it what you wish. | ||
6 | * | ||
7 | * Equivalent code is available from RSA Data Security, Inc. | ||
8 | * This code has been tested against that, and is equivalent, | ||
9 | * except that you don't need to include two pages of legalese | ||
10 | * with every copy. | ||
11 | * | ||
12 | * To compute the message digest of a chunk of bytes, declare an | ||
13 | * MD5Context structure, pass it to MD5Init, call MD5Update as | ||
14 | * needed on buffers full of bytes, and then call MD5Final, which | ||
15 | * will fill a supplied 16-byte array with the digest. | ||
16 | */ | ||
17 | |||
18 | /* This code slightly modified to fit into Samba by | ||
19 | abartlet@samba.org Jun 2001 | ||
20 | and to fit the cifs vfs by | ||
21 | Steve French sfrench@us.ibm.com */ | ||
22 | |||
23 | #include <linux/string.h> | ||
24 | #include "md5.h" | ||
25 | |||
26 | static void MD5Transform(__u32 buf[4], __u32 const in[16]); | ||
27 | |||
28 | /* | ||
29 | * Note: this code is harmless on little-endian machines. | ||
30 | */ | ||
31 | static void | ||
32 | byteReverse(unsigned char *buf, unsigned longs) | ||
33 | { | ||
34 | __u32 t; | ||
35 | do { | ||
36 | t = (__u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | | ||
37 | ((unsigned) buf[1] << 8 | buf[0]); | ||
38 | *(__u32 *) buf = t; | ||
39 | buf += 4; | ||
40 | } while (--longs); | ||
41 | } | ||
42 | |||
43 | /* | ||
44 | * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious | ||
45 | * initialization constants. | ||
46 | */ | ||
47 | void | ||
48 | MD5Init(struct MD5Context *ctx) | ||
49 | { | ||
50 | ctx->buf[0] = 0x67452301; | ||
51 | ctx->buf[1] = 0xefcdab89; | ||
52 | ctx->buf[2] = 0x98badcfe; | ||
53 | ctx->buf[3] = 0x10325476; | ||
54 | |||
55 | ctx->bits[0] = 0; | ||
56 | ctx->bits[1] = 0; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Update context to reflect the concatenation of another buffer full | ||
61 | * of bytes. | ||
62 | */ | ||
63 | void | ||
64 | MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) | ||
65 | { | ||
66 | register __u32 t; | ||
67 | |||
68 | /* Update bitcount */ | ||
69 | |||
70 | t = ctx->bits[0]; | ||
71 | if ((ctx->bits[0] = t + ((__u32) len << 3)) < t) | ||
72 | ctx->bits[1]++; /* Carry from low to high */ | ||
73 | ctx->bits[1] += len >> 29; | ||
74 | |||
75 | t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ | ||
76 | |||
77 | /* Handle any leading odd-sized chunks */ | ||
78 | |||
79 | if (t) { | ||
80 | unsigned char *p = (unsigned char *) ctx->in + t; | ||
81 | |||
82 | t = 64 - t; | ||
83 | if (len < t) { | ||
84 | memmove(p, buf, len); | ||
85 | return; | ||
86 | } | ||
87 | memmove(p, buf, t); | ||
88 | byteReverse(ctx->in, 16); | ||
89 | MD5Transform(ctx->buf, (__u32 *) ctx->in); | ||
90 | buf += t; | ||
91 | len -= t; | ||
92 | } | ||
93 | /* Process data in 64-byte chunks */ | ||
94 | |||
95 | while (len >= 64) { | ||
96 | memmove(ctx->in, buf, 64); | ||
97 | byteReverse(ctx->in, 16); | ||
98 | MD5Transform(ctx->buf, (__u32 *) ctx->in); | ||
99 | buf += 64; | ||
100 | len -= 64; | ||
101 | } | ||
102 | |||
103 | /* Handle any remaining bytes of data. */ | ||
104 | |||
105 | memmove(ctx->in, buf, len); | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * Final wrapup - pad to 64-byte boundary with the bit pattern | ||
110 | * 1 0* (64-bit count of bits processed, MSB-first) | ||
111 | */ | ||
112 | void | ||
113 | MD5Final(unsigned char digest[16], struct MD5Context *ctx) | ||
114 | { | ||
115 | unsigned int count; | ||
116 | unsigned char *p; | ||
117 | |||
118 | /* Compute number of bytes mod 64 */ | ||
119 | count = (ctx->bits[0] >> 3) & 0x3F; | ||
120 | |||
121 | /* Set the first char of padding to 0x80. This is safe since there is | ||
122 | always at least one byte free */ | ||
123 | p = ctx->in + count; | ||
124 | *p++ = 0x80; | ||
125 | |||
126 | /* Bytes of padding needed to make 64 bytes */ | ||
127 | count = 64 - 1 - count; | ||
128 | |||
129 | /* Pad out to 56 mod 64 */ | ||
130 | if (count < 8) { | ||
131 | /* Two lots of padding: Pad the first block to 64 bytes */ | ||
132 | memset(p, 0, count); | ||
133 | byteReverse(ctx->in, 16); | ||
134 | MD5Transform(ctx->buf, (__u32 *) ctx->in); | ||
135 | |||
136 | /* Now fill the next block with 56 bytes */ | ||
137 | memset(ctx->in, 0, 56); | ||
138 | } else { | ||
139 | /* Pad block to 56 bytes */ | ||
140 | memset(p, 0, count - 8); | ||
141 | } | ||
142 | byteReverse(ctx->in, 14); | ||
143 | |||
144 | /* Append length in bits and transform */ | ||
145 | ((__u32 *) ctx->in)[14] = ctx->bits[0]; | ||
146 | ((__u32 *) ctx->in)[15] = ctx->bits[1]; | ||
147 | |||
148 | MD5Transform(ctx->buf, (__u32 *) ctx->in); | ||
149 | byteReverse((unsigned char *) ctx->buf, 4); | ||
150 | memmove(digest, ctx->buf, 16); | ||
151 | memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ | ||
152 | } | ||
153 | |||
154 | /* The four core functions - F1 is optimized somewhat */ | ||
155 | |||
156 | /* #define F1(x, y, z) (x & y | ~x & z) */ | ||
157 | #define F1(x, y, z) (z ^ (x & (y ^ z))) | ||
158 | #define F2(x, y, z) F1(z, x, y) | ||
159 | #define F3(x, y, z) (x ^ y ^ z) | ||
160 | #define F4(x, y, z) (y ^ (x | ~z)) | ||
161 | |||
162 | /* This is the central step in the MD5 algorithm. */ | ||
163 | #define MD5STEP(f, w, x, y, z, data, s) \ | ||
164 | ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) | ||
165 | |||
166 | /* | ||
167 | * The core of the MD5 algorithm, this alters an existing MD5 hash to | ||
168 | * reflect the addition of 16 longwords of new data. MD5Update blocks | ||
169 | * the data and converts bytes into longwords for this routine. | ||
170 | */ | ||
171 | static void | ||
172 | MD5Transform(__u32 buf[4], __u32 const in[16]) | ||
173 | { | ||
174 | register __u32 a, b, c, d; | ||
175 | |||
176 | a = buf[0]; | ||
177 | b = buf[1]; | ||
178 | c = buf[2]; | ||
179 | d = buf[3]; | ||
180 | |||
181 | MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); | ||
182 | MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); | ||
183 | MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); | ||
184 | MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); | ||
185 | MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); | ||
186 | MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); | ||
187 | MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); | ||
188 | MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); | ||
189 | MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); | ||
190 | MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); | ||
191 | MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); | ||
192 | MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); | ||
193 | MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); | ||
194 | MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); | ||
195 | MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); | ||
196 | MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); | ||
197 | |||
198 | MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); | ||
199 | MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); | ||
200 | MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); | ||
201 | MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); | ||
202 | MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); | ||
203 | MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); | ||
204 | MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); | ||
205 | MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); | ||
206 | MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); | ||
207 | MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); | ||
208 | MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); | ||
209 | MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); | ||
210 | MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); | ||
211 | MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); | ||
212 | MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); | ||
213 | MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); | ||
214 | |||
215 | MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); | ||
216 | MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); | ||
217 | MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); | ||
218 | MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); | ||
219 | MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); | ||
220 | MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); | ||
221 | MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); | ||
222 | MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); | ||
223 | MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); | ||
224 | MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); | ||
225 | MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); | ||
226 | MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); | ||
227 | MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); | ||
228 | MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); | ||
229 | MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); | ||
230 | MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); | ||
231 | |||
232 | MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); | ||
233 | MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); | ||
234 | MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); | ||
235 | MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); | ||
236 | MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); | ||
237 | MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); | ||
238 | MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); | ||
239 | MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); | ||
240 | MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); | ||
241 | MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); | ||
242 | MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); | ||
243 | MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); | ||
244 | MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); | ||
245 | MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); | ||
246 | MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); | ||
247 | MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); | ||
248 | |||
249 | buf[0] += a; | ||
250 | buf[1] += b; | ||
251 | buf[2] += c; | ||
252 | buf[3] += d; | ||
253 | } | ||
254 | |||
255 | /*********************************************************************** | ||
256 | the rfc 2104 version of hmac_md5 initialisation. | ||
257 | ***********************************************************************/ | ||
258 | void | ||
259 | hmac_md5_init_rfc2104(unsigned char *key, int key_len, | ||
260 | struct HMACMD5Context *ctx) | ||
261 | { | ||
262 | int i; | ||
263 | |||
264 | /* if key is longer than 64 bytes reset it to key=MD5(key) */ | ||
265 | if (key_len > 64) { | ||
266 | unsigned char tk[16]; | ||
267 | struct MD5Context tctx; | ||
268 | |||
269 | MD5Init(&tctx); | ||
270 | MD5Update(&tctx, key, key_len); | ||
271 | MD5Final(tk, &tctx); | ||
272 | |||
273 | key = tk; | ||
274 | key_len = 16; | ||
275 | } | ||
276 | |||
277 | /* start out by storing key in pads */ | ||
278 | memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad)); | ||
279 | memset(ctx->k_opad, 0, sizeof (ctx->k_opad)); | ||
280 | memcpy(ctx->k_ipad, key, key_len); | ||
281 | memcpy(ctx->k_opad, key, key_len); | ||
282 | |||
283 | /* XOR key with ipad and opad values */ | ||
284 | for (i = 0; i < 64; i++) { | ||
285 | ctx->k_ipad[i] ^= 0x36; | ||
286 | ctx->k_opad[i] ^= 0x5c; | ||
287 | } | ||
288 | |||
289 | MD5Init(&ctx->ctx); | ||
290 | MD5Update(&ctx->ctx, ctx->k_ipad, 64); | ||
291 | } | ||
292 | |||
293 | /*********************************************************************** | ||
294 | the microsoft version of hmac_md5 initialisation. | ||
295 | ***********************************************************************/ | ||
296 | void | ||
297 | hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, | ||
298 | struct HMACMD5Context *ctx) | ||
299 | { | ||
300 | int i; | ||
301 | |||
302 | /* if key is longer than 64 bytes truncate it */ | ||
303 | if (key_len > 64) { | ||
304 | key_len = 64; | ||
305 | } | ||
306 | |||
307 | /* start out by storing key in pads */ | ||
308 | memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad)); | ||
309 | memset(ctx->k_opad, 0, sizeof (ctx->k_opad)); | ||
310 | memcpy(ctx->k_ipad, key, key_len); | ||
311 | memcpy(ctx->k_opad, key, key_len); | ||
312 | |||
313 | /* XOR key with ipad and opad values */ | ||
314 | for (i = 0; i < 64; i++) { | ||
315 | ctx->k_ipad[i] ^= 0x36; | ||
316 | ctx->k_opad[i] ^= 0x5c; | ||
317 | } | ||
318 | |||
319 | MD5Init(&ctx->ctx); | ||
320 | MD5Update(&ctx->ctx, ctx->k_ipad, 64); | ||
321 | } | ||
322 | |||
323 | /*********************************************************************** | ||
324 | update hmac_md5 "inner" buffer | ||
325 | ***********************************************************************/ | ||
326 | void | ||
327 | hmac_md5_update(const unsigned char *text, int text_len, | ||
328 | struct HMACMD5Context *ctx) | ||
329 | { | ||
330 | MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */ | ||
331 | } | ||
332 | |||
333 | /*********************************************************************** | ||
334 | finish off hmac_md5 "inner" buffer and generate outer one. | ||
335 | ***********************************************************************/ | ||
336 | void | ||
337 | hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) | ||
338 | { | ||
339 | struct MD5Context ctx_o; | ||
340 | |||
341 | MD5Final(digest, &ctx->ctx); | ||
342 | |||
343 | MD5Init(&ctx_o); | ||
344 | MD5Update(&ctx_o, ctx->k_opad, 64); | ||
345 | MD5Update(&ctx_o, digest, 16); | ||
346 | MD5Final(digest, &ctx_o); | ||
347 | } | ||
348 | |||
349 | /*********************************************************** | ||
350 | single function to calculate an HMAC MD5 digest from data. | ||
351 | use the microsoft hmacmd5 init method because the key is 16 bytes. | ||
352 | ************************************************************/ | ||
353 | void | ||
354 | hmac_md5(unsigned char key[16], unsigned char *data, int data_len, | ||
355 | unsigned char *digest) | ||
356 | { | ||
357 | struct HMACMD5Context ctx; | ||
358 | hmac_md5_init_limK_to_64(key, 16, &ctx); | ||
359 | if (data_len != 0) { | ||
360 | hmac_md5_update(data, data_len, &ctx); | ||
361 | } | ||
362 | hmac_md5_final(digest, &ctx); | ||
363 | } | ||
diff --git a/fs/cifs/md5.h b/fs/cifs/md5.h new file mode 100644 index 000000000000..00e1c5394fe1 --- /dev/null +++ b/fs/cifs/md5.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef MD5_H | ||
2 | #define MD5_H | ||
3 | #ifndef HEADER_MD5_H | ||
4 | /* Try to avoid clashes with OpenSSL */ | ||
5 | #define HEADER_MD5_H | ||
6 | #endif | ||
7 | |||
8 | struct MD5Context { | ||
9 | __u32 buf[4]; | ||
10 | __u32 bits[2]; | ||
11 | unsigned char in[64]; | ||
12 | }; | ||
13 | #endif /* !MD5_H */ | ||
14 | |||
15 | #ifndef _HMAC_MD5_H | ||
16 | struct HMACMD5Context { | ||
17 | struct MD5Context ctx; | ||
18 | unsigned char k_ipad[65]; | ||
19 | unsigned char k_opad[65]; | ||
20 | }; | ||
21 | #endif /* _HMAC_MD5_H */ | ||
22 | |||
23 | void MD5Init(struct MD5Context *context); | ||
24 | void MD5Update(struct MD5Context *context, unsigned char const *buf, | ||
25 | unsigned len); | ||
26 | void MD5Final(unsigned char digest[16], struct MD5Context *context); | ||
27 | |||
28 | /* The following definitions come from lib/hmacmd5.c */ | ||
29 | |||
30 | void hmac_md5_init_rfc2104(unsigned char *key, int key_len, | ||
31 | struct HMACMD5Context *ctx); | ||
32 | void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, | ||
33 | struct HMACMD5Context *ctx); | ||
34 | void hmac_md5_update(const unsigned char *text, int text_len, | ||
35 | struct HMACMD5Context *ctx); | ||
36 | void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx); | ||
37 | void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, | ||
38 | unsigned char *digest); | ||
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c new file mode 100644 index 000000000000..7b38d3059a83 --- /dev/null +++ b/fs/cifs/misc.c | |||
@@ -0,0 +1,516 @@ | |||
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 | |||
22 | #include <linux/slab.h> | ||
23 | #include <linux/ctype.h> | ||
24 | #include <linux/mempool.h> | ||
25 | #include "cifspdu.h" | ||
26 | #include "cifsglob.h" | ||
27 | #include "cifsproto.h" | ||
28 | #include "cifs_debug.h" | ||
29 | #include "smberr.h" | ||
30 | #include "nterr.h" | ||
31 | |||
32 | extern mempool_t *cifs_sm_req_poolp; | ||
33 | extern mempool_t *cifs_req_poolp; | ||
34 | extern struct task_struct * oplockThread; | ||
35 | |||
36 | static __u16 GlobalMid; /* multiplex id - rotating counter */ | ||
37 | |||
38 | /* The xid serves as a useful identifier for each incoming vfs request, | ||
39 | in a similar way to the mid which is useful to track each sent smb, | ||
40 | and CurrentXid can also provide a running counter (although it | ||
41 | will eventually wrap past zero) of the total vfs operations handled | ||
42 | since the cifs fs was mounted */ | ||
43 | |||
44 | unsigned int | ||
45 | _GetXid(void) | ||
46 | { | ||
47 | unsigned int xid; | ||
48 | |||
49 | spin_lock(&GlobalMid_Lock); | ||
50 | GlobalTotalActiveXid++; | ||
51 | if (GlobalTotalActiveXid > GlobalMaxActiveXid) | ||
52 | GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ | ||
53 | xid = GlobalCurrentXid++; | ||
54 | spin_unlock(&GlobalMid_Lock); | ||
55 | return xid; | ||
56 | } | ||
57 | |||
58 | void | ||
59 | _FreeXid(unsigned int xid) | ||
60 | { | ||
61 | spin_lock(&GlobalMid_Lock); | ||
62 | /* if(GlobalTotalActiveXid == 0) | ||
63 | BUG(); */ | ||
64 | GlobalTotalActiveXid--; | ||
65 | spin_unlock(&GlobalMid_Lock); | ||
66 | } | ||
67 | |||
68 | struct cifsSesInfo * | ||
69 | sesInfoAlloc(void) | ||
70 | { | ||
71 | struct cifsSesInfo *ret_buf; | ||
72 | |||
73 | ret_buf = | ||
74 | (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo), | ||
75 | GFP_KERNEL); | ||
76 | if (ret_buf) { | ||
77 | memset(ret_buf, 0, sizeof (struct cifsSesInfo)); | ||
78 | write_lock(&GlobalSMBSeslock); | ||
79 | atomic_inc(&sesInfoAllocCount); | ||
80 | ret_buf->status = CifsNew; | ||
81 | list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList); | ||
82 | init_MUTEX(&ret_buf->sesSem); | ||
83 | write_unlock(&GlobalSMBSeslock); | ||
84 | } | ||
85 | return ret_buf; | ||
86 | } | ||
87 | |||
88 | void | ||
89 | sesInfoFree(struct cifsSesInfo *buf_to_free) | ||
90 | { | ||
91 | if (buf_to_free == NULL) { | ||
92 | cFYI(1, ("Null buffer passed to sesInfoFree")); | ||
93 | return; | ||
94 | } | ||
95 | |||
96 | write_lock(&GlobalSMBSeslock); | ||
97 | atomic_dec(&sesInfoAllocCount); | ||
98 | list_del(&buf_to_free->cifsSessionList); | ||
99 | write_unlock(&GlobalSMBSeslock); | ||
100 | if (buf_to_free->serverOS) | ||
101 | kfree(buf_to_free->serverOS); | ||
102 | if (buf_to_free->serverDomain) | ||
103 | kfree(buf_to_free->serverDomain); | ||
104 | if (buf_to_free->serverNOS) | ||
105 | kfree(buf_to_free->serverNOS); | ||
106 | if (buf_to_free->password) | ||
107 | kfree(buf_to_free->password); | ||
108 | kfree(buf_to_free); | ||
109 | } | ||
110 | |||
111 | struct cifsTconInfo * | ||
112 | tconInfoAlloc(void) | ||
113 | { | ||
114 | struct cifsTconInfo *ret_buf; | ||
115 | ret_buf = | ||
116 | (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo), | ||
117 | GFP_KERNEL); | ||
118 | if (ret_buf) { | ||
119 | memset(ret_buf, 0, sizeof (struct cifsTconInfo)); | ||
120 | write_lock(&GlobalSMBSeslock); | ||
121 | atomic_inc(&tconInfoAllocCount); | ||
122 | list_add(&ret_buf->cifsConnectionList, | ||
123 | &GlobalTreeConnectionList); | ||
124 | ret_buf->tidStatus = CifsNew; | ||
125 | INIT_LIST_HEAD(&ret_buf->openFileList); | ||
126 | init_MUTEX(&ret_buf->tconSem); | ||
127 | #ifdef CONFIG_CIFS_STATS | ||
128 | spin_lock_init(&ret_buf->stat_lock); | ||
129 | #endif | ||
130 | write_unlock(&GlobalSMBSeslock); | ||
131 | } | ||
132 | return ret_buf; | ||
133 | } | ||
134 | |||
135 | void | ||
136 | tconInfoFree(struct cifsTconInfo *buf_to_free) | ||
137 | { | ||
138 | if (buf_to_free == NULL) { | ||
139 | cFYI(1, ("Null buffer passed to tconInfoFree")); | ||
140 | return; | ||
141 | } | ||
142 | write_lock(&GlobalSMBSeslock); | ||
143 | atomic_dec(&tconInfoAllocCount); | ||
144 | list_del(&buf_to_free->cifsConnectionList); | ||
145 | write_unlock(&GlobalSMBSeslock); | ||
146 | if (buf_to_free->nativeFileSystem) | ||
147 | kfree(buf_to_free->nativeFileSystem); | ||
148 | kfree(buf_to_free); | ||
149 | } | ||
150 | |||
151 | struct smb_hdr * | ||
152 | cifs_buf_get(void) | ||
153 | { | ||
154 | struct smb_hdr *ret_buf = NULL; | ||
155 | |||
156 | /* We could use negotiated size instead of max_msgsize - | ||
157 | but it may be more efficient to always alloc same size | ||
158 | albeit slightly larger than necessary and maxbuffersize | ||
159 | defaults to this and can not be bigger */ | ||
160 | ret_buf = | ||
161 | (struct smb_hdr *) mempool_alloc(cifs_req_poolp, SLAB_KERNEL | SLAB_NOFS); | ||
162 | |||
163 | /* clear the first few header bytes */ | ||
164 | /* for most paths, more is cleared in header_assemble */ | ||
165 | if (ret_buf) { | ||
166 | memset(ret_buf, 0, sizeof(struct smb_hdr) + 3); | ||
167 | atomic_inc(&bufAllocCount); | ||
168 | } | ||
169 | |||
170 | return ret_buf; | ||
171 | } | ||
172 | |||
173 | void | ||
174 | cifs_buf_release(void *buf_to_free) | ||
175 | { | ||
176 | |||
177 | if (buf_to_free == NULL) { | ||
178 | /* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/ | ||
179 | return; | ||
180 | } | ||
181 | mempool_free(buf_to_free,cifs_req_poolp); | ||
182 | |||
183 | atomic_dec(&bufAllocCount); | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | struct smb_hdr * | ||
188 | cifs_small_buf_get(void) | ||
189 | { | ||
190 | struct smb_hdr *ret_buf = NULL; | ||
191 | |||
192 | /* We could use negotiated size instead of max_msgsize - | ||
193 | but it may be more efficient to always alloc same size | ||
194 | albeit slightly larger than necessary and maxbuffersize | ||
195 | defaults to this and can not be bigger */ | ||
196 | ret_buf = | ||
197 | (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, SLAB_KERNEL | SLAB_NOFS); | ||
198 | if (ret_buf) { | ||
199 | /* No need to clear memory here, cleared in header assemble */ | ||
200 | /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/ | ||
201 | atomic_inc(&smBufAllocCount); | ||
202 | } | ||
203 | return ret_buf; | ||
204 | } | ||
205 | |||
206 | void | ||
207 | cifs_small_buf_release(void *buf_to_free) | ||
208 | { | ||
209 | |||
210 | if (buf_to_free == NULL) { | ||
211 | cFYI(1, ("Null buffer passed to cifs_small_buf_release")); | ||
212 | return; | ||
213 | } | ||
214 | mempool_free(buf_to_free,cifs_sm_req_poolp); | ||
215 | |||
216 | atomic_dec(&smBufAllocCount); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | void | ||
221 | header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | ||
222 | const struct cifsTconInfo *treeCon, int word_count | ||
223 | /* length of fixed section (word count) in two byte units */) | ||
224 | { | ||
225 | struct list_head* temp_item; | ||
226 | struct cifsSesInfo * ses; | ||
227 | char *temp = (char *) buffer; | ||
228 | |||
229 | memset(temp,0,MAX_CIFS_HDR_SIZE); | ||
230 | |||
231 | buffer->smb_buf_length = | ||
232 | (2 * word_count) + sizeof (struct smb_hdr) - | ||
233 | 4 /* RFC 1001 length field does not count */ + | ||
234 | 2 /* for bcc field itself */ ; | ||
235 | /* 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 */ | ||
236 | |||
237 | buffer->Protocol[0] = 0xFF; | ||
238 | buffer->Protocol[1] = 'S'; | ||
239 | buffer->Protocol[2] = 'M'; | ||
240 | buffer->Protocol[3] = 'B'; | ||
241 | buffer->Command = smb_command; | ||
242 | buffer->Flags = 0x00; /* case sensitive */ | ||
243 | buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES; | ||
244 | buffer->Pid = cpu_to_le16((__u16)current->tgid); | ||
245 | buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16)); | ||
246 | spin_lock(&GlobalMid_Lock); | ||
247 | GlobalMid++; | ||
248 | buffer->Mid = GlobalMid; | ||
249 | spin_unlock(&GlobalMid_Lock); | ||
250 | if (treeCon) { | ||
251 | buffer->Tid = treeCon->tid; | ||
252 | if (treeCon->ses) { | ||
253 | if (treeCon->ses->capabilities & CAP_UNICODE) | ||
254 | buffer->Flags2 |= SMBFLG2_UNICODE; | ||
255 | if (treeCon->ses->capabilities & CAP_STATUS32) { | ||
256 | buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
257 | } | ||
258 | |||
259 | buffer->Uid = treeCon->ses->Suid; /* always in LE format */ | ||
260 | if(multiuser_mount != 0) { | ||
261 | /* For the multiuser case, there are few obvious technically */ | ||
262 | /* possible mechanisms to match the local linux user (uid) */ | ||
263 | /* to a valid remote smb user (smb_uid): */ | ||
264 | /* 1) Query Winbind (or other local pam/nss daemon */ | ||
265 | /* for userid/password/logon_domain or credential */ | ||
266 | /* 2) Query Winbind for uid to sid to username mapping */ | ||
267 | /* and see if we have a matching password for existing*/ | ||
268 | /* session for that user perhas getting password by */ | ||
269 | /* adding a new pam_cifs module that stores passwords */ | ||
270 | /* so that the cifs vfs can get at that for all logged*/ | ||
271 | /* on users */ | ||
272 | /* 3) (Which is the mechanism we have chosen) */ | ||
273 | /* Search through sessions to the same server for a */ | ||
274 | /* a match on the uid that was passed in on mount */ | ||
275 | /* with the current processes uid (or euid?) and use */ | ||
276 | /* that smb uid. If no existing smb session for */ | ||
277 | /* that uid found, use the default smb session ie */ | ||
278 | /* the smb session for the volume mounted which is */ | ||
279 | /* the same as would be used if the multiuser mount */ | ||
280 | /* flag were disabled. */ | ||
281 | |||
282 | /* BB Add support for establishing new tCon and SMB Session */ | ||
283 | /* with userid/password pairs found on the smb session */ | ||
284 | /* for other target tcp/ip addresses BB */ | ||
285 | if(current->uid != treeCon->ses->linux_uid) { | ||
286 | cFYI(1,("Multiuser mode and UID did not match tcon uid ")); | ||
287 | read_lock(&GlobalSMBSeslock); | ||
288 | list_for_each(temp_item, &GlobalSMBSessionList) { | ||
289 | ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); | ||
290 | if(ses->linux_uid == current->uid) { | ||
291 | if(ses->server == treeCon->ses->server) { | ||
292 | cFYI(1,("found matching uid substitute right smb_uid")); | ||
293 | buffer->Uid = ses->Suid; | ||
294 | break; | ||
295 | } else { | ||
296 | /* BB eventually call cifs_setup_session here */ | ||
297 | cFYI(1,("local UID found but smb sess with this server does not exist")); | ||
298 | } | ||
299 | } | ||
300 | } | ||
301 | read_unlock(&GlobalSMBSeslock); | ||
302 | } | ||
303 | } | ||
304 | } | ||
305 | if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) | ||
306 | buffer->Flags2 |= SMBFLG2_DFS; | ||
307 | if((treeCon->ses) && (treeCon->ses->server)) | ||
308 | if(treeCon->ses->server->secMode & | ||
309 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
310 | buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
311 | } | ||
312 | |||
313 | /* endian conversion of flags is now done just before sending */ | ||
314 | buffer->WordCount = (char) word_count; | ||
315 | return; | ||
316 | } | ||
317 | |||
318 | int | ||
319 | checkSMBhdr(struct smb_hdr *smb, __u16 mid) | ||
320 | { | ||
321 | /* Make sure that this really is an SMB, that it is a response, | ||
322 | and that the message ids match */ | ||
323 | if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) && | ||
324 | (mid == smb->Mid)) { | ||
325 | if(smb->Flags & SMBFLG_RESPONSE) | ||
326 | return 0; | ||
327 | else { | ||
328 | /* only one valid case where server sends us request */ | ||
329 | if(smb->Command == SMB_COM_LOCKING_ANDX) | ||
330 | return 0; | ||
331 | else | ||
332 | cERROR(1, ("Rcvd Request not response ")); | ||
333 | } | ||
334 | } else { /* bad signature or mid */ | ||
335 | if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) | ||
336 | cERROR(1, | ||
337 | ("Bad protocol string signature header %x ", | ||
338 | *(unsigned int *) smb->Protocol)); | ||
339 | if (mid != smb->Mid) | ||
340 | cERROR(1, ("Mids do not match")); | ||
341 | } | ||
342 | cERROR(1, ("bad smb detected. The Mid=%d", smb->Mid)); | ||
343 | return 1; | ||
344 | } | ||
345 | |||
346 | int | ||
347 | checkSMB(struct smb_hdr *smb, __u16 mid, int length) | ||
348 | { | ||
349 | __u32 len = be32_to_cpu(smb->smb_buf_length); | ||
350 | cFYI(0, | ||
351 | ("Entering checkSMB with Length: %x, smb_buf_length: %x ", | ||
352 | length, len)); | ||
353 | if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || | ||
354 | (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { | ||
355 | if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { | ||
356 | if (((unsigned int)length >= | ||
357 | sizeof (struct smb_hdr) - 1) | ||
358 | && (smb->Status.CifsError != 0)) { | ||
359 | smb->WordCount = 0; | ||
360 | return 0; /* some error cases do not return wct and bcc */ | ||
361 | } else { | ||
362 | cERROR(1, ("Length less than smb header size")); | ||
363 | } | ||
364 | |||
365 | } | ||
366 | if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) | ||
367 | cERROR(1, | ||
368 | ("smb_buf_length greater than MaxBufSize")); | ||
369 | cERROR(1, | ||
370 | ("bad smb detected. Illegal length. The mid=%d", | ||
371 | smb->Mid)); | ||
372 | return 1; | ||
373 | } | ||
374 | |||
375 | if (checkSMBhdr(smb, mid)) | ||
376 | return 1; | ||
377 | |||
378 | if ((4 + len != smbCalcSize(smb)) | ||
379 | || (4 + len != (unsigned int)length)) { | ||
380 | return 0; | ||
381 | } else { | ||
382 | cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); | ||
383 | cERROR(1, | ||
384 | ("bad smb size detected. The Mid=%d", smb->Mid)); | ||
385 | return 1; | ||
386 | } | ||
387 | } | ||
388 | int | ||
389 | is_valid_oplock_break(struct smb_hdr *buf) | ||
390 | { | ||
391 | struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf; | ||
392 | struct list_head *tmp; | ||
393 | struct list_head *tmp1; | ||
394 | struct cifsTconInfo *tcon; | ||
395 | struct cifsFileInfo *netfile; | ||
396 | |||
397 | cFYI(1,("Checking for oplock break or dnotify response")); | ||
398 | if((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) && | ||
399 | (pSMB->hdr.Flags & SMBFLG_RESPONSE)) { | ||
400 | struct smb_com_transaction_change_notify_rsp * pSMBr = | ||
401 | (struct smb_com_transaction_change_notify_rsp *)buf; | ||
402 | struct file_notify_information * pnotify; | ||
403 | __u32 data_offset = 0; | ||
404 | if(pSMBr->ByteCount > sizeof(struct file_notify_information)) { | ||
405 | data_offset = le32_to_cpu(pSMBr->DataOffset); | ||
406 | |||
407 | pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol | ||
408 | + data_offset); | ||
409 | cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName, | ||
410 | pnotify->Action)); /* BB removeme BB */ | ||
411 | /* cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */ | ||
412 | return TRUE; | ||
413 | } | ||
414 | if(pSMBr->hdr.Status.CifsError) { | ||
415 | cFYI(1,("notify err 0x%d",pSMBr->hdr.Status.CifsError)); | ||
416 | return TRUE; | ||
417 | } | ||
418 | return FALSE; | ||
419 | } | ||
420 | if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) | ||
421 | return FALSE; | ||
422 | if(pSMB->hdr.Flags & SMBFLG_RESPONSE) { | ||
423 | /* no sense logging error on invalid handle on oplock | ||
424 | break - harmless race between close request and oplock | ||
425 | break response is expected from time to time writing out | ||
426 | large dirty files cached on the client */ | ||
427 | if ((NT_STATUS_INVALID_HANDLE) == | ||
428 | le32_to_cpu(pSMB->hdr.Status.CifsError)) { | ||
429 | cFYI(1,("invalid handle on oplock break")); | ||
430 | return TRUE; | ||
431 | } else if (ERRbadfid == | ||
432 | le16_to_cpu(pSMB->hdr.Status.DosError.Error)) { | ||
433 | return TRUE; | ||
434 | } else { | ||
435 | return FALSE; /* on valid oplock brk we get "request" */ | ||
436 | } | ||
437 | } | ||
438 | if(pSMB->hdr.WordCount != 8) | ||
439 | return FALSE; | ||
440 | |||
441 | cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel)); | ||
442 | if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) | ||
443 | return FALSE; | ||
444 | |||
445 | /* look up tcon based on tid & uid */ | ||
446 | read_lock(&GlobalSMBSeslock); | ||
447 | list_for_each(tmp, &GlobalTreeConnectionList) { | ||
448 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | ||
449 | if (tcon->tid == buf->Tid) { | ||
450 | #ifdef CONFIG_CIFS_STATS | ||
451 | atomic_inc(&tcon->num_oplock_brks); | ||
452 | #endif | ||
453 | list_for_each(tmp1,&tcon->openFileList){ | ||
454 | netfile = list_entry(tmp1,struct cifsFileInfo,tlist); | ||
455 | if(pSMB->Fid == netfile->netfid) { | ||
456 | struct cifsInodeInfo *pCifsInode; | ||
457 | read_unlock(&GlobalSMBSeslock); | ||
458 | cFYI(1,("Matching file id, processing oplock break")); | ||
459 | pCifsInode = | ||
460 | CIFS_I(netfile->pInode); | ||
461 | pCifsInode->clientCanCacheAll = FALSE; | ||
462 | if(pSMB->OplockLevel == 0) | ||
463 | pCifsInode->clientCanCacheRead = FALSE; | ||
464 | pCifsInode->oplockPending = TRUE; | ||
465 | AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon); | ||
466 | cFYI(1,("about to wake up oplock thd")); | ||
467 | wake_up_process(oplockThread); | ||
468 | return TRUE; | ||
469 | } | ||
470 | } | ||
471 | read_unlock(&GlobalSMBSeslock); | ||
472 | cFYI(1,("No matching file for oplock break on connection")); | ||
473 | return TRUE; | ||
474 | } | ||
475 | } | ||
476 | read_unlock(&GlobalSMBSeslock); | ||
477 | cFYI(1,("Can not process oplock break for non-existent connection")); | ||
478 | return TRUE; | ||
479 | } | ||
480 | |||
481 | void | ||
482 | dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) | ||
483 | { | ||
484 | int i, j; | ||
485 | char debug_line[17]; | ||
486 | unsigned char *buffer; | ||
487 | |||
488 | if (traceSMB == 0) | ||
489 | return; | ||
490 | |||
491 | buffer = (unsigned char *) smb_buf; | ||
492 | for (i = 0, j = 0; i < smb_buf_length; i++, j++) { | ||
493 | if (i % 8 == 0) { /* we have reached the beginning of line */ | ||
494 | printk(KERN_DEBUG "| "); | ||
495 | j = 0; | ||
496 | } | ||
497 | printk("%0#4x ", buffer[i]); | ||
498 | debug_line[2 * j] = ' '; | ||
499 | if (isprint(buffer[i])) | ||
500 | debug_line[1 + (2 * j)] = buffer[i]; | ||
501 | else | ||
502 | debug_line[1 + (2 * j)] = '_'; | ||
503 | |||
504 | if (i % 8 == 7) { /* we have reached end of line, time to print ascii */ | ||
505 | debug_line[16] = 0; | ||
506 | printk(" | %s\n", debug_line); | ||
507 | } | ||
508 | } | ||
509 | for (; j < 8; j++) { | ||
510 | printk(" "); | ||
511 | debug_line[2 * j] = ' '; | ||
512 | debug_line[1 + (2 * j)] = ' '; | ||
513 | } | ||
514 | printk( " | %s\n", debug_line); | ||
515 | return; | ||
516 | } | ||
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c new file mode 100644 index 000000000000..4e34c89cec5d --- /dev/null +++ b/fs/cifs/netmisc.c | |||
@@ -0,0 +1,904 @@ | |||
1 | /* | ||
2 | * fs/cifs/netmisc.c | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2002 | ||
5 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
6 | * | ||
7 | * Error mapping routines from Samba libsmb/errormap.c | ||
8 | * Copyright (C) Andrew Tridgell 2001 | ||
9 | * | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
19 | * the GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | */ | ||
25 | |||
26 | #include <linux/net.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/in.h> | ||
29 | #include <linux/ctype.h> | ||
30 | #include <linux/fs.h> | ||
31 | #include <asm/div64.h> | ||
32 | #include <asm/byteorder.h> | ||
33 | #include "cifsfs.h" | ||
34 | #include "cifspdu.h" | ||
35 | #include "cifsglob.h" | ||
36 | #include "cifsproto.h" | ||
37 | #include "smberr.h" | ||
38 | #include "cifs_debug.h" | ||
39 | #include "nterr.h" | ||
40 | |||
41 | struct smb_to_posix_error { | ||
42 | __u16 smb_err; | ||
43 | int posix_code; | ||
44 | }; | ||
45 | |||
46 | static const struct smb_to_posix_error mapping_table_ERRDOS[] = { | ||
47 | {ERRbadfunc, -EINVAL}, | ||
48 | {ERRbadfile, -ENOENT}, | ||
49 | {ERRbadpath, -ENOTDIR}, | ||
50 | {ERRnofids, -EMFILE}, | ||
51 | {ERRnoaccess, -EACCES}, | ||
52 | {ERRbadfid, -EBADF}, | ||
53 | {ERRbadmcb, -EIO}, | ||
54 | {ERRnomem, -ENOMEM}, | ||
55 | {ERRbadmem, -EFAULT}, | ||
56 | {ERRbadenv, -EFAULT}, | ||
57 | {ERRbadformat, -EINVAL}, | ||
58 | {ERRbadaccess, -EACCES}, | ||
59 | {ERRbaddata, -EIO}, | ||
60 | {ERRbaddrive, -ENXIO}, | ||
61 | {ERRremcd, -EACCES}, | ||
62 | {ERRdiffdevice, -EXDEV}, | ||
63 | {ERRnofiles, -ENOENT}, | ||
64 | {ERRbadshare, -ETXTBSY}, | ||
65 | {ERRlock, -EACCES}, | ||
66 | {ERRunsup, -EINVAL}, | ||
67 | {ERRnosuchshare,-ENXIO}, | ||
68 | {ERRfilexists, -EEXIST}, | ||
69 | {ERRinvparm, -EINVAL}, | ||
70 | {ERRdiskfull, -ENOSPC}, | ||
71 | {ERRinvname, -ENOENT}, | ||
72 | {ERRinvlevel,-EOPNOTSUPP}, | ||
73 | {ERRdirnotempty, -ENOTEMPTY}, | ||
74 | {ERRnotlocked, -ENOLCK}, | ||
75 | {ERRalreadyexists, -EEXIST}, | ||
76 | {ERRmoredata, -EOVERFLOW}, | ||
77 | {ERReasnotsupported,-EOPNOTSUPP}, | ||
78 | {ErrQuota, -EDQUOT}, | ||
79 | {ErrNotALink, -ENOLINK}, | ||
80 | {ERRnetlogonNotStarted,-ENOPROTOOPT}, | ||
81 | {0, 0} | ||
82 | }; | ||
83 | |||
84 | static const struct smb_to_posix_error mapping_table_ERRSRV[] = { | ||
85 | {ERRerror, -EIO}, | ||
86 | {ERRbadpw, -EPERM}, | ||
87 | {ERRbadtype, -EREMOTE}, | ||
88 | {ERRaccess, -EACCES}, | ||
89 | {ERRinvtid, -ENXIO}, | ||
90 | {ERRinvnetname, -ENODEV}, | ||
91 | {ERRinvdevice, -ENXIO}, | ||
92 | {ERRqfull, -ENOSPC}, | ||
93 | {ERRqtoobig, -ENOSPC}, | ||
94 | {ERRqeof, -EIO}, | ||
95 | {ERRinvpfid, -EBADF}, | ||
96 | {ERRsmbcmd, -EBADRQC}, | ||
97 | {ERRsrverror, -EIO}, | ||
98 | {ERRbadBID, -EIO}, | ||
99 | {ERRfilespecs, -EINVAL}, | ||
100 | {ERRbadLink, -EIO}, | ||
101 | {ERRbadpermits, -EINVAL}, | ||
102 | {ERRbadPID, -ESRCH}, | ||
103 | {ERRsetattrmode, -EINVAL}, | ||
104 | {ERRpaused, -EHOSTDOWN}, | ||
105 | {ERRmsgoff, -EHOSTDOWN}, | ||
106 | {ERRnoroom, -ENOSPC}, | ||
107 | {ERRrmuns, -EUSERS}, | ||
108 | {ERRtimeout, -ETIME}, | ||
109 | {ERRnoresource, -ENOBUFS}, | ||
110 | {ERRtoomanyuids, -EUSERS}, | ||
111 | {ERRbaduid, -EACCES}, | ||
112 | {ERRusempx, -EIO}, | ||
113 | {ERRusestd, -EIO}, | ||
114 | {ERR_NOTIFY_ENUM_DIR, -ENOBUFS}, | ||
115 | {ERRaccountexpired, -EACCES}, | ||
116 | {ERRbadclient, -EACCES}, | ||
117 | {ERRbadLogonTime, -EACCES}, | ||
118 | {ERRpasswordExpired, -EACCES}, | ||
119 | {ERRnosupport, -EINVAL}, | ||
120 | {0, 0} | ||
121 | }; | ||
122 | |||
123 | static const struct smb_to_posix_error mapping_table_ERRHRD[] = { | ||
124 | {0, 0} | ||
125 | }; | ||
126 | |||
127 | /* Convert string containing dotted ip address to binary form */ | ||
128 | /* returns 0 if invalid address */ | ||
129 | |||
130 | /* BB add address family, change rc to status flag and return union or for ipv6 */ | ||
131 | /* will need parent to call something like inet_pton to convert ipv6 address BB */ | ||
132 | int | ||
133 | cifs_inet_pton(int address_family, char *cp,void *dst) | ||
134 | { | ||
135 | struct in_addr address; | ||
136 | int value; | ||
137 | int digit; | ||
138 | int i; | ||
139 | char temp; | ||
140 | char bytes[4]; | ||
141 | char *end = bytes; | ||
142 | static const int addr_class_max[4] = | ||
143 | { 0xffffffff, 0xffffff, 0xffff, 0xff }; | ||
144 | |||
145 | if(address_family != AF_INET) | ||
146 | return -EAFNOSUPPORT; | ||
147 | |||
148 | for (i = 0; i < 4; i++) { | ||
149 | bytes[i] = 0; | ||
150 | } | ||
151 | |||
152 | temp = *cp; | ||
153 | |||
154 | while (TRUE) { | ||
155 | if (!isdigit(temp)) | ||
156 | return 0; | ||
157 | |||
158 | value = 0; | ||
159 | digit = 0; | ||
160 | for (;;) { | ||
161 | if (isascii(temp) && isdigit(temp)) { | ||
162 | value = (value * 10) + temp - '0'; | ||
163 | temp = *++cp; | ||
164 | digit = 1; | ||
165 | } else | ||
166 | break; | ||
167 | } | ||
168 | |||
169 | if (temp == '.') { | ||
170 | if ((end > bytes + 2) || (value > 255)) | ||
171 | return 0; | ||
172 | *end++ = value; | ||
173 | temp = *++cp; | ||
174 | } else if (temp == ':') { | ||
175 | cFYI(1,("IPv6 addresses not supported for CIFS mounts yet")); | ||
176 | return -1; | ||
177 | } else | ||
178 | break; | ||
179 | } | ||
180 | |||
181 | /* check for last characters */ | ||
182 | if (temp != '\0' && (!isascii(temp) || !isspace(temp))) | ||
183 | if (temp != '\\') { | ||
184 | if (temp != '/') | ||
185 | return 0; | ||
186 | else | ||
187 | (*cp = '\\'); /* switch the slash the expected way */ | ||
188 | } | ||
189 | if (value > addr_class_max[end - bytes]) | ||
190 | return 0; | ||
191 | |||
192 | address.s_addr = *((__be32 *) bytes) | htonl(value); | ||
193 | *((__be32 *)dst) = address.s_addr; | ||
194 | return 1; /* success */ | ||
195 | } | ||
196 | |||
197 | /***************************************************************************** | ||
198 | convert a NT status code to a dos class/code | ||
199 | *****************************************************************************/ | ||
200 | /* NT status -> dos error map */ | ||
201 | static const struct { | ||
202 | __u8 dos_class; | ||
203 | __u16 dos_code; | ||
204 | __u32 ntstatus; | ||
205 | } ntstatus_to_dos_map[] = { | ||
206 | { | ||
207 | ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, { | ||
208 | ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, { | ||
209 | ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS}, { | ||
210 | ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, { | ||
211 | ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, { | ||
212 | ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, { | ||
213 | ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA}, { | ||
214 | ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE}, { | ||
215 | ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK}, { | ||
216 | ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC}, { | ||
217 | ERRDOS, 87, NT_STATUS_INVALID_CID}, { | ||
218 | ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED}, { | ||
219 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER}, { | ||
220 | ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE}, { | ||
221 | ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE}, { | ||
222 | ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST}, { | ||
223 | ERRDOS, 38, NT_STATUS_END_OF_FILE}, { | ||
224 | ERRDOS, 34, NT_STATUS_WRONG_VOLUME}, { | ||
225 | ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE}, { | ||
226 | ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA}, { | ||
227 | ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR}, | ||
228 | /* { This NT error code was 'sqashed' | ||
229 | from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK | ||
230 | during the session setup } */ | ||
231 | { | ||
232 | ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY}, { | ||
233 | ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES}, { | ||
234 | ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW}, { | ||
235 | ERRDOS, 87, NT_STATUS_UNABLE_TO_FREE_VM}, { | ||
236 | ERRDOS, 87, NT_STATUS_UNABLE_TO_DELETE_SECTION}, { | ||
237 | ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE}, { | ||
238 | ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION}, { | ||
239 | ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE}, { | ||
240 | ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE}, { | ||
241 | ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION}, { | ||
242 | ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED}, | ||
243 | /* { This NT error code was 'sqashed' | ||
244 | from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE | ||
245 | during the session setup } */ | ||
246 | { | ||
247 | ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED}, { | ||
248 | ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL}, { | ||
249 | ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH}, { | ||
250 | ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION}, { | ||
251 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION}, { | ||
252 | ERRHRD, ERRgeneral, NT_STATUS_UNWIND}, { | ||
253 | ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK}, { | ||
254 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET}, { | ||
255 | ERRDOS, 158, NT_STATUS_NOT_LOCKED}, { | ||
256 | ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR}, { | ||
257 | ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM}, { | ||
258 | ERRDOS, 487, NT_STATUS_NOT_COMMITTED}, { | ||
259 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES}, { | ||
260 | ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG}, { | ||
261 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_MIX}, { | ||
262 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER}, { | ||
263 | ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR}, { | ||
264 | ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_INVALID}, { /* mapping changed since shell does lookup on * and expects file not found */ | ||
265 | ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND}, { | ||
266 | ERRDOS, ERRalreadyexists, NT_STATUS_OBJECT_NAME_COLLISION}, { | ||
267 | ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, { | ||
268 | ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, { | ||
269 | ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, { | ||
270 | ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID}, { | ||
271 | ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND}, { | ||
272 | ERRDOS, 161, NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, { | ||
273 | ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN}, { | ||
274 | ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR}, { | ||
275 | ERRDOS, 23, NT_STATUS_DATA_ERROR}, { | ||
276 | ERRDOS, 23, NT_STATUS_CRC_ERROR}, { | ||
277 | ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG}, { | ||
278 | ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED}, { | ||
279 | ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE}, { | ||
280 | ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION}, { | ||
281 | ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED}, { | ||
282 | ERRDOS, 87, NT_STATUS_INVALID_PAGE_PROTECTION}, { | ||
283 | ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED}, { | ||
284 | ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, { | ||
285 | ERRDOS, 87, NT_STATUS_PORT_ALREADY_SET}, { | ||
286 | ERRDOS, 87, NT_STATUS_SECTION_NOT_IMAGE}, { | ||
287 | ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED}, { | ||
288 | ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING}, { | ||
289 | ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT}, { | ||
290 | ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP}, { | ||
291 | ERRDOS, 87, NT_STATUS_SECTION_PROTECTION}, { | ||
292 | ERRDOS, ERReasnotsupported, NT_STATUS_EAS_NOT_SUPPORTED}, { | ||
293 | ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, { | ||
294 | ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, { | ||
295 | ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, { | ||
296 | ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR}, { | ||
297 | ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT}, { | ||
298 | ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED}, { | ||
299 | ERRDOS, ERRbadfile, NT_STATUS_DELETE_PENDING}, { | ||
300 | ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED}, { | ||
301 | ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION}, { | ||
302 | ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH}, { | ||
303 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER}, { | ||
304 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP}, { | ||
305 | ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN}, { | ||
306 | ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY}, { | ||
307 | ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS}, { | ||
308 | ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION}, { | ||
309 | ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE}, { | ||
310 | ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD}, { | ||
311 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, { | ||
312 | ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS}, | ||
313 | /* { This NT error code was 'sqashed' | ||
314 | from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE | ||
315 | during the session setup } */ | ||
316 | { | ||
317 | ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { | ||
318 | ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, { | ||
319 | ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, { | ||
320 | ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, { | ||
321 | ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP}, { | ||
322 | ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN}, | ||
323 | /* { This NT error code was 'sqashed' | ||
324 | from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE | ||
325 | during the session setup } */ | ||
326 | { | ||
327 | ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD}, { | ||
328 | ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD}, { | ||
329 | ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, { | ||
330 | ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, { | ||
331 | ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { | ||
332 | ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { | ||
333 | ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { | ||
334 | ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, { | ||
335 | ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { | ||
336 | ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { | ||
337 | ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { | ||
338 | ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, { | ||
339 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY}, { | ||
340 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL}, { | ||
341 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID}, { | ||
342 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR}, { | ||
343 | ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND}, { | ||
344 | ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT}, { | ||
345 | ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN}, { | ||
346 | ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL}, { | ||
347 | ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED}, { | ||
348 | ERRDOS, 112, NT_STATUS_DISK_FULL}, { | ||
349 | ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED}, { | ||
350 | ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED}, { | ||
351 | ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, { | ||
352 | ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED}, { | ||
353 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY}, { | ||
354 | ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED}, { | ||
355 | ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL}, { | ||
356 | ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED}, { | ||
357 | ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA}, { | ||
358 | ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND}, { | ||
359 | ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, { | ||
360 | ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND}, { | ||
361 | ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, { | ||
362 | ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND}, { | ||
363 | ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, { | ||
364 | ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT}, { | ||
365 | ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION}, { | ||
366 | ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW}, { | ||
367 | ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK}, { | ||
368 | ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW}, { | ||
369 | ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, { | ||
370 | ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW}, { | ||
371 | ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION}, { | ||
372 | ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES}, { | ||
373 | ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, { | ||
374 | ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED}, | ||
375 | /* { This NT error code was 'sqashed' | ||
376 | from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES | ||
377 | during the session setup } */ | ||
378 | { | ||
379 | ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, { | ||
380 | ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, { | ||
381 | ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR}, { | ||
382 | ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED}, { | ||
383 | ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE}, { | ||
384 | ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE}, { | ||
385 | ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED}, { | ||
386 | ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA}, { | ||
387 | ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED}, { | ||
388 | ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY}, { | ||
389 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES}, { | ||
390 | ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL}, { | ||
391 | ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS}, { | ||
392 | ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS}, { | ||
393 | ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE}, { | ||
394 | ERRDOS, 87, NT_STATUS_BAD_MASTER_BOOT_RECORD}, { | ||
395 | ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT}, { | ||
396 | ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE}, { | ||
397 | ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE}, { | ||
398 | ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE}, { | ||
399 | ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY}, { | ||
400 | ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION}, { | ||
401 | ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED}, { | ||
402 | ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING}, { | ||
403 | ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED}, { | ||
404 | ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING}, { | ||
405 | ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE}, { | ||
406 | ERRDOS, 121, NT_STATUS_IO_TIMEOUT}, { | ||
407 | ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED}, { | ||
408 | ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED}, { | ||
409 | ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED}, { | ||
410 | ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET}, { | ||
411 | ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY}, { | ||
412 | ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED}, { | ||
413 | ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING}, { | ||
414 | ERRDOS, 52, NT_STATUS_DUPLICATE_NAME}, { | ||
415 | ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH}, { | ||
416 | ERRDOS, 54, NT_STATUS_NETWORK_BUSY}, { | ||
417 | ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST}, { | ||
418 | ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS}, { | ||
419 | ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR}, { | ||
420 | ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE}, { | ||
421 | ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR}, { | ||
422 | ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER}, { | ||
423 | ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL}, { | ||
424 | ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE}, { | ||
425 | ERRDOS, 63, NT_STATUS_PRINT_CANCELLED}, { | ||
426 | ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED}, { | ||
427 | ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED}, { | ||
428 | ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE}, { | ||
429 | ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME}, { | ||
430 | ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES}, { | ||
431 | ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS}, { | ||
432 | ERRDOS, 70, NT_STATUS_SHARING_PAUSED}, { | ||
433 | ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED}, { | ||
434 | ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED}, { | ||
435 | ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT}, { | ||
436 | ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT}, { | ||
437 | ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE}, { | ||
438 | ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED}, { | ||
439 | ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, { | ||
440 | ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT}, { | ||
441 | ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT}, { | ||
442 | ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY}, { | ||
443 | ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, { | ||
444 | ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF}, { | ||
445 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE}, { | ||
446 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE}, { | ||
447 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE}, { | ||
448 | ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN}, { | ||
449 | ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS}, { | ||
450 | ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, { | ||
451 | ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED}, { | ||
452 | ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL}, { | ||
453 | ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION}, { | ||
454 | ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR}, { | ||
455 | ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED}, { | ||
456 | ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT}, { | ||
457 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER}, { | ||
458 | ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR}, { | ||
459 | ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, { | ||
460 | ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, { | ||
461 | ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, { | ||
462 | ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS}, { | ||
463 | ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS}, { | ||
464 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_1}, { | ||
465 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_2}, { | ||
466 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_3}, { | ||
467 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_4}, { | ||
468 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_5}, { | ||
469 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_6}, { | ||
470 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_7}, { | ||
471 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_8}, { | ||
472 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_9}, { | ||
473 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_10}, { | ||
474 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_11}, { | ||
475 | ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_12}, { | ||
476 | ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED}, { | ||
477 | ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED}, { | ||
478 | ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW}, { | ||
479 | ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE}, { | ||
480 | ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE}, { | ||
481 | ERRDOS, 203, 0xc0000100}, { | ||
482 | ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY}, { | ||
483 | ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR}, { | ||
484 | ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY}, { | ||
485 | ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE}, { | ||
486 | ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION}, { | ||
487 | ERRDOS, 206, NT_STATUS_NAME_TOO_LONG}, { | ||
488 | ERRDOS, 2401, NT_STATUS_FILES_OPEN}, { | ||
489 | ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE}, { | ||
490 | ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND}, { | ||
491 | ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING}, { | ||
492 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE}, { | ||
493 | ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION}, { | ||
494 | ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE}, { | ||
495 | ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED}, { | ||
496 | ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT}, { | ||
497 | ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST}, { | ||
498 | ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED}, { | ||
499 | ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER}, { | ||
500 | ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND}, { | ||
501 | ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID}, { | ||
502 | ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, { | ||
503 | ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR}, { | ||
504 | ERRHRD, ERRgeneral, NT_STATUS_NO_LDT}, { | ||
505 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE}, { | ||
506 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET}, { | ||
507 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR}, { | ||
508 | ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT}, { | ||
509 | ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE}, { | ||
510 | ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE}, { | ||
511 | ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO}, { | ||
512 | ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES}, { | ||
513 | ERRHRD, ERRgeneral, NT_STATUS_CANCELLED}, { | ||
514 | ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE}, { | ||
515 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME}, { | ||
516 | ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED}, { | ||
517 | ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT}, { | ||
518 | ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP}, { | ||
519 | ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER}, { | ||
520 | ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP}, { | ||
521 | ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED}, { | ||
522 | ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS}, { | ||
523 | ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS}, { | ||
524 | ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE}, { | ||
525 | ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, { | ||
526 | ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT}, { | ||
527 | ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT}, { | ||
528 | ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ}, { | ||
529 | ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT}, { | ||
530 | ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16}, { | ||
531 | ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT}, { | ||
532 | ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC}, { | ||
533 | ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED}, { | ||
534 | ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND}, { | ||
535 | ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED}, { | ||
536 | ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED}, { | ||
537 | ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND}, { | ||
538 | ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND}, { | ||
539 | ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT}, { | ||
540 | ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT}, { | ||
541 | ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT}, { | ||
542 | ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES}, { | ||
543 | ERRDOS, 59, NT_STATUS_LINK_FAILED}, { | ||
544 | ERRDOS, 59, NT_STATUS_LINK_TIMEOUT}, { | ||
545 | ERRDOS, 59, NT_STATUS_INVALID_CONNECTION}, { | ||
546 | ERRDOS, 59, NT_STATUS_INVALID_ADDRESS}, { | ||
547 | ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED}, { | ||
548 | ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE}, { | ||
549 | ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION}, { | ||
550 | ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE}, { | ||
551 | ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED}, { | ||
552 | ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE}, { | ||
553 | ERRDOS, 124, NT_STATUS_INVALID_LEVEL}, { | ||
554 | ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE}, { | ||
555 | ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, { | ||
556 | ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, { | ||
557 | ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT}, { | ||
558 | ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED}, { | ||
559 | ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR}, { | ||
560 | ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME}, { | ||
561 | ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED}, { | ||
562 | ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS}, { | ||
563 | ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS}, { | ||
564 | ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS}, { | ||
565 | ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS}, { | ||
566 | ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED}, { | ||
567 | ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS}, { | ||
568 | ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG}, { | ||
569 | ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR}, { | ||
570 | ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE}, { | ||
571 | ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS}, { | ||
572 | ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED}, { | ||
573 | ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE}, { | ||
574 | ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, { | ||
575 | ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, { | ||
576 | ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER}, { | ||
577 | ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, { | ||
578 | ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER}, { | ||
579 | ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER}, { | ||
580 | ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER}, { | ||
581 | ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME}, { | ||
582 | ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, { | ||
583 | ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER}, { | ||
584 | ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR}, { | ||
585 | ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS}, { | ||
586 | ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED}, { | ||
587 | ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED}, { | ||
588 | ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED}, { | ||
589 | ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY}, { | ||
590 | ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING}, { | ||
591 | ERRHRD, ERRgeneral, 0xc000016e}, { | ||
592 | ERRHRD, ERRgeneral, 0xc000016f}, { | ||
593 | ERRHRD, ERRgeneral, 0xc0000170}, { | ||
594 | ERRHRD, ERRgeneral, 0xc0000171}, { | ||
595 | ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE}, { | ||
596 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH}, { | ||
597 | ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED}, { | ||
598 | ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA}, { | ||
599 | ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, { | ||
600 | ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW}, { | ||
601 | ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA}, { | ||
602 | ERRHRD, ERRgeneral, 0xc0000179}, { | ||
603 | ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER}, { | ||
604 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER}, { | ||
605 | ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED}, { | ||
606 | ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE}, { | ||
607 | ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS}, { | ||
608 | ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, { | ||
609 | ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN}, { | ||
610 | ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE}, { | ||
611 | ERRDOS, 87, NT_STATUS_DEVICE_CONFIGURATION_ERROR}, { | ||
612 | ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR}, { | ||
613 | ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE}, { | ||
614 | ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR}, { | ||
615 | ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR}, { | ||
616 | ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER}, { | ||
617 | ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL}, { | ||
618 | ERRDOS, 19, NT_STATUS_TOO_LATE}, { | ||
619 | ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET}, | ||
620 | /* { This NT error code was 'sqashed' | ||
621 | from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE | ||
622 | during the session setup } */ | ||
623 | { | ||
624 | ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, { | ||
625 | ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, { | ||
626 | ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, { | ||
627 | ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT}, { | ||
628 | ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, { | ||
629 | ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, { | ||
630 | ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, { | ||
631 | ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, { | ||
632 | ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, { | ||
633 | ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, { | ||
634 | ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, { | ||
635 | ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, { | ||
636 | ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED}, { | ||
637 | ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, { | ||
638 | ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, { | ||
639 | ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT}, | ||
640 | /* { This NT error code was 'sqashed' | ||
641 | from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE | ||
642 | during the session setup } */ | ||
643 | { | ||
644 | ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, { | ||
645 | ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED}, { | ||
646 | ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY}, { | ||
647 | ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED}, { | ||
648 | ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND}, { | ||
649 | ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES}, { | ||
650 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE}, { | ||
651 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT}, { | ||
652 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD}, { | ||
653 | ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES}, { | ||
654 | ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS}, { | ||
655 | ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED}, { | ||
656 | ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED}, { | ||
657 | ERRDOS, 64, NT_STATUS_CONNECTION_RESET}, { | ||
658 | ERRDOS, 68, NT_STATUS_TOO_MANY_NODES}, { | ||
659 | ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED}, { | ||
660 | ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT}, { | ||
661 | ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE}, { | ||
662 | ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH}, { | ||
663 | ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED}, { | ||
664 | ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID}, { | ||
665 | ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE}, { | ||
666 | ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION}, { | ||
667 | ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION}, { | ||
668 | ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, { | ||
669 | ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED}, { | ||
670 | ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED}, { | ||
671 | ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED}, { | ||
672 | ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND}, { | ||
673 | ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR}, { | ||
674 | ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT}, { | ||
675 | ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH}, { | ||
676 | ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT}, { | ||
677 | ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, { | ||
678 | ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, { | ||
679 | ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, { | ||
680 | ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, { | ||
681 | ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, { | ||
682 | ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, { | ||
683 | ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, { | ||
684 | ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ}, { | ||
685 | ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK}, { | ||
686 | ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID}, { | ||
687 | ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS}, { | ||
688 | ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE}, { | ||
689 | ERRHRD, ERRgeneral, NT_STATUS_RETRY}, { | ||
690 | ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE}, { | ||
691 | ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET}, { | ||
692 | ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND}, { | ||
693 | ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW}, { | ||
694 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT}, { | ||
695 | ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, { | ||
696 | ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT}, { | ||
697 | ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE}, { | ||
698 | ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED}, { | ||
699 | ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT}, { | ||
700 | ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, { | ||
701 | ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED}, { | ||
702 | ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID}, { | ||
703 | ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE}, { | ||
704 | ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE}, { | ||
705 | ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE}, { | ||
706 | ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE}, { | ||
707 | ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE}, { | ||
708 | ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED}, { | ||
709 | ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED}, { | ||
710 | ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER}, { | ||
711 | ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE}, { | ||
712 | ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED}, { | ||
713 | ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET}, { | ||
714 | ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT}, { | ||
715 | ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION}, { | ||
716 | ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION}, { | ||
717 | ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH}, { | ||
718 | ERRHRD, ERRgeneral, 0xc000024a}, { | ||
719 | ERRHRD, ERRgeneral, 0xc000024b}, { | ||
720 | ERRHRD, ERRgeneral, 0xc000024c}, { | ||
721 | ERRHRD, ERRgeneral, 0xc000024d}, { | ||
722 | ERRHRD, ERRgeneral, 0xc000024e}, { | ||
723 | ERRHRD, ERRgeneral, 0xc000024f}, { | ||
724 | ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO}, { | ||
725 | ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT}, { | ||
726 | ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT}, { | ||
727 | ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST}, { | ||
728 | ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1}, { | ||
729 | ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2}, { | ||
730 | ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT}, { | ||
731 | ERRSRV, 3, NT_STATUS_PATH_NOT_COVERED}, { | ||
732 | ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE}, { | ||
733 | ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED}, { | ||
734 | ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT}, { | ||
735 | ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT}, { | ||
736 | ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT}, { | ||
737 | ERRHRD, ERRgeneral, 0xc000025d}, { | ||
738 | ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE}, { | ||
739 | ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION}, { | ||
740 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE}, { | ||
741 | ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, { | ||
742 | ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, { | ||
743 | ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, { | ||
744 | ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, { | ||
745 | ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, { | ||
746 | ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, { | ||
747 | ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, { | ||
748 | ERRDOS, 21, 0xc000026e}, { | ||
749 | ERRDOS, 161, 0xc0000281}, { | ||
750 | ERRDOS, ERRnoaccess, 0xc000028a}, { | ||
751 | ERRDOS, ERRnoaccess, 0xc000028b}, { | ||
752 | ERRHRD, ERRgeneral, 0xc000028c}, { | ||
753 | ERRDOS, ERRnoaccess, 0xc000028d}, { | ||
754 | ERRDOS, ERRnoaccess, 0xc000028e}, { | ||
755 | ERRDOS, ERRnoaccess, 0xc000028f}, { | ||
756 | ERRDOS, ERRnoaccess, 0xc0000290}, { | ||
757 | ERRDOS, ERRbadfunc, 0xc000029c}, { | ||
758 | ERRDOS, ERRinvlevel, 0x007c0001}, }; | ||
759 | |||
760 | /***************************************************************************** | ||
761 | Print an error message from the status code | ||
762 | *****************************************************************************/ | ||
763 | static void | ||
764 | cifs_print_status(__u32 status_code) | ||
765 | { | ||
766 | int idx = 0; | ||
767 | |||
768 | while (nt_errs[idx].nt_errstr != NULL) { | ||
769 | if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) == | ||
770 | (status_code & 0xFFFFFF)) { | ||
771 | printk(KERN_NOTICE "Status code returned 0x%08x %s\n", | ||
772 | status_code,nt_errs[idx].nt_errstr); | ||
773 | } | ||
774 | idx++; | ||
775 | } | ||
776 | return; | ||
777 | } | ||
778 | |||
779 | |||
780 | static void | ||
781 | ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode) | ||
782 | { | ||
783 | int i; | ||
784 | if (ntstatus == 0) { | ||
785 | *eclass = 0; | ||
786 | *ecode = 0; | ||
787 | return; | ||
788 | } | ||
789 | for (i = 0; ntstatus_to_dos_map[i].ntstatus; i++) { | ||
790 | if (ntstatus == ntstatus_to_dos_map[i].ntstatus) { | ||
791 | *eclass = ntstatus_to_dos_map[i].dos_class; | ||
792 | *ecode = ntstatus_to_dos_map[i].dos_code; | ||
793 | return; | ||
794 | } | ||
795 | } | ||
796 | *eclass = ERRHRD; | ||
797 | *ecode = ERRgeneral; | ||
798 | } | ||
799 | |||
800 | int | ||
801 | map_smb_to_linux_error(struct smb_hdr *smb) | ||
802 | { | ||
803 | unsigned int i; | ||
804 | int rc = -EIO; /* if transport error smb error may not be set */ | ||
805 | __u8 smberrclass; | ||
806 | __u16 smberrcode; | ||
807 | |||
808 | /* BB if NT Status codes - map NT BB */ | ||
809 | |||
810 | /* old style smb error codes */ | ||
811 | if (smb->Status.CifsError == 0) | ||
812 | return 0; | ||
813 | |||
814 | if (smb->Flags2 & SMBFLG2_ERR_STATUS) { | ||
815 | /* translate the newer STATUS codes to old style errors and then to POSIX errors */ | ||
816 | __u32 err = le32_to_cpu(smb->Status.CifsError); | ||
817 | if(cifsFYI) | ||
818 | cifs_print_status(err); | ||
819 | ntstatus_to_dos(err, &smberrclass, &smberrcode); | ||
820 | } else { | ||
821 | smberrclass = smb->Status.DosError.ErrorClass; | ||
822 | smberrcode = le16_to_cpu(smb->Status.DosError.Error); | ||
823 | } | ||
824 | |||
825 | /* old style errors */ | ||
826 | |||
827 | /* DOS class smb error codes - map DOS */ | ||
828 | if (smberrclass == ERRDOS) { /* one byte field no need to byte reverse */ | ||
829 | for (i = 0; | ||
830 | i < | ||
831 | sizeof (mapping_table_ERRDOS) / | ||
832 | sizeof (struct smb_to_posix_error); i++) { | ||
833 | if (mapping_table_ERRDOS[i].smb_err == 0) | ||
834 | break; | ||
835 | else if (mapping_table_ERRDOS[i].smb_err == smberrcode) { | ||
836 | rc = mapping_table_ERRDOS[i].posix_code; | ||
837 | break; | ||
838 | } | ||
839 | /* else try the next error mapping one to see if it will match */ | ||
840 | } | ||
841 | } else if (smberrclass == ERRSRV) { /* server class of error codes */ | ||
842 | for (i = 0; | ||
843 | i < | ||
844 | sizeof (mapping_table_ERRSRV) / | ||
845 | sizeof (struct smb_to_posix_error); i++) { | ||
846 | if (mapping_table_ERRSRV[i].smb_err == 0) | ||
847 | break; | ||
848 | else if (mapping_table_ERRSRV[i].smb_err == smberrcode) { | ||
849 | rc = mapping_table_ERRSRV[i].posix_code; | ||
850 | break; | ||
851 | } | ||
852 | /* else try the next error mapping one to see if it will match */ | ||
853 | } | ||
854 | } | ||
855 | /* else ERRHRD class errors or junk - return EIO */ | ||
856 | |||
857 | cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", smberrcode,rc)); | ||
858 | |||
859 | /* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */ | ||
860 | |||
861 | return rc; | ||
862 | } | ||
863 | |||
864 | /* | ||
865 | * calculate the size of the SMB message based on the fixed header | ||
866 | * portion, the number of word parameters and the data portion of the message | ||
867 | */ | ||
868 | unsigned int | ||
869 | smbCalcSize(struct smb_hdr *ptr) | ||
870 | { | ||
871 | return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + | ||
872 | BCC(ptr)); | ||
873 | } | ||
874 | |||
875 | /* The following are taken from fs/ntfs/util.c */ | ||
876 | |||
877 | #define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000) | ||
878 | |||
879 | /* | ||
880 | * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units) | ||
881 | * into Unix UTC (based 1970-01-01, in seconds). | ||
882 | */ | ||
883 | struct timespec | ||
884 | cifs_NTtimeToUnix(u64 ntutc) | ||
885 | { | ||
886 | struct timespec ts; | ||
887 | /* BB what about the timezone? BB */ | ||
888 | |||
889 | /* Subtract the NTFS time offset, then convert to 1s intervals. */ | ||
890 | u64 t; | ||
891 | |||
892 | t = ntutc - NTFS_TIME_OFFSET; | ||
893 | ts.tv_nsec = do_div(t, 10000000) * 100; | ||
894 | ts.tv_sec = t; | ||
895 | return ts; | ||
896 | } | ||
897 | |||
898 | /* Convert the Unix UTC into NT UTC. */ | ||
899 | u64 | ||
900 | cifs_UnixTimeToNT(struct timespec t) | ||
901 | { | ||
902 | /* Convert to 100ns intervals and then add the NTFS time offset. */ | ||
903 | return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET; | ||
904 | } | ||
diff --git a/fs/cifs/nterr.c b/fs/cifs/nterr.c new file mode 100644 index 000000000000..4da50cd34469 --- /dev/null +++ b/fs/cifs/nterr.c | |||
@@ -0,0 +1,687 @@ | |||
1 | /* | ||
2 | * Unix SMB/Netbios implementation. | ||
3 | * Version 1.9. | ||
4 | * RPC Pipe client / server routines | ||
5 | * Copyright (C) Luke Kenneth Casson Leighton 1997-2001. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program 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 the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | /* NT error codes - see nterr.h */ | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/fs.h> | ||
25 | #include "nterr.h" | ||
26 | |||
27 | const struct nt_err_code_struct nt_errs[] = { | ||
28 | {"NT_STATUS_OK", NT_STATUS_OK}, | ||
29 | {"NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL}, | ||
30 | {"NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED}, | ||
31 | {"NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS}, | ||
32 | {"NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH}, | ||
33 | {"NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION}, | ||
34 | {"STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW}, | ||
35 | {"NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR}, | ||
36 | {"NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA}, | ||
37 | {"NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE}, | ||
38 | {"NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK}, | ||
39 | {"NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC}, | ||
40 | {"NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID}, | ||
41 | {"NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED}, | ||
42 | {"NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER}, | ||
43 | {"NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE}, | ||
44 | {"NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE}, | ||
45 | {"NT_STATUS_INVALID_DEVICE_REQUEST", | ||
46 | NT_STATUS_INVALID_DEVICE_REQUEST}, | ||
47 | {"NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE}, | ||
48 | {"NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME}, | ||
49 | {"NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE}, | ||
50 | {"NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA}, | ||
51 | {"NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR}, | ||
52 | {"NT_STATUS_MORE_PROCESSING_REQUIRED", | ||
53 | NT_STATUS_MORE_PROCESSING_REQUIRED}, | ||
54 | {"NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY}, | ||
55 | {"NT_STATUS_CONFLICTING_ADDRESSES", | ||
56 | NT_STATUS_CONFLICTING_ADDRESSES}, | ||
57 | {"NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW}, | ||
58 | {"NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM}, | ||
59 | {"NT_STATUS_UNABLE_TO_DELETE_SECTION", | ||
60 | NT_STATUS_UNABLE_TO_DELETE_SECTION}, | ||
61 | {"NT_STATUS_INVALID_SYSTEM_SERVICE", | ||
62 | NT_STATUS_INVALID_SYSTEM_SERVICE}, | ||
63 | {"NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION}, | ||
64 | {"NT_STATUS_INVALID_LOCK_SEQUENCE", | ||
65 | NT_STATUS_INVALID_LOCK_SEQUENCE}, | ||
66 | {"NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE}, | ||
67 | {"NT_STATUS_INVALID_FILE_FOR_SECTION", | ||
68 | NT_STATUS_INVALID_FILE_FOR_SECTION}, | ||
69 | {"NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED}, | ||
70 | {"NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED}, | ||
71 | {"NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL}, | ||
72 | {"NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH}, | ||
73 | {"NT_STATUS_NONCONTINUABLE_EXCEPTION", | ||
74 | NT_STATUS_NONCONTINUABLE_EXCEPTION}, | ||
75 | {"NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION}, | ||
76 | {"NT_STATUS_UNWIND", NT_STATUS_UNWIND}, | ||
77 | {"NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK}, | ||
78 | {"NT_STATUS_INVALID_UNWIND_TARGET", | ||
79 | NT_STATUS_INVALID_UNWIND_TARGET}, | ||
80 | {"NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED}, | ||
81 | {"NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR}, | ||
82 | {"NT_STATUS_UNABLE_TO_DECOMMIT_VM", | ||
83 | NT_STATUS_UNABLE_TO_DECOMMIT_VM}, | ||
84 | {"NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED}, | ||
85 | {"NT_STATUS_INVALID_PORT_ATTRIBUTES", | ||
86 | NT_STATUS_INVALID_PORT_ATTRIBUTES}, | ||
87 | {"NT_STATUS_PORT_MESSAGE_TOO_LONG", | ||
88 | NT_STATUS_PORT_MESSAGE_TOO_LONG}, | ||
89 | {"NT_STATUS_INVALID_PARAMETER_MIX", | ||
90 | NT_STATUS_INVALID_PARAMETER_MIX}, | ||
91 | {"NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER}, | ||
92 | {"NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR}, | ||
93 | {"NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID}, | ||
94 | {"NT_STATUS_OBJECT_NAME_NOT_FOUND", | ||
95 | NT_STATUS_OBJECT_NAME_NOT_FOUND}, | ||
96 | {"NT_STATUS_OBJECT_NAME_COLLISION", | ||
97 | NT_STATUS_OBJECT_NAME_COLLISION}, | ||
98 | {"NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE}, | ||
99 | {"NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED}, | ||
100 | {"NT_STATUS_DEVICE_ALREADY_ATTACHED", | ||
101 | NT_STATUS_DEVICE_ALREADY_ATTACHED}, | ||
102 | {"NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID}, | ||
103 | {"NT_STATUS_OBJECT_PATH_NOT_FOUND", | ||
104 | NT_STATUS_OBJECT_PATH_NOT_FOUND}, | ||
105 | {"NT_STATUS_OBJECT_PATH_SYNTAX_BAD", | ||
106 | NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, | ||
107 | {"NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN}, | ||
108 | {"NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR}, | ||
109 | {"NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR}, | ||
110 | {"NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR}, | ||
111 | {"NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG}, | ||
112 | {"NT_STATUS_PORT_CONNECTION_REFUSED", | ||
113 | NT_STATUS_PORT_CONNECTION_REFUSED}, | ||
114 | {"NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE}, | ||
115 | {"NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION}, | ||
116 | {"NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED}, | ||
117 | {"NT_STATUS_INVALID_PAGE_PROTECTION", | ||
118 | NT_STATUS_INVALID_PAGE_PROTECTION}, | ||
119 | {"NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED}, | ||
120 | {"NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED", | ||
121 | NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, | ||
122 | {"NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET}, | ||
123 | {"NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE}, | ||
124 | {"NT_STATUS_SUSPEND_COUNT_EXCEEDED", | ||
125 | NT_STATUS_SUSPEND_COUNT_EXCEEDED}, | ||
126 | {"NT_STATUS_THREAD_IS_TERMINATING", | ||
127 | NT_STATUS_THREAD_IS_TERMINATING}, | ||
128 | {"NT_STATUS_BAD_WORKING_SET_LIMIT", | ||
129 | NT_STATUS_BAD_WORKING_SET_LIMIT}, | ||
130 | {"NT_STATUS_INCOMPATIBLE_FILE_MAP", | ||
131 | NT_STATUS_INCOMPATIBLE_FILE_MAP}, | ||
132 | {"NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION}, | ||
133 | {"NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED}, | ||
134 | {"NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE}, | ||
135 | {"NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY}, | ||
136 | {"NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE}, | ||
137 | {"NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR}, | ||
138 | {"NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT}, | ||
139 | {"NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED}, | ||
140 | {"NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING}, | ||
141 | {"NT_STATUS_CTL_FILE_NOT_SUPPORTED", | ||
142 | NT_STATUS_CTL_FILE_NOT_SUPPORTED}, | ||
143 | {"NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION}, | ||
144 | {"NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH}, | ||
145 | {"NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER}, | ||
146 | {"NT_STATUS_INVALID_PRIMARY_GROUP", | ||
147 | NT_STATUS_INVALID_PRIMARY_GROUP}, | ||
148 | {"NT_STATUS_NO_IMPERSONATION_TOKEN", | ||
149 | NT_STATUS_NO_IMPERSONATION_TOKEN}, | ||
150 | {"NT_STATUS_CANT_DISABLE_MANDATORY", | ||
151 | NT_STATUS_CANT_DISABLE_MANDATORY}, | ||
152 | {"NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS}, | ||
153 | {"NT_STATUS_NO_SUCH_LOGON_SESSION", | ||
154 | NT_STATUS_NO_SUCH_LOGON_SESSION}, | ||
155 | {"NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE}, | ||
156 | {"NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD}, | ||
157 | {"NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME}, | ||
158 | {"NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS}, | ||
159 | {"NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER}, | ||
160 | {"NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS}, | ||
161 | {"NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP}, | ||
162 | {"NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP}, | ||
163 | {"NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP}, | ||
164 | {"NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN}, | ||
165 | {"NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD}, | ||
166 | {"NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD}, | ||
167 | {"NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION}, | ||
168 | {"NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE}, | ||
169 | {"NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION}, | ||
170 | {"NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS}, | ||
171 | {"NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION}, | ||
172 | {"NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED}, | ||
173 | {"NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED}, | ||
174 | {"NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED}, | ||
175 | {"NT_STATUS_TOO_MANY_LUIDS_REQUESTED", | ||
176 | NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, | ||
177 | {"NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED}, | ||
178 | {"NT_STATUS_INVALID_SUB_AUTHORITY", | ||
179 | NT_STATUS_INVALID_SUB_AUTHORITY}, | ||
180 | {"NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL}, | ||
181 | {"NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID}, | ||
182 | {"NT_STATUS_INVALID_SECURITY_DESCR", | ||
183 | NT_STATUS_INVALID_SECURITY_DESCR}, | ||
184 | {"NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND}, | ||
185 | {"NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT}, | ||
186 | {"NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN}, | ||
187 | {"NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL}, | ||
188 | {"NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED}, | ||
189 | {"NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL}, | ||
190 | {"NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED}, | ||
191 | {"NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED}, | ||
192 | {"NT_STATUS_TOO_MANY_GUIDS_REQUESTED", | ||
193 | NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, | ||
194 | {"NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED}, | ||
195 | {"NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY}, | ||
196 | {"NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED}, | ||
197 | {"NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL}, | ||
198 | {"NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED}, | ||
199 | {"NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA}, | ||
200 | {"NT_STATUS_RESOURCE_DATA_NOT_FOUND", | ||
201 | NT_STATUS_RESOURCE_DATA_NOT_FOUND}, | ||
202 | {"NT_STATUS_RESOURCE_TYPE_NOT_FOUND", | ||
203 | NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, | ||
204 | {"NT_STATUS_RESOURCE_NAME_NOT_FOUND", | ||
205 | NT_STATUS_RESOURCE_NAME_NOT_FOUND}, | ||
206 | {"NT_STATUS_ARRAY_BOUNDS_EXCEEDED", | ||
207 | NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, | ||
208 | {"NT_STATUS_FLOAT_DENORMAL_OPERAND", | ||
209 | NT_STATUS_FLOAT_DENORMAL_OPERAND}, | ||
210 | {"NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, | ||
211 | {"NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT}, | ||
212 | {"NT_STATUS_FLOAT_INVALID_OPERATION", | ||
213 | NT_STATUS_FLOAT_INVALID_OPERATION}, | ||
214 | {"NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW}, | ||
215 | {"NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK}, | ||
216 | {"NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW}, | ||
217 | {"NT_STATUS_INTEGER_DIVIDE_BY_ZERO", | ||
218 | NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, | ||
219 | {"NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW}, | ||
220 | {"NT_STATUS_PRIVILEGED_INSTRUCTION", | ||
221 | NT_STATUS_PRIVILEGED_INSTRUCTION}, | ||
222 | {"NT_STATUS_TOO_MANY_PAGING_FILES", | ||
223 | NT_STATUS_TOO_MANY_PAGING_FILES}, | ||
224 | {"NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID}, | ||
225 | {"NT_STATUS_ALLOTTED_SPACE_EXCEEDED", | ||
226 | NT_STATUS_ALLOTTED_SPACE_EXCEEDED}, | ||
227 | {"NT_STATUS_INSUFFICIENT_RESOURCES", | ||
228 | NT_STATUS_INSUFFICIENT_RESOURCES}, | ||
229 | {"NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND}, | ||
230 | {"NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR}, | ||
231 | {"NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED}, | ||
232 | {"NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE}, | ||
233 | {"NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE}, | ||
234 | {"NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED}, | ||
235 | {"NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA}, | ||
236 | {"NT_STATUS_MEDIA_WRITE_PROTECTED", | ||
237 | NT_STATUS_MEDIA_WRITE_PROTECTED}, | ||
238 | {"NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY}, | ||
239 | {"NT_STATUS_INVALID_GROUP_ATTRIBUTES", | ||
240 | NT_STATUS_INVALID_GROUP_ATTRIBUTES}, | ||
241 | {"NT_STATUS_BAD_IMPERSONATION_LEVEL", | ||
242 | NT_STATUS_BAD_IMPERSONATION_LEVEL}, | ||
243 | {"NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS}, | ||
244 | {"NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS}, | ||
245 | {"NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE}, | ||
246 | {"NT_STATUS_BAD_MASTER_BOOT_RECORD", | ||
247 | NT_STATUS_BAD_MASTER_BOOT_RECORD}, | ||
248 | {"NT_STATUS_INSTRUCTION_MISALIGNMENT", | ||
249 | NT_STATUS_INSTRUCTION_MISALIGNMENT}, | ||
250 | {"NT_STATUS_INSTANCE_NOT_AVAILABLE", | ||
251 | NT_STATUS_INSTANCE_NOT_AVAILABLE}, | ||
252 | {"NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE}, | ||
253 | {"NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE}, | ||
254 | {"NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY}, | ||
255 | {"NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION}, | ||
256 | {"NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED}, | ||
257 | {"NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING}, | ||
258 | {"NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED}, | ||
259 | {"NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING}, | ||
260 | {"NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE}, | ||
261 | {"NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT}, | ||
262 | {"NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED}, | ||
263 | {"NT_STATUS_PROFILING_NOT_STARTED", | ||
264 | NT_STATUS_PROFILING_NOT_STARTED}, | ||
265 | {"NT_STATUS_PROFILING_NOT_STOPPED", | ||
266 | NT_STATUS_PROFILING_NOT_STOPPED}, | ||
267 | {"NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET}, | ||
268 | {"NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY}, | ||
269 | {"NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED}, | ||
270 | {"NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING}, | ||
271 | {"NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME}, | ||
272 | {"NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH}, | ||
273 | {"NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY}, | ||
274 | {"NT_STATUS_DEVICE_DOES_NOT_EXIST", | ||
275 | NT_STATUS_DEVICE_DOES_NOT_EXIST}, | ||
276 | {"NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS}, | ||
277 | {"NT_STATUS_ADAPTER_HARDWARE_ERROR", | ||
278 | NT_STATUS_ADAPTER_HARDWARE_ERROR}, | ||
279 | {"NT_STATUS_INVALID_NETWORK_RESPONSE", | ||
280 | NT_STATUS_INVALID_NETWORK_RESPONSE}, | ||
281 | {"NT_STATUS_UNEXPECTED_NETWORK_ERROR", | ||
282 | NT_STATUS_UNEXPECTED_NETWORK_ERROR}, | ||
283 | {"NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER}, | ||
284 | {"NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL}, | ||
285 | {"NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE}, | ||
286 | {"NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED}, | ||
287 | {"NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED}, | ||
288 | {"NT_STATUS_NETWORK_ACCESS_DENIED", | ||
289 | NT_STATUS_NETWORK_ACCESS_DENIED}, | ||
290 | {"NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE}, | ||
291 | {"NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME}, | ||
292 | {"NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES}, | ||
293 | {"NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS}, | ||
294 | {"NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED}, | ||
295 | {"NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED}, | ||
296 | {"NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED}, | ||
297 | {"NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT}, | ||
298 | {"NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT}, | ||
299 | {"NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE}, | ||
300 | {"NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED}, | ||
301 | {"NT_STATUS_VIRTUAL_CIRCUIT_CLOSED", | ||
302 | NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, | ||
303 | {"NT_STATUS_NO_SECURITY_ON_OBJECT", | ||
304 | NT_STATUS_NO_SECURITY_ON_OBJECT}, | ||
305 | {"NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT}, | ||
306 | {"NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY}, | ||
307 | {"NT_STATUS_CANT_ACCESS_DOMAIN_INFO", | ||
308 | NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, | ||
309 | {"NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF}, | ||
310 | {"NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE}, | ||
311 | {"NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE}, | ||
312 | {"NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE}, | ||
313 | {"NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN}, | ||
314 | {"NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS}, | ||
315 | {"NT_STATUS_DOMAIN_LIMIT_EXCEEDED", | ||
316 | NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, | ||
317 | {"NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED}, | ||
318 | {"NT_STATUS_INVALID_OPLOCK_PROTOCOL", | ||
319 | NT_STATUS_INVALID_OPLOCK_PROTOCOL}, | ||
320 | {"NT_STATUS_INTERNAL_DB_CORRUPTION", | ||
321 | NT_STATUS_INTERNAL_DB_CORRUPTION}, | ||
322 | {"NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR}, | ||
323 | {"NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED}, | ||
324 | {"NT_STATUS_BAD_DESCRIPTOR_FORMAT", | ||
325 | NT_STATUS_BAD_DESCRIPTOR_FORMAT}, | ||
326 | {"NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER}, | ||
327 | {"NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR}, | ||
328 | {"NT_STATUS_UNEXPECTED_MM_CREATE_ERR", | ||
329 | NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, | ||
330 | {"NT_STATUS_UNEXPECTED_MM_MAP_ERROR", | ||
331 | NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, | ||
332 | {"NT_STATUS_UNEXPECTED_MM_EXTEND_ERR", | ||
333 | NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, | ||
334 | {"NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS}, | ||
335 | {"NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS}, | ||
336 | {"NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1}, | ||
337 | {"NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2}, | ||
338 | {"NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3}, | ||
339 | {"NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4}, | ||
340 | {"NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5}, | ||
341 | {"NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6}, | ||
342 | {"NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7}, | ||
343 | {"NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8}, | ||
344 | {"NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9}, | ||
345 | {"NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10}, | ||
346 | {"NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11}, | ||
347 | {"NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12}, | ||
348 | {"NT_STATUS_REDIRECTOR_NOT_STARTED", | ||
349 | NT_STATUS_REDIRECTOR_NOT_STARTED}, | ||
350 | {"NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED}, | ||
351 | {"NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW}, | ||
352 | {"NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE}, | ||
353 | {"NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE}, | ||
354 | {"NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY}, | ||
355 | {"NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR}, | ||
356 | {"NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY}, | ||
357 | {"NT_STATUS_BAD_LOGON_SESSION_STATE", | ||
358 | NT_STATUS_BAD_LOGON_SESSION_STATE}, | ||
359 | {"NT_STATUS_LOGON_SESSION_COLLISION", | ||
360 | NT_STATUS_LOGON_SESSION_COLLISION}, | ||
361 | {"NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG}, | ||
362 | {"NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN}, | ||
363 | {"NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE}, | ||
364 | {"NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND}, | ||
365 | {"NT_STATUS_PROCESS_IS_TERMINATING", | ||
366 | NT_STATUS_PROCESS_IS_TERMINATING}, | ||
367 | {"NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE}, | ||
368 | {"NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION}, | ||
369 | {"NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE}, | ||
370 | {"NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED}, | ||
371 | {"NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT}, | ||
372 | {"NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST}, | ||
373 | {"NT_STATUS_ABIOS_LID_ALREADY_OWNED", | ||
374 | NT_STATUS_ABIOS_LID_ALREADY_OWNED}, | ||
375 | {"NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER}, | ||
376 | {"NT_STATUS_ABIOS_INVALID_COMMAND", | ||
377 | NT_STATUS_ABIOS_INVALID_COMMAND}, | ||
378 | {"NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID}, | ||
379 | {"NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", | ||
380 | NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, | ||
381 | {"NT_STATUS_ABIOS_INVALID_SELECTOR", | ||
382 | NT_STATUS_ABIOS_INVALID_SELECTOR}, | ||
383 | {"NT_STATUS_NO_LDT", NT_STATUS_NO_LDT}, | ||
384 | {"NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE}, | ||
385 | {"NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET}, | ||
386 | {"NT_STATUS_INVALID_LDT_DESCRIPTOR", | ||
387 | NT_STATUS_INVALID_LDT_DESCRIPTOR}, | ||
388 | {"NT_STATUS_INVALID_IMAGE_NE_FORMAT", | ||
389 | NT_STATUS_INVALID_IMAGE_NE_FORMAT}, | ||
390 | {"NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE}, | ||
391 | {"NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE}, | ||
392 | {"NT_STATUS_MAPPED_FILE_SIZE_ZERO", | ||
393 | NT_STATUS_MAPPED_FILE_SIZE_ZERO}, | ||
394 | {"NT_STATUS_TOO_MANY_OPENED_FILES", | ||
395 | NT_STATUS_TOO_MANY_OPENED_FILES}, | ||
396 | {"NT_STATUS_CANCELLED", NT_STATUS_CANCELLED}, | ||
397 | {"NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE}, | ||
398 | {"NT_STATUS_INVALID_COMPUTER_NAME", | ||
399 | NT_STATUS_INVALID_COMPUTER_NAME}, | ||
400 | {"NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED}, | ||
401 | {"NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT}, | ||
402 | {"NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP}, | ||
403 | {"NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER}, | ||
404 | {"NT_STATUS_MEMBERS_PRIMARY_GROUP", | ||
405 | NT_STATUS_MEMBERS_PRIMARY_GROUP}, | ||
406 | {"NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED}, | ||
407 | {"NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS}, | ||
408 | {"NT_STATUS_THREAD_NOT_IN_PROCESS", | ||
409 | NT_STATUS_THREAD_NOT_IN_PROCESS}, | ||
410 | {"NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE}, | ||
411 | {"NT_STATUS_PAGEFILE_QUOTA_EXCEEDED", | ||
412 | NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, | ||
413 | {"NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT}, | ||
414 | {"NT_STATUS_INVALID_IMAGE_LE_FORMAT", | ||
415 | NT_STATUS_INVALID_IMAGE_LE_FORMAT}, | ||
416 | {"NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ}, | ||
417 | {"NT_STATUS_INVALID_IMAGE_PROTECT", | ||
418 | NT_STATUS_INVALID_IMAGE_PROTECT}, | ||
419 | {"NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16}, | ||
420 | {"NT_STATUS_LOGON_SERVER_CONFLICT", | ||
421 | NT_STATUS_LOGON_SERVER_CONFLICT}, | ||
422 | {"NT_STATUS_TIME_DIFFERENCE_AT_DC", | ||
423 | NT_STATUS_TIME_DIFFERENCE_AT_DC}, | ||
424 | {"NT_STATUS_SYNCHRONIZATION_REQUIRED", | ||
425 | NT_STATUS_SYNCHRONIZATION_REQUIRED}, | ||
426 | {"NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND}, | ||
427 | {"NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED}, | ||
428 | {"NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED}, | ||
429 | {"NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND}, | ||
430 | {"NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND}, | ||
431 | {"NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT}, | ||
432 | {"NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT}, | ||
433 | {"NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT}, | ||
434 | {"NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES}, | ||
435 | {"NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED}, | ||
436 | {"NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT}, | ||
437 | {"NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION}, | ||
438 | {"NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS}, | ||
439 | {"NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED}, | ||
440 | {"NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE}, | ||
441 | {"NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION}, | ||
442 | {"NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE}, | ||
443 | {"NT_STATUS_PAGEFILE_CREATE_FAILED", | ||
444 | NT_STATUS_PAGEFILE_CREATE_FAILED}, | ||
445 | {"NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE}, | ||
446 | {"NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL}, | ||
447 | {"NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE}, | ||
448 | {"NT_STATUS_ILLEGAL_FLOAT_CONTEXT", | ||
449 | NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, | ||
450 | {"NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN}, | ||
451 | {"NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT}, | ||
452 | {"NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED}, | ||
453 | {"NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR}, | ||
454 | {"NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME}, | ||
455 | {"NT_STATUS_SERIAL_NO_DEVICE_INITED", | ||
456 | NT_STATUS_SERIAL_NO_DEVICE_INITED}, | ||
457 | {"NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS}, | ||
458 | {"NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS}, | ||
459 | {"NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS}, | ||
460 | {"NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS}, | ||
461 | {"NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED}, | ||
462 | {"NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS}, | ||
463 | {"NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG}, | ||
464 | {"NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR}, | ||
465 | {"NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE}, | ||
466 | {"NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS}, | ||
467 | {"NT_STATUS_LOGON_TYPE_NOT_GRANTED", | ||
468 | NT_STATUS_LOGON_TYPE_NOT_GRANTED}, | ||
469 | {"NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE}, | ||
470 | {"NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED", | ||
471 | NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, | ||
472 | {"NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR", | ||
473 | NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, | ||
474 | {"NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER}, | ||
475 | {"NT_STATUS_ILL_FORMED_SERVICE_ENTRY", | ||
476 | NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, | ||
477 | {"NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER}, | ||
478 | {"NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER}, | ||
479 | {"NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER}, | ||
480 | {"NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME}, | ||
481 | {"NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND", | ||
482 | NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, | ||
483 | {"NT_STATUS_FLOPPY_WRONG_CYLINDER", | ||
484 | NT_STATUS_FLOPPY_WRONG_CYLINDER}, | ||
485 | {"NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR}, | ||
486 | {"NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS}, | ||
487 | {"NT_STATUS_DISK_RECALIBRATE_FAILED", | ||
488 | NT_STATUS_DISK_RECALIBRATE_FAILED}, | ||
489 | {"NT_STATUS_DISK_OPERATION_FAILED", | ||
490 | NT_STATUS_DISK_OPERATION_FAILED}, | ||
491 | {"NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED}, | ||
492 | {"NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY}, | ||
493 | {"NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING}, | ||
494 | {"NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE}, | ||
495 | {"NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH}, | ||
496 | {"NT_STATUS_DEVICE_NOT_PARTITIONED", | ||
497 | NT_STATUS_DEVICE_NOT_PARTITIONED}, | ||
498 | {"NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA}, | ||
499 | {"NT_STATUS_UNABLE_TO_UNLOAD_MEDIA", | ||
500 | NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, | ||
501 | {"NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW}, | ||
502 | {"NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA}, | ||
503 | {"NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER}, | ||
504 | {"NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER}, | ||
505 | {"NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED}, | ||
506 | {"NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE}, | ||
507 | {"NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS}, | ||
508 | {"NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED", | ||
509 | NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, | ||
510 | {"NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN}, | ||
511 | {"NT_STATUS_CHILD_MUST_BE_VOLATILE", | ||
512 | NT_STATUS_CHILD_MUST_BE_VOLATILE}, | ||
513 | {"NT_STATUS_DEVICE_CONFIGURATION_ERROR", | ||
514 | NT_STATUS_DEVICE_CONFIGURATION_ERROR}, | ||
515 | {"NT_STATUS_DRIVER_INTERNAL_ERROR", | ||
516 | NT_STATUS_DRIVER_INTERNAL_ERROR}, | ||
517 | {"NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE}, | ||
518 | {"NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR}, | ||
519 | {"NT_STATUS_DEVICE_PROTOCOL_ERROR", | ||
520 | NT_STATUS_DEVICE_PROTOCOL_ERROR}, | ||
521 | {"NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER}, | ||
522 | {"NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL}, | ||
523 | {"NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE}, | ||
524 | {"NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET}, | ||
525 | {"NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT}, | ||
526 | {"NT_STATUS_TRUSTED_DOMAIN_FAILURE", | ||
527 | NT_STATUS_TRUSTED_DOMAIN_FAILURE}, | ||
528 | {"NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE", | ||
529 | NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, | ||
530 | {"NT_STATUS_EVENTLOG_FILE_CORRUPT", | ||
531 | NT_STATUS_EVENTLOG_FILE_CORRUPT}, | ||
532 | {"NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START}, | ||
533 | {"NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE}, | ||
534 | {"NT_STATUS_MUTANT_LIMIT_EXCEEDED", | ||
535 | NT_STATUS_MUTANT_LIMIT_EXCEEDED}, | ||
536 | {"NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED}, | ||
537 | {"NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED}, | ||
538 | {"NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK}, | ||
539 | {"NT_STATUS_NETWORK_CREDENTIAL_CONFLICT", | ||
540 | NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, | ||
541 | {"NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT}, | ||
542 | {"NT_STATUS_EVENTLOG_FILE_CHANGED", | ||
543 | NT_STATUS_EVENTLOG_FILE_CHANGED}, | ||
544 | {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", | ||
545 | NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, | ||
546 | {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", | ||
547 | NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, | ||
548 | {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", | ||
549 | NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT}, | ||
550 | {"NT_STATUS_DOMAIN_TRUST_INCONSISTENT", | ||
551 | NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, | ||
552 | {"NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED}, | ||
553 | {"NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY}, | ||
554 | {"NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED}, | ||
555 | {"NT_STATUS_RESOURCE_LANG_NOT_FOUND", | ||
556 | NT_STATUS_RESOURCE_LANG_NOT_FOUND}, | ||
557 | {"NT_STATUS_INSUFF_SERVER_RESOURCES", | ||
558 | NT_STATUS_INSUFF_SERVER_RESOURCES}, | ||
559 | {"NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE}, | ||
560 | {"NT_STATUS_INVALID_ADDRESS_COMPONENT", | ||
561 | NT_STATUS_INVALID_ADDRESS_COMPONENT}, | ||
562 | {"NT_STATUS_INVALID_ADDRESS_WILDCARD", | ||
563 | NT_STATUS_INVALID_ADDRESS_WILDCARD}, | ||
564 | {"NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES}, | ||
565 | {"NT_STATUS_ADDRESS_ALREADY_EXISTS", | ||
566 | NT_STATUS_ADDRESS_ALREADY_EXISTS}, | ||
567 | {"NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED}, | ||
568 | {"NT_STATUS_CONNECTION_DISCONNECTED", | ||
569 | NT_STATUS_CONNECTION_DISCONNECTED}, | ||
570 | {"NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET}, | ||
571 | {"NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES}, | ||
572 | {"NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED}, | ||
573 | {"NT_STATUS_TRANSACTION_TIMED_OUT", | ||
574 | NT_STATUS_TRANSACTION_TIMED_OUT}, | ||
575 | {"NT_STATUS_TRANSACTION_NO_RELEASE", | ||
576 | NT_STATUS_TRANSACTION_NO_RELEASE}, | ||
577 | {"NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH}, | ||
578 | {"NT_STATUS_TRANSACTION_RESPONDED", | ||
579 | NT_STATUS_TRANSACTION_RESPONDED}, | ||
580 | {"NT_STATUS_TRANSACTION_INVALID_ID", | ||
581 | NT_STATUS_TRANSACTION_INVALID_ID}, | ||
582 | {"NT_STATUS_TRANSACTION_INVALID_TYPE", | ||
583 | NT_STATUS_TRANSACTION_INVALID_TYPE}, | ||
584 | {"NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION}, | ||
585 | {"NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION}, | ||
586 | {"NT_STATUS_CANNOT_LOAD_REGISTRY_FILE", | ||
587 | NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, | ||
588 | {"NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED}, | ||
589 | {"NT_STATUS_SYSTEM_PROCESS_TERMINATED", | ||
590 | NT_STATUS_SYSTEM_PROCESS_TERMINATED}, | ||
591 | {"NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED}, | ||
592 | {"NT_STATUS_NO_BROWSER_SERVERS_FOUND", | ||
593 | NT_STATUS_NO_BROWSER_SERVERS_FOUND}, | ||
594 | {"NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR}, | ||
595 | {"NT_STATUS_DRIVER_CANCEL_TIMEOUT", | ||
596 | NT_STATUS_DRIVER_CANCEL_TIMEOUT}, | ||
597 | {"NT_STATUS_REPLY_MESSAGE_MISMATCH", | ||
598 | NT_STATUS_REPLY_MESSAGE_MISMATCH}, | ||
599 | {"NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT}, | ||
600 | {"NT_STATUS_IMAGE_CHECKSUM_MISMATCH", | ||
601 | NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, | ||
602 | {"NT_STATUS_LOST_WRITEBEHIND_DATA", | ||
603 | NT_STATUS_LOST_WRITEBEHIND_DATA}, | ||
604 | {"NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID", | ||
605 | NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, | ||
606 | {"NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE}, | ||
607 | {"NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND}, | ||
608 | {"NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM}, | ||
609 | {"NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE}, | ||
610 | {"NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ}, | ||
611 | {"NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK}, | ||
612 | {"NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID}, | ||
613 | {"NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS}, | ||
614 | {"NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE}, | ||
615 | {"NT_STATUS_RETRY", NT_STATUS_RETRY}, | ||
616 | {"NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE}, | ||
617 | {"NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET}, | ||
618 | {"NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND}, | ||
619 | {"NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW}, | ||
620 | {"NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT}, | ||
621 | {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", | ||
622 | NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, | ||
623 | {"NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT}, | ||
624 | {"NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE}, | ||
625 | {"NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED}, | ||
626 | {"NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT}, | ||
627 | {"NT_STATUS_ADDRESS_ALREADY_ASSOCIATED", | ||
628 | NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, | ||
629 | {"NT_STATUS_ADDRESS_NOT_ASSOCIATED", | ||
630 | NT_STATUS_ADDRESS_NOT_ASSOCIATED}, | ||
631 | {"NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID}, | ||
632 | {"NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE}, | ||
633 | {"NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE}, | ||
634 | {"NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE}, | ||
635 | {"NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE}, | ||
636 | {"NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE}, | ||
637 | {"NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED}, | ||
638 | {"NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED}, | ||
639 | {"NT_STATUS_BAD_COMPRESSION_BUFFER", | ||
640 | NT_STATUS_BAD_COMPRESSION_BUFFER}, | ||
641 | {"NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE}, | ||
642 | {"NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED}, | ||
643 | {"NT_STATUS_TIMER_RESOLUTION_NOT_SET", | ||
644 | NT_STATUS_TIMER_RESOLUTION_NOT_SET}, | ||
645 | {"NT_STATUS_CONNECTION_COUNT_LIMIT", | ||
646 | NT_STATUS_CONNECTION_COUNT_LIMIT}, | ||
647 | {"NT_STATUS_LOGIN_TIME_RESTRICTION", | ||
648 | NT_STATUS_LOGIN_TIME_RESTRICTION}, | ||
649 | {"NT_STATUS_LOGIN_WKSTA_RESTRICTION", | ||
650 | NT_STATUS_LOGIN_WKSTA_RESTRICTION}, | ||
651 | {"NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH}, | ||
652 | {"NT_STATUS_INSUFFICIENT_LOGON_INFO", | ||
653 | NT_STATUS_INSUFFICIENT_LOGON_INFO}, | ||
654 | {"NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT}, | ||
655 | {"NT_STATUS_BAD_SERVICE_ENTRYPOINT", | ||
656 | NT_STATUS_BAD_SERVICE_ENTRYPOINT}, | ||
657 | {"NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST}, | ||
658 | {"NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1}, | ||
659 | {"NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2}, | ||
660 | {"NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT}, | ||
661 | {"NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED}, | ||
662 | {"NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE}, | ||
663 | {"NT_STATUS_LICENSE_QUOTA_EXCEEDED", | ||
664 | NT_STATUS_LICENSE_QUOTA_EXCEEDED}, | ||
665 | {"NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT}, | ||
666 | {"NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT}, | ||
667 | {"NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT}, | ||
668 | {"NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE}, | ||
669 | {"NT_STATUS_UNSUPPORTED_COMPRESSION", | ||
670 | NT_STATUS_UNSUPPORTED_COMPRESSION}, | ||
671 | {"NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE}, | ||
672 | {"NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH", | ||
673 | NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, | ||
674 | {"NT_STATUS_DRIVER_ORDINAL_NOT_FOUND", | ||
675 | NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, | ||
676 | {"NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", | ||
677 | NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, | ||
678 | {"NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED}, | ||
679 | {"NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS}, | ||
680 | {"NT_STATUS_QUOTA_LIST_INCONSISTENT", | ||
681 | NT_STATUS_QUOTA_LIST_INCONSISTENT}, | ||
682 | {"NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE}, | ||
683 | {"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES}, | ||
684 | {"STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES}, | ||
685 | {"STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED}, | ||
686 | {NULL, 0} | ||
687 | }; | ||
diff --git a/fs/cifs/nterr.h b/fs/cifs/nterr.h new file mode 100644 index 000000000000..d2fb06c97dfa --- /dev/null +++ b/fs/cifs/nterr.h | |||
@@ -0,0 +1,556 @@ | |||
1 | /* | ||
2 | Unix SMB/Netbios implementation. | ||
3 | Version 1.9. | ||
4 | NT error code constants | ||
5 | Copyright (C) Andrew Tridgell 1992-2000 | ||
6 | Copyright (C) John H Terpstra 1996-2000 | ||
7 | Copyright (C) Luke Kenneth Casson Leighton 1996-2000 | ||
8 | Copyright (C) Paul Ashton 1998-2000 | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | |||
26 | |||
27 | #ifndef _NTERR_H | ||
28 | #define _NTERR_H | ||
29 | |||
30 | struct nt_err_code_struct { | ||
31 | char *nt_errstr; | ||
32 | __u32 nt_errcode; | ||
33 | }; | ||
34 | |||
35 | extern const struct nt_err_code_struct nt_errs[]; | ||
36 | |||
37 | /* Win32 Status codes. */ | ||
38 | |||
39 | #define STATUS_BUFFER_OVERFLOW 0x80000005 | ||
40 | #define STATUS_MORE_ENTRIES 0x0105 | ||
41 | #define ERROR_INVALID_PARAMETER 0x0057 | ||
42 | #define ERROR_INSUFFICIENT_BUFFER 0x007a | ||
43 | #define STATUS_1804 0x070c | ||
44 | #define STATUS_NOTIFY_ENUM_DIR 0x010c | ||
45 | |||
46 | /* Win32 Error codes extracted using a loop in smbclient then printing a | ||
47 | netmon sniff to a file. */ | ||
48 | |||
49 | #define NT_STATUS_OK 0x0000 | ||
50 | #define STATUS_SOME_UNMAPPED 0x0107 | ||
51 | #define STATUS_BUFFER_OVERFLOW 0x80000005 | ||
52 | #define NT_STATUS_NO_MORE_ENTRIES 0x8000001a | ||
53 | #define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001 | ||
54 | #define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002 | ||
55 | #define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003 | ||
56 | #define NT_STATUS_INFO_LENGTH_MISMATCH 0xC0000000 | 0x0004 | ||
57 | #define NT_STATUS_ACCESS_VIOLATION 0xC0000000 | 0x0005 | ||
58 | #define NT_STATUS_IN_PAGE_ERROR 0xC0000000 | 0x0006 | ||
59 | #define NT_STATUS_PAGEFILE_QUOTA 0xC0000000 | 0x0007 | ||
60 | #define NT_STATUS_INVALID_HANDLE 0xC0000000 | 0x0008 | ||
61 | #define NT_STATUS_BAD_INITIAL_STACK 0xC0000000 | 0x0009 | ||
62 | #define NT_STATUS_BAD_INITIAL_PC 0xC0000000 | 0x000a | ||
63 | #define NT_STATUS_INVALID_CID 0xC0000000 | 0x000b | ||
64 | #define NT_STATUS_TIMER_NOT_CANCELED 0xC0000000 | 0x000c | ||
65 | #define NT_STATUS_INVALID_PARAMETER 0xC0000000 | 0x000d | ||
66 | #define NT_STATUS_NO_SUCH_DEVICE 0xC0000000 | 0x000e | ||
67 | #define NT_STATUS_NO_SUCH_FILE 0xC0000000 | 0x000f | ||
68 | #define NT_STATUS_INVALID_DEVICE_REQUEST 0xC0000000 | 0x0010 | ||
69 | #define NT_STATUS_END_OF_FILE 0xC0000000 | 0x0011 | ||
70 | #define NT_STATUS_WRONG_VOLUME 0xC0000000 | 0x0012 | ||
71 | #define NT_STATUS_NO_MEDIA_IN_DEVICE 0xC0000000 | 0x0013 | ||
72 | #define NT_STATUS_UNRECOGNIZED_MEDIA 0xC0000000 | 0x0014 | ||
73 | #define NT_STATUS_NONEXISTENT_SECTOR 0xC0000000 | 0x0015 | ||
74 | #define NT_STATUS_MORE_PROCESSING_REQUIRED 0xC0000000 | 0x0016 | ||
75 | #define NT_STATUS_NO_MEMORY 0xC0000000 | 0x0017 | ||
76 | #define NT_STATUS_CONFLICTING_ADDRESSES 0xC0000000 | 0x0018 | ||
77 | #define NT_STATUS_NOT_MAPPED_VIEW 0xC0000000 | 0x0019 | ||
78 | #define NT_STATUS_UNABLE_TO_FREE_VM 0x80000000 | 0x001a | ||
79 | #define NT_STATUS_UNABLE_TO_DELETE_SECTION 0xC0000000 | 0x001b | ||
80 | #define NT_STATUS_INVALID_SYSTEM_SERVICE 0xC0000000 | 0x001c | ||
81 | #define NT_STATUS_ILLEGAL_INSTRUCTION 0xC0000000 | 0x001d | ||
82 | #define NT_STATUS_INVALID_LOCK_SEQUENCE 0xC0000000 | 0x001e | ||
83 | #define NT_STATUS_INVALID_VIEW_SIZE 0xC0000000 | 0x001f | ||
84 | #define NT_STATUS_INVALID_FILE_FOR_SECTION 0xC0000000 | 0x0020 | ||
85 | #define NT_STATUS_ALREADY_COMMITTED 0xC0000000 | 0x0021 | ||
86 | #define NT_STATUS_ACCESS_DENIED 0xC0000000 | 0x0022 | ||
87 | #define NT_STATUS_BUFFER_TOO_SMALL 0xC0000000 | 0x0023 | ||
88 | #define NT_STATUS_OBJECT_TYPE_MISMATCH 0xC0000000 | 0x0024 | ||
89 | #define NT_STATUS_NONCONTINUABLE_EXCEPTION 0xC0000000 | 0x0025 | ||
90 | #define NT_STATUS_INVALID_DISPOSITION 0xC0000000 | 0x0026 | ||
91 | #define NT_STATUS_UNWIND 0xC0000000 | 0x0027 | ||
92 | #define NT_STATUS_BAD_STACK 0xC0000000 | 0x0028 | ||
93 | #define NT_STATUS_INVALID_UNWIND_TARGET 0xC0000000 | 0x0029 | ||
94 | #define NT_STATUS_NOT_LOCKED 0xC0000000 | 0x002a | ||
95 | #define NT_STATUS_PARITY_ERROR 0xC0000000 | 0x002b | ||
96 | #define NT_STATUS_UNABLE_TO_DECOMMIT_VM 0xC0000000 | 0x002c | ||
97 | #define NT_STATUS_NOT_COMMITTED 0xC0000000 | 0x002d | ||
98 | #define NT_STATUS_INVALID_PORT_ATTRIBUTES 0xC0000000 | 0x002e | ||
99 | #define NT_STATUS_PORT_MESSAGE_TOO_LONG 0xC0000000 | 0x002f | ||
100 | #define NT_STATUS_INVALID_PARAMETER_MIX 0xC0000000 | 0x0030 | ||
101 | #define NT_STATUS_INVALID_QUOTA_LOWER 0xC0000000 | 0x0031 | ||
102 | #define NT_STATUS_DISK_CORRUPT_ERROR 0xC0000000 | 0x0032 | ||
103 | #define NT_STATUS_OBJECT_NAME_INVALID 0xC0000000 | 0x0033 | ||
104 | #define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000000 | 0x0034 | ||
105 | #define NT_STATUS_OBJECT_NAME_COLLISION 0xC0000000 | 0x0035 | ||
106 | #define NT_STATUS_HANDLE_NOT_WAITABLE 0xC0000000 | 0x0036 | ||
107 | #define NT_STATUS_PORT_DISCONNECTED 0xC0000000 | 0x0037 | ||
108 | #define NT_STATUS_DEVICE_ALREADY_ATTACHED 0xC0000000 | 0x0038 | ||
109 | #define NT_STATUS_OBJECT_PATH_INVALID 0xC0000000 | 0x0039 | ||
110 | #define NT_STATUS_OBJECT_PATH_NOT_FOUND 0xC0000000 | 0x003a | ||
111 | #define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 0xC0000000 | 0x003b | ||
112 | #define NT_STATUS_DATA_OVERRUN 0xC0000000 | 0x003c | ||
113 | #define NT_STATUS_DATA_LATE_ERROR 0xC0000000 | 0x003d | ||
114 | #define NT_STATUS_DATA_ERROR 0xC0000000 | 0x003e | ||
115 | #define NT_STATUS_CRC_ERROR 0xC0000000 | 0x003f | ||
116 | #define NT_STATUS_SECTION_TOO_BIG 0xC0000000 | 0x0040 | ||
117 | #define NT_STATUS_PORT_CONNECTION_REFUSED 0xC0000000 | 0x0041 | ||
118 | #define NT_STATUS_INVALID_PORT_HANDLE 0xC0000000 | 0x0042 | ||
119 | #define NT_STATUS_SHARING_VIOLATION 0xC0000000 | 0x0043 | ||
120 | #define NT_STATUS_QUOTA_EXCEEDED 0xC0000000 | 0x0044 | ||
121 | #define NT_STATUS_INVALID_PAGE_PROTECTION 0xC0000000 | 0x0045 | ||
122 | #define NT_STATUS_MUTANT_NOT_OWNED 0xC0000000 | 0x0046 | ||
123 | #define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000000 | 0x0047 | ||
124 | #define NT_STATUS_PORT_ALREADY_SET 0xC0000000 | 0x0048 | ||
125 | #define NT_STATUS_SECTION_NOT_IMAGE 0xC0000000 | 0x0049 | ||
126 | #define NT_STATUS_SUSPEND_COUNT_EXCEEDED 0xC0000000 | 0x004a | ||
127 | #define NT_STATUS_THREAD_IS_TERMINATING 0xC0000000 | 0x004b | ||
128 | #define NT_STATUS_BAD_WORKING_SET_LIMIT 0xC0000000 | 0x004c | ||
129 | #define NT_STATUS_INCOMPATIBLE_FILE_MAP 0xC0000000 | 0x004d | ||
130 | #define NT_STATUS_SECTION_PROTECTION 0xC0000000 | 0x004e | ||
131 | #define NT_STATUS_EAS_NOT_SUPPORTED 0xC0000000 | 0x004f | ||
132 | #define NT_STATUS_EA_TOO_LARGE 0xC0000000 | 0x0050 | ||
133 | #define NT_STATUS_NONEXISTENT_EA_ENTRY 0xC0000000 | 0x0051 | ||
134 | #define NT_STATUS_NO_EAS_ON_FILE 0xC0000000 | 0x0052 | ||
135 | #define NT_STATUS_EA_CORRUPT_ERROR 0xC0000000 | 0x0053 | ||
136 | #define NT_STATUS_FILE_LOCK_CONFLICT 0xC0000000 | 0x0054 | ||
137 | #define NT_STATUS_LOCK_NOT_GRANTED 0xC0000000 | 0x0055 | ||
138 | #define NT_STATUS_DELETE_PENDING 0xC0000000 | 0x0056 | ||
139 | #define NT_STATUS_CTL_FILE_NOT_SUPPORTED 0xC0000000 | 0x0057 | ||
140 | #define NT_STATUS_UNKNOWN_REVISION 0xC0000000 | 0x0058 | ||
141 | #define NT_STATUS_REVISION_MISMATCH 0xC0000000 | 0x0059 | ||
142 | #define NT_STATUS_INVALID_OWNER 0xC0000000 | 0x005a | ||
143 | #define NT_STATUS_INVALID_PRIMARY_GROUP 0xC0000000 | 0x005b | ||
144 | #define NT_STATUS_NO_IMPERSONATION_TOKEN 0xC0000000 | 0x005c | ||
145 | #define NT_STATUS_CANT_DISABLE_MANDATORY 0xC0000000 | 0x005d | ||
146 | #define NT_STATUS_NO_LOGON_SERVERS 0xC0000000 | 0x005e | ||
147 | #define NT_STATUS_NO_SUCH_LOGON_SESSION 0xC0000000 | 0x005f | ||
148 | #define NT_STATUS_NO_SUCH_PRIVILEGE 0xC0000000 | 0x0060 | ||
149 | #define NT_STATUS_PRIVILEGE_NOT_HELD 0xC0000000 | 0x0061 | ||
150 | #define NT_STATUS_INVALID_ACCOUNT_NAME 0xC0000000 | 0x0062 | ||
151 | #define NT_STATUS_USER_EXISTS 0xC0000000 | 0x0063 | ||
152 | #define NT_STATUS_NO_SUCH_USER 0xC0000000 | 0x0064 | ||
153 | #define NT_STATUS_GROUP_EXISTS 0xC0000000 | 0x0065 | ||
154 | #define NT_STATUS_NO_SUCH_GROUP 0xC0000000 | 0x0066 | ||
155 | #define NT_STATUS_MEMBER_IN_GROUP 0xC0000000 | 0x0067 | ||
156 | #define NT_STATUS_MEMBER_NOT_IN_GROUP 0xC0000000 | 0x0068 | ||
157 | #define NT_STATUS_LAST_ADMIN 0xC0000000 | 0x0069 | ||
158 | #define NT_STATUS_WRONG_PASSWORD 0xC0000000 | 0x006a | ||
159 | #define NT_STATUS_ILL_FORMED_PASSWORD 0xC0000000 | 0x006b | ||
160 | #define NT_STATUS_PASSWORD_RESTRICTION 0xC0000000 | 0x006c | ||
161 | #define NT_STATUS_LOGON_FAILURE 0xC0000000 | 0x006d | ||
162 | #define NT_STATUS_ACCOUNT_RESTRICTION 0xC0000000 | 0x006e | ||
163 | #define NT_STATUS_INVALID_LOGON_HOURS 0xC0000000 | 0x006f | ||
164 | #define NT_STATUS_INVALID_WORKSTATION 0xC0000000 | 0x0070 | ||
165 | #define NT_STATUS_PASSWORD_EXPIRED 0xC0000000 | 0x0071 | ||
166 | #define NT_STATUS_ACCOUNT_DISABLED 0xC0000000 | 0x0072 | ||
167 | #define NT_STATUS_NONE_MAPPED 0xC0000000 | 0x0073 | ||
168 | #define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 0xC0000000 | 0x0074 | ||
169 | #define NT_STATUS_LUIDS_EXHAUSTED 0xC0000000 | 0x0075 | ||
170 | #define NT_STATUS_INVALID_SUB_AUTHORITY 0xC0000000 | 0x0076 | ||
171 | #define NT_STATUS_INVALID_ACL 0xC0000000 | 0x0077 | ||
172 | #define NT_STATUS_INVALID_SID 0xC0000000 | 0x0078 | ||
173 | #define NT_STATUS_INVALID_SECURITY_DESCR 0xC0000000 | 0x0079 | ||
174 | #define NT_STATUS_PROCEDURE_NOT_FOUND 0xC0000000 | 0x007a | ||
175 | #define NT_STATUS_INVALID_IMAGE_FORMAT 0xC0000000 | 0x007b | ||
176 | #define NT_STATUS_NO_TOKEN 0xC0000000 | 0x007c | ||
177 | #define NT_STATUS_BAD_INHERITANCE_ACL 0xC0000000 | 0x007d | ||
178 | #define NT_STATUS_RANGE_NOT_LOCKED 0xC0000000 | 0x007e | ||
179 | #define NT_STATUS_DISK_FULL 0xC0000000 | 0x007f | ||
180 | #define NT_STATUS_SERVER_DISABLED 0xC0000000 | 0x0080 | ||
181 | #define NT_STATUS_SERVER_NOT_DISABLED 0xC0000000 | 0x0081 | ||
182 | #define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 0xC0000000 | 0x0082 | ||
183 | #define NT_STATUS_GUIDS_EXHAUSTED 0xC0000000 | 0x0083 | ||
184 | #define NT_STATUS_INVALID_ID_AUTHORITY 0xC0000000 | 0x0084 | ||
185 | #define NT_STATUS_AGENTS_EXHAUSTED 0xC0000000 | 0x0085 | ||
186 | #define NT_STATUS_INVALID_VOLUME_LABEL 0xC0000000 | 0x0086 | ||
187 | #define NT_STATUS_SECTION_NOT_EXTENDED 0xC0000000 | 0x0087 | ||
188 | #define NT_STATUS_NOT_MAPPED_DATA 0xC0000000 | 0x0088 | ||
189 | #define NT_STATUS_RESOURCE_DATA_NOT_FOUND 0xC0000000 | 0x0089 | ||
190 | #define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 0xC0000000 | 0x008a | ||
191 | #define NT_STATUS_RESOURCE_NAME_NOT_FOUND 0xC0000000 | 0x008b | ||
192 | #define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 0xC0000000 | 0x008c | ||
193 | #define NT_STATUS_FLOAT_DENORMAL_OPERAND 0xC0000000 | 0x008d | ||
194 | #define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 0xC0000000 | 0x008e | ||
195 | #define NT_STATUS_FLOAT_INEXACT_RESULT 0xC0000000 | 0x008f | ||
196 | #define NT_STATUS_FLOAT_INVALID_OPERATION 0xC0000000 | 0x0090 | ||
197 | #define NT_STATUS_FLOAT_OVERFLOW 0xC0000000 | 0x0091 | ||
198 | #define NT_STATUS_FLOAT_STACK_CHECK 0xC0000000 | 0x0092 | ||
199 | #define NT_STATUS_FLOAT_UNDERFLOW 0xC0000000 | 0x0093 | ||
200 | #define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000000 | 0x0094 | ||
201 | #define NT_STATUS_INTEGER_OVERFLOW 0xC0000000 | 0x0095 | ||
202 | #define NT_STATUS_PRIVILEGED_INSTRUCTION 0xC0000000 | 0x0096 | ||
203 | #define NT_STATUS_TOO_MANY_PAGING_FILES 0xC0000000 | 0x0097 | ||
204 | #define NT_STATUS_FILE_INVALID 0xC0000000 | 0x0098 | ||
205 | #define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 0xC0000000 | 0x0099 | ||
206 | #define NT_STATUS_INSUFFICIENT_RESOURCES 0xC0000000 | 0x009a | ||
207 | #define NT_STATUS_DFS_EXIT_PATH_FOUND 0xC0000000 | 0x009b | ||
208 | #define NT_STATUS_DEVICE_DATA_ERROR 0xC0000000 | 0x009c | ||
209 | #define NT_STATUS_DEVICE_NOT_CONNECTED 0xC0000000 | 0x009d | ||
210 | #define NT_STATUS_DEVICE_POWER_FAILURE 0xC0000000 | 0x009e | ||
211 | #define NT_STATUS_FREE_VM_NOT_AT_BASE 0xC0000000 | 0x009f | ||
212 | #define NT_STATUS_MEMORY_NOT_ALLOCATED 0xC0000000 | 0x00a0 | ||
213 | #define NT_STATUS_WORKING_SET_QUOTA 0xC0000000 | 0x00a1 | ||
214 | #define NT_STATUS_MEDIA_WRITE_PROTECTED 0xC0000000 | 0x00a2 | ||
215 | #define NT_STATUS_DEVICE_NOT_READY 0xC0000000 | 0x00a3 | ||
216 | #define NT_STATUS_INVALID_GROUP_ATTRIBUTES 0xC0000000 | 0x00a4 | ||
217 | #define NT_STATUS_BAD_IMPERSONATION_LEVEL 0xC0000000 | 0x00a5 | ||
218 | #define NT_STATUS_CANT_OPEN_ANONYMOUS 0xC0000000 | 0x00a6 | ||
219 | #define NT_STATUS_BAD_VALIDATION_CLASS 0xC0000000 | 0x00a7 | ||
220 | #define NT_STATUS_BAD_TOKEN_TYPE 0xC0000000 | 0x00a8 | ||
221 | #define NT_STATUS_BAD_MASTER_BOOT_RECORD 0xC0000000 | 0x00a9 | ||
222 | #define NT_STATUS_INSTRUCTION_MISALIGNMENT 0xC0000000 | 0x00aa | ||
223 | #define NT_STATUS_INSTANCE_NOT_AVAILABLE 0xC0000000 | 0x00ab | ||
224 | #define NT_STATUS_PIPE_NOT_AVAILABLE 0xC0000000 | 0x00ac | ||
225 | #define NT_STATUS_INVALID_PIPE_STATE 0xC0000000 | 0x00ad | ||
226 | #define NT_STATUS_PIPE_BUSY 0xC0000000 | 0x00ae | ||
227 | #define NT_STATUS_ILLEGAL_FUNCTION 0xC0000000 | 0x00af | ||
228 | #define NT_STATUS_PIPE_DISCONNECTED 0xC0000000 | 0x00b0 | ||
229 | #define NT_STATUS_PIPE_CLOSING 0xC0000000 | 0x00b1 | ||
230 | #define NT_STATUS_PIPE_CONNECTED 0xC0000000 | 0x00b2 | ||
231 | #define NT_STATUS_PIPE_LISTENING 0xC0000000 | 0x00b3 | ||
232 | #define NT_STATUS_INVALID_READ_MODE 0xC0000000 | 0x00b4 | ||
233 | #define NT_STATUS_IO_TIMEOUT 0xC0000000 | 0x00b5 | ||
234 | #define NT_STATUS_FILE_FORCED_CLOSED 0xC0000000 | 0x00b6 | ||
235 | #define NT_STATUS_PROFILING_NOT_STARTED 0xC0000000 | 0x00b7 | ||
236 | #define NT_STATUS_PROFILING_NOT_STOPPED 0xC0000000 | 0x00b8 | ||
237 | #define NT_STATUS_COULD_NOT_INTERPRET 0xC0000000 | 0x00b9 | ||
238 | #define NT_STATUS_FILE_IS_A_DIRECTORY 0xC0000000 | 0x00ba | ||
239 | #define NT_STATUS_NOT_SUPPORTED 0xC0000000 | 0x00bb | ||
240 | #define NT_STATUS_REMOTE_NOT_LISTENING 0xC0000000 | 0x00bc | ||
241 | #define NT_STATUS_DUPLICATE_NAME 0xC0000000 | 0x00bd | ||
242 | #define NT_STATUS_BAD_NETWORK_PATH 0xC0000000 | 0x00be | ||
243 | #define NT_STATUS_NETWORK_BUSY 0xC0000000 | 0x00bf | ||
244 | #define NT_STATUS_DEVICE_DOES_NOT_EXIST 0xC0000000 | 0x00c0 | ||
245 | #define NT_STATUS_TOO_MANY_COMMANDS 0xC0000000 | 0x00c1 | ||
246 | #define NT_STATUS_ADAPTER_HARDWARE_ERROR 0xC0000000 | 0x00c2 | ||
247 | #define NT_STATUS_INVALID_NETWORK_RESPONSE 0xC0000000 | 0x00c3 | ||
248 | #define NT_STATUS_UNEXPECTED_NETWORK_ERROR 0xC0000000 | 0x00c4 | ||
249 | #define NT_STATUS_BAD_REMOTE_ADAPTER 0xC0000000 | 0x00c5 | ||
250 | #define NT_STATUS_PRINT_QUEUE_FULL 0xC0000000 | 0x00c6 | ||
251 | #define NT_STATUS_NO_SPOOL_SPACE 0xC0000000 | 0x00c7 | ||
252 | #define NT_STATUS_PRINT_CANCELLED 0xC0000000 | 0x00c8 | ||
253 | #define NT_STATUS_NETWORK_NAME_DELETED 0xC0000000 | 0x00c9 | ||
254 | #define NT_STATUS_NETWORK_ACCESS_DENIED 0xC0000000 | 0x00ca | ||
255 | #define NT_STATUS_BAD_DEVICE_TYPE 0xC0000000 | 0x00cb | ||
256 | #define NT_STATUS_BAD_NETWORK_NAME 0xC0000000 | 0x00cc | ||
257 | #define NT_STATUS_TOO_MANY_NAMES 0xC0000000 | 0x00cd | ||
258 | #define NT_STATUS_TOO_MANY_SESSIONS 0xC0000000 | 0x00ce | ||
259 | #define NT_STATUS_SHARING_PAUSED 0xC0000000 | 0x00cf | ||
260 | #define NT_STATUS_REQUEST_NOT_ACCEPTED 0xC0000000 | 0x00d0 | ||
261 | #define NT_STATUS_REDIRECTOR_PAUSED 0xC0000000 | 0x00d1 | ||
262 | #define NT_STATUS_NET_WRITE_FAULT 0xC0000000 | 0x00d2 | ||
263 | #define NT_STATUS_PROFILING_AT_LIMIT 0xC0000000 | 0x00d3 | ||
264 | #define NT_STATUS_NOT_SAME_DEVICE 0xC0000000 | 0x00d4 | ||
265 | #define NT_STATUS_FILE_RENAMED 0xC0000000 | 0x00d5 | ||
266 | #define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 0xC0000000 | 0x00d6 | ||
267 | #define NT_STATUS_NO_SECURITY_ON_OBJECT 0xC0000000 | 0x00d7 | ||
268 | #define NT_STATUS_CANT_WAIT 0xC0000000 | 0x00d8 | ||
269 | #define NT_STATUS_PIPE_EMPTY 0xC0000000 | 0x00d9 | ||
270 | #define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 0xC0000000 | 0x00da | ||
271 | #define NT_STATUS_CANT_TERMINATE_SELF 0xC0000000 | 0x00db | ||
272 | #define NT_STATUS_INVALID_SERVER_STATE 0xC0000000 | 0x00dc | ||
273 | #define NT_STATUS_INVALID_DOMAIN_STATE 0xC0000000 | 0x00dd | ||
274 | #define NT_STATUS_INVALID_DOMAIN_ROLE 0xC0000000 | 0x00de | ||
275 | #define NT_STATUS_NO_SUCH_DOMAIN 0xC0000000 | 0x00df | ||
276 | #define NT_STATUS_DOMAIN_EXISTS 0xC0000000 | 0x00e0 | ||
277 | #define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 0xC0000000 | 0x00e1 | ||
278 | #define NT_STATUS_OPLOCK_NOT_GRANTED 0xC0000000 | 0x00e2 | ||
279 | #define NT_STATUS_INVALID_OPLOCK_PROTOCOL 0xC0000000 | 0x00e3 | ||
280 | #define NT_STATUS_INTERNAL_DB_CORRUPTION 0xC0000000 | 0x00e4 | ||
281 | #define NT_STATUS_INTERNAL_ERROR 0xC0000000 | 0x00e5 | ||
282 | #define NT_STATUS_GENERIC_NOT_MAPPED 0xC0000000 | 0x00e6 | ||
283 | #define NT_STATUS_BAD_DESCRIPTOR_FORMAT 0xC0000000 | 0x00e7 | ||
284 | #define NT_STATUS_INVALID_USER_BUFFER 0xC0000000 | 0x00e8 | ||
285 | #define NT_STATUS_UNEXPECTED_IO_ERROR 0xC0000000 | 0x00e9 | ||
286 | #define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 0xC0000000 | 0x00ea | ||
287 | #define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 0xC0000000 | 0x00eb | ||
288 | #define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 0xC0000000 | 0x00ec | ||
289 | #define NT_STATUS_NOT_LOGON_PROCESS 0xC0000000 | 0x00ed | ||
290 | #define NT_STATUS_LOGON_SESSION_EXISTS 0xC0000000 | 0x00ee | ||
291 | #define NT_STATUS_INVALID_PARAMETER_1 0xC0000000 | 0x00ef | ||
292 | #define NT_STATUS_INVALID_PARAMETER_2 0xC0000000 | 0x00f0 | ||
293 | #define NT_STATUS_INVALID_PARAMETER_3 0xC0000000 | 0x00f1 | ||
294 | #define NT_STATUS_INVALID_PARAMETER_4 0xC0000000 | 0x00f2 | ||
295 | #define NT_STATUS_INVALID_PARAMETER_5 0xC0000000 | 0x00f3 | ||
296 | #define NT_STATUS_INVALID_PARAMETER_6 0xC0000000 | 0x00f4 | ||
297 | #define NT_STATUS_INVALID_PARAMETER_7 0xC0000000 | 0x00f5 | ||
298 | #define NT_STATUS_INVALID_PARAMETER_8 0xC0000000 | 0x00f6 | ||
299 | #define NT_STATUS_INVALID_PARAMETER_9 0xC0000000 | 0x00f7 | ||
300 | #define NT_STATUS_INVALID_PARAMETER_10 0xC0000000 | 0x00f8 | ||
301 | #define NT_STATUS_INVALID_PARAMETER_11 0xC0000000 | 0x00f9 | ||
302 | #define NT_STATUS_INVALID_PARAMETER_12 0xC0000000 | 0x00fa | ||
303 | #define NT_STATUS_REDIRECTOR_NOT_STARTED 0xC0000000 | 0x00fb | ||
304 | #define NT_STATUS_REDIRECTOR_STARTED 0xC0000000 | 0x00fc | ||
305 | #define NT_STATUS_STACK_OVERFLOW 0xC0000000 | 0x00fd | ||
306 | #define NT_STATUS_NO_SUCH_PACKAGE 0xC0000000 | 0x00fe | ||
307 | #define NT_STATUS_BAD_FUNCTION_TABLE 0xC0000000 | 0x00ff | ||
308 | #define NT_STATUS_DIRECTORY_NOT_EMPTY 0xC0000000 | 0x0101 | ||
309 | #define NT_STATUS_FILE_CORRUPT_ERROR 0xC0000000 | 0x0102 | ||
310 | #define NT_STATUS_NOT_A_DIRECTORY 0xC0000000 | 0x0103 | ||
311 | #define NT_STATUS_BAD_LOGON_SESSION_STATE 0xC0000000 | 0x0104 | ||
312 | #define NT_STATUS_LOGON_SESSION_COLLISION 0xC0000000 | 0x0105 | ||
313 | #define NT_STATUS_NAME_TOO_LONG 0xC0000000 | 0x0106 | ||
314 | #define NT_STATUS_FILES_OPEN 0xC0000000 | 0x0107 | ||
315 | #define NT_STATUS_CONNECTION_IN_USE 0xC0000000 | 0x0108 | ||
316 | #define NT_STATUS_MESSAGE_NOT_FOUND 0xC0000000 | 0x0109 | ||
317 | #define NT_STATUS_PROCESS_IS_TERMINATING 0xC0000000 | 0x010a | ||
318 | #define NT_STATUS_INVALID_LOGON_TYPE 0xC0000000 | 0x010b | ||
319 | #define NT_STATUS_NO_GUID_TRANSLATION 0xC0000000 | 0x010c | ||
320 | #define NT_STATUS_CANNOT_IMPERSONATE 0xC0000000 | 0x010d | ||
321 | #define NT_STATUS_IMAGE_ALREADY_LOADED 0xC0000000 | 0x010e | ||
322 | #define NT_STATUS_ABIOS_NOT_PRESENT 0xC0000000 | 0x010f | ||
323 | #define NT_STATUS_ABIOS_LID_NOT_EXIST 0xC0000000 | 0x0110 | ||
324 | #define NT_STATUS_ABIOS_LID_ALREADY_OWNED 0xC0000000 | 0x0111 | ||
325 | #define NT_STATUS_ABIOS_NOT_LID_OWNER 0xC0000000 | 0x0112 | ||
326 | #define NT_STATUS_ABIOS_INVALID_COMMAND 0xC0000000 | 0x0113 | ||
327 | #define NT_STATUS_ABIOS_INVALID_LID 0xC0000000 | 0x0114 | ||
328 | #define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0xC0000000 | 0x0115 | ||
329 | #define NT_STATUS_ABIOS_INVALID_SELECTOR 0xC0000000 | 0x0116 | ||
330 | #define NT_STATUS_NO_LDT 0xC0000000 | 0x0117 | ||
331 | #define NT_STATUS_INVALID_LDT_SIZE 0xC0000000 | 0x0118 | ||
332 | #define NT_STATUS_INVALID_LDT_OFFSET 0xC0000000 | 0x0119 | ||
333 | #define NT_STATUS_INVALID_LDT_DESCRIPTOR 0xC0000000 | 0x011a | ||
334 | #define NT_STATUS_INVALID_IMAGE_NE_FORMAT 0xC0000000 | 0x011b | ||
335 | #define NT_STATUS_RXACT_INVALID_STATE 0xC0000000 | 0x011c | ||
336 | #define NT_STATUS_RXACT_COMMIT_FAILURE 0xC0000000 | 0x011d | ||
337 | #define NT_STATUS_MAPPED_FILE_SIZE_ZERO 0xC0000000 | 0x011e | ||
338 | #define NT_STATUS_TOO_MANY_OPENED_FILES 0xC0000000 | 0x011f | ||
339 | #define NT_STATUS_CANCELLED 0xC0000000 | 0x0120 | ||
340 | #define NT_STATUS_CANNOT_DELETE 0xC0000000 | 0x0121 | ||
341 | #define NT_STATUS_INVALID_COMPUTER_NAME 0xC0000000 | 0x0122 | ||
342 | #define NT_STATUS_FILE_DELETED 0xC0000000 | 0x0123 | ||
343 | #define NT_STATUS_SPECIAL_ACCOUNT 0xC0000000 | 0x0124 | ||
344 | #define NT_STATUS_SPECIAL_GROUP 0xC0000000 | 0x0125 | ||
345 | #define NT_STATUS_SPECIAL_USER 0xC0000000 | 0x0126 | ||
346 | #define NT_STATUS_MEMBERS_PRIMARY_GROUP 0xC0000000 | 0x0127 | ||
347 | #define NT_STATUS_FILE_CLOSED 0xC0000000 | 0x0128 | ||
348 | #define NT_STATUS_TOO_MANY_THREADS 0xC0000000 | 0x0129 | ||
349 | #define NT_STATUS_THREAD_NOT_IN_PROCESS 0xC0000000 | 0x012a | ||
350 | #define NT_STATUS_TOKEN_ALREADY_IN_USE 0xC0000000 | 0x012b | ||
351 | #define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 0xC0000000 | 0x012c | ||
352 | #define NT_STATUS_COMMITMENT_LIMIT 0xC0000000 | 0x012d | ||
353 | #define NT_STATUS_INVALID_IMAGE_LE_FORMAT 0xC0000000 | 0x012e | ||
354 | #define NT_STATUS_INVALID_IMAGE_NOT_MZ 0xC0000000 | 0x012f | ||
355 | #define NT_STATUS_INVALID_IMAGE_PROTECT 0xC0000000 | 0x0130 | ||
356 | #define NT_STATUS_INVALID_IMAGE_WIN_16 0xC0000000 | 0x0131 | ||
357 | #define NT_STATUS_LOGON_SERVER_CONFLICT 0xC0000000 | 0x0132 | ||
358 | #define NT_STATUS_TIME_DIFFERENCE_AT_DC 0xC0000000 | 0x0133 | ||
359 | #define NT_STATUS_SYNCHRONIZATION_REQUIRED 0xC0000000 | 0x0134 | ||
360 | #define NT_STATUS_DLL_NOT_FOUND 0xC0000000 | 0x0135 | ||
361 | #define NT_STATUS_OPEN_FAILED 0xC0000000 | 0x0136 | ||
362 | #define NT_STATUS_IO_PRIVILEGE_FAILED 0xC0000000 | 0x0137 | ||
363 | #define NT_STATUS_ORDINAL_NOT_FOUND 0xC0000000 | 0x0138 | ||
364 | #define NT_STATUS_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0139 | ||
365 | #define NT_STATUS_CONTROL_C_EXIT 0xC0000000 | 0x013a | ||
366 | #define NT_STATUS_LOCAL_DISCONNECT 0xC0000000 | 0x013b | ||
367 | #define NT_STATUS_REMOTE_DISCONNECT 0xC0000000 | 0x013c | ||
368 | #define NT_STATUS_REMOTE_RESOURCES 0xC0000000 | 0x013d | ||
369 | #define NT_STATUS_LINK_FAILED 0xC0000000 | 0x013e | ||
370 | #define NT_STATUS_LINK_TIMEOUT 0xC0000000 | 0x013f | ||
371 | #define NT_STATUS_INVALID_CONNECTION 0xC0000000 | 0x0140 | ||
372 | #define NT_STATUS_INVALID_ADDRESS 0xC0000000 | 0x0141 | ||
373 | #define NT_STATUS_DLL_INIT_FAILED 0xC0000000 | 0x0142 | ||
374 | #define NT_STATUS_MISSING_SYSTEMFILE 0xC0000000 | 0x0143 | ||
375 | #define NT_STATUS_UNHANDLED_EXCEPTION 0xC0000000 | 0x0144 | ||
376 | #define NT_STATUS_APP_INIT_FAILURE 0xC0000000 | 0x0145 | ||
377 | #define NT_STATUS_PAGEFILE_CREATE_FAILED 0xC0000000 | 0x0146 | ||
378 | #define NT_STATUS_NO_PAGEFILE 0xC0000000 | 0x0147 | ||
379 | #define NT_STATUS_INVALID_LEVEL 0xC0000000 | 0x0148 | ||
380 | #define NT_STATUS_WRONG_PASSWORD_CORE 0xC0000000 | 0x0149 | ||
381 | #define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 0xC0000000 | 0x014a | ||
382 | #define NT_STATUS_PIPE_BROKEN 0xC0000000 | 0x014b | ||
383 | #define NT_STATUS_REGISTRY_CORRUPT 0xC0000000 | 0x014c | ||
384 | #define NT_STATUS_REGISTRY_IO_FAILED 0xC0000000 | 0x014d | ||
385 | #define NT_STATUS_NO_EVENT_PAIR 0xC0000000 | 0x014e | ||
386 | #define NT_STATUS_UNRECOGNIZED_VOLUME 0xC0000000 | 0x014f | ||
387 | #define NT_STATUS_SERIAL_NO_DEVICE_INITED 0xC0000000 | 0x0150 | ||
388 | #define NT_STATUS_NO_SUCH_ALIAS 0xC0000000 | 0x0151 | ||
389 | #define NT_STATUS_MEMBER_NOT_IN_ALIAS 0xC0000000 | 0x0152 | ||
390 | #define NT_STATUS_MEMBER_IN_ALIAS 0xC0000000 | 0x0153 | ||
391 | #define NT_STATUS_ALIAS_EXISTS 0xC0000000 | 0x0154 | ||
392 | #define NT_STATUS_LOGON_NOT_GRANTED 0xC0000000 | 0x0155 | ||
393 | #define NT_STATUS_TOO_MANY_SECRETS 0xC0000000 | 0x0156 | ||
394 | #define NT_STATUS_SECRET_TOO_LONG 0xC0000000 | 0x0157 | ||
395 | #define NT_STATUS_INTERNAL_DB_ERROR 0xC0000000 | 0x0158 | ||
396 | #define NT_STATUS_FULLSCREEN_MODE 0xC0000000 | 0x0159 | ||
397 | #define NT_STATUS_TOO_MANY_CONTEXT_IDS 0xC0000000 | 0x015a | ||
398 | #define NT_STATUS_LOGON_TYPE_NOT_GRANTED 0xC0000000 | 0x015b | ||
399 | #define NT_STATUS_NOT_REGISTRY_FILE 0xC0000000 | 0x015c | ||
400 | #define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x015d | ||
401 | #define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0xC0000000 | 0x015e | ||
402 | #define NT_STATUS_FT_MISSING_MEMBER 0xC0000000 | 0x015f | ||
403 | #define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 0xC0000000 | 0x0160 | ||
404 | #define NT_STATUS_ILLEGAL_CHARACTER 0xC0000000 | 0x0161 | ||
405 | #define NT_STATUS_UNMAPPABLE_CHARACTER 0xC0000000 | 0x0162 | ||
406 | #define NT_STATUS_UNDEFINED_CHARACTER 0xC0000000 | 0x0163 | ||
407 | #define NT_STATUS_FLOPPY_VOLUME 0xC0000000 | 0x0164 | ||
408 | #define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 0xC0000000 | 0x0165 | ||
409 | #define NT_STATUS_FLOPPY_WRONG_CYLINDER 0xC0000000 | 0x0166 | ||
410 | #define NT_STATUS_FLOPPY_UNKNOWN_ERROR 0xC0000000 | 0x0167 | ||
411 | #define NT_STATUS_FLOPPY_BAD_REGISTERS 0xC0000000 | 0x0168 | ||
412 | #define NT_STATUS_DISK_RECALIBRATE_FAILED 0xC0000000 | 0x0169 | ||
413 | #define NT_STATUS_DISK_OPERATION_FAILED 0xC0000000 | 0x016a | ||
414 | #define NT_STATUS_DISK_RESET_FAILED 0xC0000000 | 0x016b | ||
415 | #define NT_STATUS_SHARED_IRQ_BUSY 0xC0000000 | 0x016c | ||
416 | #define NT_STATUS_FT_ORPHANING 0xC0000000 | 0x016d | ||
417 | #define NT_STATUS_PARTITION_FAILURE 0xC0000000 | 0x0172 | ||
418 | #define NT_STATUS_INVALID_BLOCK_LENGTH 0xC0000000 | 0x0173 | ||
419 | #define NT_STATUS_DEVICE_NOT_PARTITIONED 0xC0000000 | 0x0174 | ||
420 | #define NT_STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000000 | 0x0175 | ||
421 | #define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000000 | 0x0176 | ||
422 | #define NT_STATUS_EOM_OVERFLOW 0xC0000000 | 0x0177 | ||
423 | #define NT_STATUS_NO_MEDIA 0xC0000000 | 0x0178 | ||
424 | #define NT_STATUS_NO_SUCH_MEMBER 0xC0000000 | 0x017a | ||
425 | #define NT_STATUS_INVALID_MEMBER 0xC0000000 | 0x017b | ||
426 | #define NT_STATUS_KEY_DELETED 0xC0000000 | 0x017c | ||
427 | #define NT_STATUS_NO_LOG_SPACE 0xC0000000 | 0x017d | ||
428 | #define NT_STATUS_TOO_MANY_SIDS 0xC0000000 | 0x017e | ||
429 | #define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x017f | ||
430 | #define NT_STATUS_KEY_HAS_CHILDREN 0xC0000000 | 0x0180 | ||
431 | #define NT_STATUS_CHILD_MUST_BE_VOLATILE 0xC0000000 | 0x0181 | ||
432 | #define NT_STATUS_DEVICE_CONFIGURATION_ERROR 0xC0000000 | 0x0182 | ||
433 | #define NT_STATUS_DRIVER_INTERNAL_ERROR 0xC0000000 | 0x0183 | ||
434 | #define NT_STATUS_INVALID_DEVICE_STATE 0xC0000000 | 0x0184 | ||
435 | #define NT_STATUS_IO_DEVICE_ERROR 0xC0000000 | 0x0185 | ||
436 | #define NT_STATUS_DEVICE_PROTOCOL_ERROR 0xC0000000 | 0x0186 | ||
437 | #define NT_STATUS_BACKUP_CONTROLLER 0xC0000000 | 0x0187 | ||
438 | #define NT_STATUS_LOG_FILE_FULL 0xC0000000 | 0x0188 | ||
439 | #define NT_STATUS_TOO_LATE 0xC0000000 | 0x0189 | ||
440 | #define NT_STATUS_NO_TRUST_LSA_SECRET 0xC0000000 | 0x018a | ||
441 | #define NT_STATUS_NO_TRUST_SAM_ACCOUNT 0xC0000000 | 0x018b | ||
442 | #define NT_STATUS_TRUSTED_DOMAIN_FAILURE 0xC0000000 | 0x018c | ||
443 | #define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC0000000 | 0x018d | ||
444 | #define NT_STATUS_EVENTLOG_FILE_CORRUPT 0xC0000000 | 0x018e | ||
445 | #define NT_STATUS_EVENTLOG_CANT_START 0xC0000000 | 0x018f | ||
446 | #define NT_STATUS_TRUST_FAILURE 0xC0000000 | 0x0190 | ||
447 | #define NT_STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000000 | 0x0191 | ||
448 | #define NT_STATUS_NETLOGON_NOT_STARTED 0xC0000000 | 0x0192 | ||
449 | #define NT_STATUS_ACCOUNT_EXPIRED 0xC0000000 | 0x0193 | ||
450 | #define NT_STATUS_POSSIBLE_DEADLOCK 0xC0000000 | 0x0194 | ||
451 | #define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000000 | 0x0195 | ||
452 | #define NT_STATUS_REMOTE_SESSION_LIMIT 0xC0000000 | 0x0196 | ||
453 | #define NT_STATUS_EVENTLOG_FILE_CHANGED 0xC0000000 | 0x0197 | ||
454 | #define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000000 | 0x0198 | ||
455 | #define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000000 | 0x0199 | ||
456 | #define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC0000000 | 0x019a | ||
457 | #define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 0xC0000000 | 0x019b | ||
458 | #define NT_STATUS_FS_DRIVER_REQUIRED 0xC0000000 | 0x019c | ||
459 | #define NT_STATUS_NO_USER_SESSION_KEY 0xC0000000 | 0x0202 | ||
460 | #define NT_STATUS_USER_SESSION_DELETED 0xC0000000 | 0x0203 | ||
461 | #define NT_STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000000 | 0x0204 | ||
462 | #define NT_STATUS_INSUFF_SERVER_RESOURCES 0xC0000000 | 0x0205 | ||
463 | #define NT_STATUS_INVALID_BUFFER_SIZE 0xC0000000 | 0x0206 | ||
464 | #define NT_STATUS_INVALID_ADDRESS_COMPONENT 0xC0000000 | 0x0207 | ||
465 | #define NT_STATUS_INVALID_ADDRESS_WILDCARD 0xC0000000 | 0x0208 | ||
466 | #define NT_STATUS_TOO_MANY_ADDRESSES 0xC0000000 | 0x0209 | ||
467 | #define NT_STATUS_ADDRESS_ALREADY_EXISTS 0xC0000000 | 0x020a | ||
468 | #define NT_STATUS_ADDRESS_CLOSED 0xC0000000 | 0x020b | ||
469 | #define NT_STATUS_CONNECTION_DISCONNECTED 0xC0000000 | 0x020c | ||
470 | #define NT_STATUS_CONNECTION_RESET 0xC0000000 | 0x020d | ||
471 | #define NT_STATUS_TOO_MANY_NODES 0xC0000000 | 0x020e | ||
472 | #define NT_STATUS_TRANSACTION_ABORTED 0xC0000000 | 0x020f | ||
473 | #define NT_STATUS_TRANSACTION_TIMED_OUT 0xC0000000 | 0x0210 | ||
474 | #define NT_STATUS_TRANSACTION_NO_RELEASE 0xC0000000 | 0x0211 | ||
475 | #define NT_STATUS_TRANSACTION_NO_MATCH 0xC0000000 | 0x0212 | ||
476 | #define NT_STATUS_TRANSACTION_RESPONDED 0xC0000000 | 0x0213 | ||
477 | #define NT_STATUS_TRANSACTION_INVALID_ID 0xC0000000 | 0x0214 | ||
478 | #define NT_STATUS_TRANSACTION_INVALID_TYPE 0xC0000000 | 0x0215 | ||
479 | #define NT_STATUS_NOT_SERVER_SESSION 0xC0000000 | 0x0216 | ||
480 | #define NT_STATUS_NOT_CLIENT_SESSION 0xC0000000 | 0x0217 | ||
481 | #define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 0xC0000000 | 0x0218 | ||
482 | #define NT_STATUS_DEBUG_ATTACH_FAILED 0xC0000000 | 0x0219 | ||
483 | #define NT_STATUS_SYSTEM_PROCESS_TERMINATED 0xC0000000 | 0x021a | ||
484 | #define NT_STATUS_DATA_NOT_ACCEPTED 0xC0000000 | 0x021b | ||
485 | #define NT_STATUS_NO_BROWSER_SERVERS_FOUND 0xC0000000 | 0x021c | ||
486 | #define NT_STATUS_VDM_HARD_ERROR 0xC0000000 | 0x021d | ||
487 | #define NT_STATUS_DRIVER_CANCEL_TIMEOUT 0xC0000000 | 0x021e | ||
488 | #define NT_STATUS_REPLY_MESSAGE_MISMATCH 0xC0000000 | 0x021f | ||
489 | #define NT_STATUS_MAPPED_ALIGNMENT 0xC0000000 | 0x0220 | ||
490 | #define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 0xC0000000 | 0x0221 | ||
491 | #define NT_STATUS_LOST_WRITEBEHIND_DATA 0xC0000000 | 0x0222 | ||
492 | #define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0xC0000000 | 0x0223 | ||
493 | #define NT_STATUS_PASSWORD_MUST_CHANGE 0xC0000000 | 0x0224 | ||
494 | #define NT_STATUS_NOT_FOUND 0xC0000000 | 0x0225 | ||
495 | #define NT_STATUS_NOT_TINY_STREAM 0xC0000000 | 0x0226 | ||
496 | #define NT_STATUS_RECOVERY_FAILURE 0xC0000000 | 0x0227 | ||
497 | #define NT_STATUS_STACK_OVERFLOW_READ 0xC0000000 | 0x0228 | ||
498 | #define NT_STATUS_FAIL_CHECK 0xC0000000 | 0x0229 | ||
499 | #define NT_STATUS_DUPLICATE_OBJECTID 0xC0000000 | 0x022a | ||
500 | #define NT_STATUS_OBJECTID_EXISTS 0xC0000000 | 0x022b | ||
501 | #define NT_STATUS_CONVERT_TO_LARGE 0xC0000000 | 0x022c | ||
502 | #define NT_STATUS_RETRY 0xC0000000 | 0x022d | ||
503 | #define NT_STATUS_FOUND_OUT_OF_SCOPE 0xC0000000 | 0x022e | ||
504 | #define NT_STATUS_ALLOCATE_BUCKET 0xC0000000 | 0x022f | ||
505 | #define NT_STATUS_PROPSET_NOT_FOUND 0xC0000000 | 0x0230 | ||
506 | #define NT_STATUS_MARSHALL_OVERFLOW 0xC0000000 | 0x0231 | ||
507 | #define NT_STATUS_INVALID_VARIANT 0xC0000000 | 0x0232 | ||
508 | #define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0xC0000000 | 0x0233 | ||
509 | #define NT_STATUS_ACCOUNT_LOCKED_OUT 0xC0000000 | 0x0234 | ||
510 | #define NT_STATUS_HANDLE_NOT_CLOSABLE 0xC0000000 | 0x0235 | ||
511 | #define NT_STATUS_CONNECTION_REFUSED 0xC0000000 | 0x0236 | ||
512 | #define NT_STATUS_GRACEFUL_DISCONNECT 0xC0000000 | 0x0237 | ||
513 | #define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 0xC0000000 | 0x0238 | ||
514 | #define NT_STATUS_ADDRESS_NOT_ASSOCIATED 0xC0000000 | 0x0239 | ||
515 | #define NT_STATUS_CONNECTION_INVALID 0xC0000000 | 0x023a | ||
516 | #define NT_STATUS_CONNECTION_ACTIVE 0xC0000000 | 0x023b | ||
517 | #define NT_STATUS_NETWORK_UNREACHABLE 0xC0000000 | 0x023c | ||
518 | #define NT_STATUS_HOST_UNREACHABLE 0xC0000000 | 0x023d | ||
519 | #define NT_STATUS_PROTOCOL_UNREACHABLE 0xC0000000 | 0x023e | ||
520 | #define NT_STATUS_PORT_UNREACHABLE 0xC0000000 | 0x023f | ||
521 | #define NT_STATUS_REQUEST_ABORTED 0xC0000000 | 0x0240 | ||
522 | #define NT_STATUS_CONNECTION_ABORTED 0xC0000000 | 0x0241 | ||
523 | #define NT_STATUS_BAD_COMPRESSION_BUFFER 0xC0000000 | 0x0242 | ||
524 | #define NT_STATUS_USER_MAPPED_FILE 0xC0000000 | 0x0243 | ||
525 | #define NT_STATUS_AUDIT_FAILED 0xC0000000 | 0x0244 | ||
526 | #define NT_STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000000 | 0x0245 | ||
527 | #define NT_STATUS_CONNECTION_COUNT_LIMIT 0xC0000000 | 0x0246 | ||
528 | #define NT_STATUS_LOGIN_TIME_RESTRICTION 0xC0000000 | 0x0247 | ||
529 | #define NT_STATUS_LOGIN_WKSTA_RESTRICTION 0xC0000000 | 0x0248 | ||
530 | #define NT_STATUS_IMAGE_MP_UP_MISMATCH 0xC0000000 | 0x0249 | ||
531 | #define NT_STATUS_INSUFFICIENT_LOGON_INFO 0xC0000000 | 0x0250 | ||
532 | #define NT_STATUS_BAD_DLL_ENTRYPOINT 0xC0000000 | 0x0251 | ||
533 | #define NT_STATUS_BAD_SERVICE_ENTRYPOINT 0xC0000000 | 0x0252 | ||
534 | #define NT_STATUS_LPC_REPLY_LOST 0xC0000000 | 0x0253 | ||
535 | #define NT_STATUS_IP_ADDRESS_CONFLICT1 0xC0000000 | 0x0254 | ||
536 | #define NT_STATUS_IP_ADDRESS_CONFLICT2 0xC0000000 | 0x0255 | ||
537 | #define NT_STATUS_REGISTRY_QUOTA_LIMIT 0xC0000000 | 0x0256 | ||
538 | #define NT_STATUS_PATH_NOT_COVERED 0xC0000000 | 0x0257 | ||
539 | #define NT_STATUS_NO_CALLBACK_ACTIVE 0xC0000000 | 0x0258 | ||
540 | #define NT_STATUS_LICENSE_QUOTA_EXCEEDED 0xC0000000 | 0x0259 | ||
541 | #define NT_STATUS_PWD_TOO_SHORT 0xC0000000 | 0x025a | ||
542 | #define NT_STATUS_PWD_TOO_RECENT 0xC0000000 | 0x025b | ||
543 | #define NT_STATUS_PWD_HISTORY_CONFLICT 0xC0000000 | 0x025c | ||
544 | #define NT_STATUS_PLUGPLAY_NO_DEVICE 0xC0000000 | 0x025e | ||
545 | #define NT_STATUS_UNSUPPORTED_COMPRESSION 0xC0000000 | 0x025f | ||
546 | #define NT_STATUS_INVALID_HW_PROFILE 0xC0000000 | 0x0260 | ||
547 | #define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0xC0000000 | 0x0261 | ||
548 | #define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 0xC0000000 | 0x0262 | ||
549 | #define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0263 | ||
550 | #define NT_STATUS_RESOURCE_NOT_OWNED 0xC0000000 | 0x0264 | ||
551 | #define NT_STATUS_TOO_MANY_LINKS 0xC0000000 | 0x0265 | ||
552 | #define NT_STATUS_QUOTA_LIST_INCONSISTENT 0xC0000000 | 0x0266 | ||
553 | #define NT_STATUS_FILE_IS_OFFLINE 0xC0000000 | 0x0267 | ||
554 | #define NT_STATUS_NO_SUCH_JOB 0xC0000000 | 0xEDE /* scheduler */ | ||
555 | |||
556 | #endif /* _NTERR_H */ | ||
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h new file mode 100644 index 000000000000..6facb41117a3 --- /dev/null +++ b/fs/cifs/ntlmssp.h | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * fs/cifs/ntlmssp.h | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2002 | ||
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 | |||
22 | #pragma pack(1) | ||
23 | |||
24 | #define NTLMSSP_SIGNATURE "NTLMSSP" | ||
25 | /* Message Types */ | ||
26 | #define NtLmNegotiate cpu_to_le32(1) | ||
27 | #define NtLmChallenge cpu_to_le32(2) | ||
28 | #define NtLmAuthenticate cpu_to_le32(3) | ||
29 | #define UnknownMessage cpu_to_le32(8) | ||
30 | |||
31 | /* Negotiate Flags */ | ||
32 | #define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode | ||
33 | #define NTLMSSP_NEGOTIATE_OEM 0x02 // Text strings are in OEM | ||
34 | #define NTLMSSP_REQUEST_TARGET 0x04 // Server return its auth realm | ||
35 | #define NTLMSSP_NEGOTIATE_SIGN 0x0010 // Request signature capability | ||
36 | #define NTLMSSP_NEGOTIATE_SEAL 0x0020 // Request confidentiality | ||
37 | #define NTLMSSP_NEGOTIATE_DGRAM 0x0040 | ||
38 | #define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 // Use LM session key for sign/seal | ||
39 | #define NTLMSSP_NEGOTIATE_NTLM 0x0200 // NTLM authentication | ||
40 | #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 | ||
41 | #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 | ||
42 | #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 // client/server on same machine | ||
43 | #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 // Sign for all security levels | ||
44 | #define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 | ||
45 | #define NTLMSSP_TARGET_TYPE_SERVER 0x20000 | ||
46 | #define NTLMSSP_TARGET_TYPE_SHARE 0x40000 | ||
47 | #define NTLMSSP_NEGOTIATE_NTLMV2 0x80000 | ||
48 | #define NTLMSSP_REQUEST_INIT_RESP 0x100000 | ||
49 | #define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 | ||
50 | #define NTLMSSP_REQUEST_NOT_NT_KEY 0x400000 | ||
51 | #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 | ||
52 | #define NTLMSSP_NEGOTIATE_128 0x20000000 | ||
53 | #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 | ||
54 | #define NTLMSSP_NEGOTIATE_56 0x80000000 | ||
55 | |||
56 | /* Although typedefs are not commonly used for structure definitions */ | ||
57 | /* in the Linux kernel, in this particular case they are useful */ | ||
58 | /* to more closely match the standards document for NTLMSSP from */ | ||
59 | /* OpenGroup and to make the code more closely match the standard in */ | ||
60 | /* appearance */ | ||
61 | |||
62 | typedef struct _SECURITY_BUFFER { | ||
63 | __le16 Length; | ||
64 | __le16 MaximumLength; | ||
65 | __le32 Buffer; /* offset to buffer */ | ||
66 | } SECURITY_BUFFER; | ||
67 | |||
68 | typedef struct _NEGOTIATE_MESSAGE { | ||
69 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; | ||
70 | __le32 MessageType; /* 1 */ | ||
71 | __le32 NegotiateFlags; | ||
72 | SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ | ||
73 | SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ | ||
74 | char DomainString[0]; | ||
75 | /* followed by WorkstationString */ | ||
76 | } NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; | ||
77 | |||
78 | typedef struct _CHALLENGE_MESSAGE { | ||
79 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; | ||
80 | __le32 MessageType; /* 2 */ | ||
81 | SECURITY_BUFFER TargetName; | ||
82 | __le32 NegotiateFlags; | ||
83 | __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; | ||
84 | __u8 Reserved[8]; | ||
85 | SECURITY_BUFFER TargetInfoArray; | ||
86 | } CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; | ||
87 | |||
88 | typedef struct _AUTHENTICATE_MESSAGE { | ||
89 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; | ||
90 | __le32 MessageType; /* 3 */ | ||
91 | SECURITY_BUFFER LmChallengeResponse; | ||
92 | SECURITY_BUFFER NtChallengeResponse; | ||
93 | SECURITY_BUFFER DomainName; | ||
94 | SECURITY_BUFFER UserName; | ||
95 | SECURITY_BUFFER WorkstationName; | ||
96 | SECURITY_BUFFER SessionKey; | ||
97 | __le32 NegotiateFlags; | ||
98 | char UserString[0]; | ||
99 | } AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; | ||
100 | |||
101 | #pragma pack() /* resume default structure packing */ | ||
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c new file mode 100644 index 000000000000..f8bea395ec9e --- /dev/null +++ b/fs/cifs/readdir.c | |||
@@ -0,0 +1,867 @@ | |||
1 | /* | ||
2 | * fs/cifs/readdir.c | ||
3 | * | ||
4 | * Directory search handling | ||
5 | * | ||
6 | * Copyright (C) International Business Machines Corp., 2004 | ||
7 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
8 | * | ||
9 | * This library is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU Lesser General Public License as published | ||
11 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This library is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
17 | * the GNU Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public License | ||
20 | * along with this library; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/stat.h> | ||
25 | #include <linux/smp_lock.h> | ||
26 | #include "cifspdu.h" | ||
27 | #include "cifsglob.h" | ||
28 | #include "cifsproto.h" | ||
29 | #include "cifs_unicode.h" | ||
30 | #include "cifs_debug.h" | ||
31 | #include "cifs_fs_sb.h" | ||
32 | #include "cifsfs.h" | ||
33 | |||
34 | /* BB fixme - add debug wrappers around this function to disable it fixme BB */ | ||
35 | /* static void dump_cifs_file_struct(struct file *file, char *label) | ||
36 | { | ||
37 | struct cifsFileInfo * cf; | ||
38 | |||
39 | if(file) { | ||
40 | cf = file->private_data; | ||
41 | if(cf == NULL) { | ||
42 | cFYI(1,("empty cifs private file data")); | ||
43 | return; | ||
44 | } | ||
45 | if(cf->invalidHandle) { | ||
46 | cFYI(1,("invalid handle")); | ||
47 | } | ||
48 | if(cf->srch_inf.endOfSearch) { | ||
49 | cFYI(1,("end of search")); | ||
50 | } | ||
51 | if(cf->srch_inf.emptyDir) { | ||
52 | cFYI(1,("empty dir")); | ||
53 | } | ||
54 | |||
55 | } | ||
56 | } */ | ||
57 | |||
58 | /* Returns one if new inode created (which therefore needs to be hashed) */ | ||
59 | /* Might check in the future if inode number changed so we can rehash inode */ | ||
60 | static int construct_dentry(struct qstr *qstring, struct file *file, | ||
61 | struct inode **ptmp_inode, struct dentry **pnew_dentry) | ||
62 | { | ||
63 | struct dentry *tmp_dentry; | ||
64 | struct cifs_sb_info *cifs_sb; | ||
65 | struct cifsTconInfo *pTcon; | ||
66 | int rc = 0; | ||
67 | |||
68 | cFYI(1, ("For %s ", qstring->name)); | ||
69 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
70 | pTcon = cifs_sb->tcon; | ||
71 | |||
72 | qstring->hash = full_name_hash(qstring->name, qstring->len); | ||
73 | tmp_dentry = d_lookup(file->f_dentry, qstring); | ||
74 | if (tmp_dentry) { | ||
75 | cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode)); | ||
76 | *ptmp_inode = tmp_dentry->d_inode; | ||
77 | /* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/ | ||
78 | if(*ptmp_inode == NULL) { | ||
79 | *ptmp_inode = new_inode(file->f_dentry->d_sb); | ||
80 | if(*ptmp_inode == NULL) | ||
81 | return rc; | ||
82 | rc = 1; | ||
83 | d_instantiate(tmp_dentry, *ptmp_inode); | ||
84 | } | ||
85 | } else { | ||
86 | tmp_dentry = d_alloc(file->f_dentry, qstring); | ||
87 | if(tmp_dentry == NULL) { | ||
88 | cERROR(1,("Failed allocating dentry")); | ||
89 | *ptmp_inode = NULL; | ||
90 | return rc; | ||
91 | } | ||
92 | |||
93 | *ptmp_inode = new_inode(file->f_dentry->d_sb); | ||
94 | tmp_dentry->d_op = &cifs_dentry_ops; | ||
95 | if(*ptmp_inode == NULL) | ||
96 | return rc; | ||
97 | rc = 1; | ||
98 | d_instantiate(tmp_dentry, *ptmp_inode); | ||
99 | d_rehash(tmp_dentry); | ||
100 | } | ||
101 | |||
102 | tmp_dentry->d_time = jiffies; | ||
103 | *pnew_dentry = tmp_dentry; | ||
104 | return rc; | ||
105 | } | ||
106 | |||
107 | static void fill_in_inode(struct inode *tmp_inode, | ||
108 | FILE_DIRECTORY_INFO *pfindData, int *pobject_type) | ||
109 | { | ||
110 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | ||
111 | struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); | ||
112 | __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); | ||
113 | __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize); | ||
114 | __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); | ||
115 | |||
116 | cifsInfo->cifsAttrs = attr; | ||
117 | cifsInfo->time = jiffies; | ||
118 | |||
119 | /* Linux can not store file creation time unfortunately so ignore it */ | ||
120 | tmp_inode->i_atime = | ||
121 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); | ||
122 | tmp_inode->i_mtime = | ||
123 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); | ||
124 | tmp_inode->i_ctime = | ||
125 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); | ||
126 | /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ | ||
127 | /* 2767 perms - indicate mandatory locking */ | ||
128 | /* BB fill in uid and gid here? with help from winbind? | ||
129 | or retrieve from NTFS stream extended attribute */ | ||
130 | if (atomic_read(&cifsInfo->inUse) == 0) { | ||
131 | tmp_inode->i_uid = cifs_sb->mnt_uid; | ||
132 | tmp_inode->i_gid = cifs_sb->mnt_gid; | ||
133 | /* set default mode. will override for dirs below */ | ||
134 | tmp_inode->i_mode = cifs_sb->mnt_file_mode; | ||
135 | } | ||
136 | |||
137 | cFYI(0,("CIFS FFIRST: Attributes came in as 0x%x",attr)); | ||
138 | if (attr & ATTR_DIRECTORY) { | ||
139 | *pobject_type = DT_DIR; | ||
140 | /* override default perms since we do not lock dirs */ | ||
141 | if(atomic_read(&cifsInfo->inUse) == 0) { | ||
142 | tmp_inode->i_mode = cifs_sb->mnt_dir_mode; | ||
143 | } | ||
144 | tmp_inode->i_mode |= S_IFDIR; | ||
145 | /* we no longer mark these because we could not follow them */ | ||
146 | /* } else if (attr & ATTR_REPARSE) { | ||
147 | *pobject_type = DT_LNK; | ||
148 | tmp_inode->i_mode |= S_IFLNK; */ | ||
149 | } else { | ||
150 | *pobject_type = DT_REG; | ||
151 | tmp_inode->i_mode |= S_IFREG; | ||
152 | if (attr & ATTR_READONLY) | ||
153 | tmp_inode->i_mode &= ~(S_IWUGO); | ||
154 | } /* could add code here - to validate if device or weird share type? */ | ||
155 | |||
156 | /* can not fill in nlink here as in qpathinfo version and Unx search */ | ||
157 | if (atomic_read(&cifsInfo->inUse) == 0) { | ||
158 | atomic_set(&cifsInfo->inUse, 1); | ||
159 | } | ||
160 | |||
161 | if (is_size_safe_to_change(cifsInfo)) { | ||
162 | /* can not safely change the file size here if the | ||
163 | client is writing to it due to potential races */ | ||
164 | i_size_write(tmp_inode, end_of_file); | ||
165 | |||
166 | /* 512 bytes (2**9) is the fake blocksize that must be used */ | ||
167 | /* for this calculation, even though the reported blocksize is larger */ | ||
168 | tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; | ||
169 | } | ||
170 | |||
171 | if (allocation_size < end_of_file) | ||
172 | cFYI(1, ("May be sparse file, allocation less than file size")); | ||
173 | cFYI(1, | ||
174 | ("File Size %ld and blocks %ld and blocksize %ld", | ||
175 | (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks, | ||
176 | tmp_inode->i_blksize)); | ||
177 | if (S_ISREG(tmp_inode->i_mode)) { | ||
178 | cFYI(1, (" File inode ")); | ||
179 | tmp_inode->i_op = &cifs_file_inode_ops; | ||
180 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | ||
181 | tmp_inode->i_fop = &cifs_file_direct_ops; | ||
182 | else | ||
183 | tmp_inode->i_fop = &cifs_file_ops; | ||
184 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
185 | } else if (S_ISDIR(tmp_inode->i_mode)) { | ||
186 | cFYI(1, (" Directory inode")); | ||
187 | tmp_inode->i_op = &cifs_dir_inode_ops; | ||
188 | tmp_inode->i_fop = &cifs_dir_ops; | ||
189 | } else if (S_ISLNK(tmp_inode->i_mode)) { | ||
190 | cFYI(1, (" Symbolic Link inode ")); | ||
191 | tmp_inode->i_op = &cifs_symlink_inode_ops; | ||
192 | } else { | ||
193 | cFYI(1, (" Init special inode ")); | ||
194 | init_special_inode(tmp_inode, tmp_inode->i_mode, | ||
195 | tmp_inode->i_rdev); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | static void unix_fill_in_inode(struct inode *tmp_inode, | ||
200 | FILE_UNIX_INFO *pfindData, int *pobject_type) | ||
201 | { | ||
202 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | ||
203 | struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); | ||
204 | |||
205 | __u32 type = le32_to_cpu(pfindData->Type); | ||
206 | __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes); | ||
207 | __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); | ||
208 | cifsInfo->time = jiffies; | ||
209 | atomic_inc(&cifsInfo->inUse); | ||
210 | |||
211 | tmp_inode->i_atime = | ||
212 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); | ||
213 | tmp_inode->i_mtime = | ||
214 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime)); | ||
215 | tmp_inode->i_ctime = | ||
216 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); | ||
217 | |||
218 | tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); | ||
219 | if (type == UNIX_FILE) { | ||
220 | *pobject_type = DT_REG; | ||
221 | tmp_inode->i_mode |= S_IFREG; | ||
222 | } else if (type == UNIX_SYMLINK) { | ||
223 | *pobject_type = DT_LNK; | ||
224 | tmp_inode->i_mode |= S_IFLNK; | ||
225 | } else if (type == UNIX_DIR) { | ||
226 | *pobject_type = DT_DIR; | ||
227 | tmp_inode->i_mode |= S_IFDIR; | ||
228 | } else if (type == UNIX_CHARDEV) { | ||
229 | *pobject_type = DT_CHR; | ||
230 | tmp_inode->i_mode |= S_IFCHR; | ||
231 | tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), | ||
232 | le64_to_cpu(pfindData->DevMinor) & MINORMASK); | ||
233 | } else if (type == UNIX_BLOCKDEV) { | ||
234 | *pobject_type = DT_BLK; | ||
235 | tmp_inode->i_mode |= S_IFBLK; | ||
236 | tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), | ||
237 | le64_to_cpu(pfindData->DevMinor) & MINORMASK); | ||
238 | } else if (type == UNIX_FIFO) { | ||
239 | *pobject_type = DT_FIFO; | ||
240 | tmp_inode->i_mode |= S_IFIFO; | ||
241 | } else if (type == UNIX_SOCKET) { | ||
242 | *pobject_type = DT_SOCK; | ||
243 | tmp_inode->i_mode |= S_IFSOCK; | ||
244 | } | ||
245 | |||
246 | tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); | ||
247 | tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); | ||
248 | tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); | ||
249 | |||
250 | if (is_size_safe_to_change(cifsInfo)) { | ||
251 | /* can not safely change the file size here if the | ||
252 | client is writing to it due to potential races */ | ||
253 | i_size_write(tmp_inode,end_of_file); | ||
254 | |||
255 | /* 512 bytes (2**9) is the fake blocksize that must be used */ | ||
256 | /* for this calculation, not the real blocksize */ | ||
257 | tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; | ||
258 | } | ||
259 | |||
260 | if (S_ISREG(tmp_inode->i_mode)) { | ||
261 | cFYI(1, ("File inode")); | ||
262 | tmp_inode->i_op = &cifs_file_inode_ops; | ||
263 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | ||
264 | tmp_inode->i_fop = &cifs_file_direct_ops; | ||
265 | else | ||
266 | tmp_inode->i_fop = &cifs_file_ops; | ||
267 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
268 | } else if (S_ISDIR(tmp_inode->i_mode)) { | ||
269 | cFYI(1, ("Directory inode")); | ||
270 | tmp_inode->i_op = &cifs_dir_inode_ops; | ||
271 | tmp_inode->i_fop = &cifs_dir_ops; | ||
272 | } else if (S_ISLNK(tmp_inode->i_mode)) { | ||
273 | cFYI(1, ("Symbolic Link inode")); | ||
274 | tmp_inode->i_op = &cifs_symlink_inode_ops; | ||
275 | /* tmp_inode->i_fop = *//* do not need to set to anything */ | ||
276 | } else { | ||
277 | cFYI(1, ("Special inode")); | ||
278 | init_special_inode(tmp_inode, tmp_inode->i_mode, | ||
279 | tmp_inode->i_rdev); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | static int initiate_cifs_search(const int xid, struct file *file) | ||
284 | { | ||
285 | int rc = 0; | ||
286 | char * full_path; | ||
287 | struct cifsFileInfo * cifsFile; | ||
288 | struct cifs_sb_info *cifs_sb; | ||
289 | struct cifsTconInfo *pTcon; | ||
290 | |||
291 | if(file->private_data == NULL) { | ||
292 | file->private_data = | ||
293 | kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL); | ||
294 | } | ||
295 | |||
296 | if(file->private_data == NULL) { | ||
297 | return -ENOMEM; | ||
298 | } else { | ||
299 | memset(file->private_data,0,sizeof(struct cifsFileInfo)); | ||
300 | } | ||
301 | cifsFile = file->private_data; | ||
302 | cifsFile->invalidHandle = TRUE; | ||
303 | cifsFile->srch_inf.endOfSearch = FALSE; | ||
304 | |||
305 | if(file->f_dentry == NULL) | ||
306 | return -ENOENT; | ||
307 | |||
308 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
309 | if(cifs_sb == NULL) | ||
310 | return -EINVAL; | ||
311 | |||
312 | pTcon = cifs_sb->tcon; | ||
313 | if(pTcon == NULL) | ||
314 | return -EINVAL; | ||
315 | |||
316 | down(&file->f_dentry->d_sb->s_vfs_rename_sem); | ||
317 | full_path = build_wildcard_path_from_dentry(file->f_dentry); | ||
318 | up(&file->f_dentry->d_sb->s_vfs_rename_sem); | ||
319 | |||
320 | if(full_path == NULL) { | ||
321 | return -ENOMEM; | ||
322 | } | ||
323 | |||
324 | cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); | ||
325 | |||
326 | /* test for Unix extensions */ | ||
327 | if (pTcon->ses->capabilities & CAP_UNIX) { | ||
328 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; | ||
329 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | ||
330 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; | ||
331 | } else /* not srvinos - BB fixme add check for backlevel? */ { | ||
332 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; | ||
333 | } | ||
334 | |||
335 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, | ||
336 | &cifsFile->netfid, &cifsFile->srch_inf); | ||
337 | if(rc == 0) | ||
338 | cifsFile->invalidHandle = FALSE; | ||
339 | kfree(full_path); | ||
340 | return rc; | ||
341 | } | ||
342 | |||
343 | /* return length of unicode string in bytes */ | ||
344 | static int cifs_unicode_bytelen(char *str) | ||
345 | { | ||
346 | int len; | ||
347 | __le16 * ustr = (__le16 *)str; | ||
348 | |||
349 | for(len=0;len <= PATH_MAX;len++) { | ||
350 | if(ustr[len] == 0) | ||
351 | return len << 1; | ||
352 | } | ||
353 | cFYI(1,("Unicode string longer than PATH_MAX found")); | ||
354 | return len << 1; | ||
355 | } | ||
356 | |||
357 | static char *nxt_dir_entry(char *old_entry, char *end_of_smb) | ||
358 | { | ||
359 | char * new_entry; | ||
360 | FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; | ||
361 | |||
362 | new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); | ||
363 | cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); | ||
364 | /* validate that new_entry is not past end of SMB */ | ||
365 | if(new_entry >= end_of_smb) { | ||
366 | cFYI(1,("search entry %p began after end of SMB %p old entry %p", | ||
367 | new_entry,end_of_smb,old_entry)); | ||
368 | return NULL; | ||
369 | } else | ||
370 | return new_entry; | ||
371 | |||
372 | } | ||
373 | |||
374 | #define UNICODE_DOT cpu_to_le16(0x2e) | ||
375 | |||
376 | /* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */ | ||
377 | static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) | ||
378 | { | ||
379 | int rc = 0; | ||
380 | char * filename = NULL; | ||
381 | int len = 0; | ||
382 | |||
383 | if(cfile->srch_inf.info_level == 0x202) { | ||
384 | FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; | ||
385 | filename = &pFindData->FileName[0]; | ||
386 | if(cfile->srch_inf.unicode) { | ||
387 | len = cifs_unicode_bytelen(filename); | ||
388 | } else { | ||
389 | /* BB should we make this strnlen of PATH_MAX? */ | ||
390 | len = strnlen(filename, 5); | ||
391 | } | ||
392 | } else if(cfile->srch_inf.info_level == 0x101) { | ||
393 | FILE_DIRECTORY_INFO * pFindData = | ||
394 | (FILE_DIRECTORY_INFO *)current_entry; | ||
395 | filename = &pFindData->FileName[0]; | ||
396 | len = le32_to_cpu(pFindData->FileNameLength); | ||
397 | } else if(cfile->srch_inf.info_level == 0x102) { | ||
398 | FILE_FULL_DIRECTORY_INFO * pFindData = | ||
399 | (FILE_FULL_DIRECTORY_INFO *)current_entry; | ||
400 | filename = &pFindData->FileName[0]; | ||
401 | len = le32_to_cpu(pFindData->FileNameLength); | ||
402 | } else if(cfile->srch_inf.info_level == 0x105) { | ||
403 | SEARCH_ID_FULL_DIR_INFO * pFindData = | ||
404 | (SEARCH_ID_FULL_DIR_INFO *)current_entry; | ||
405 | filename = &pFindData->FileName[0]; | ||
406 | len = le32_to_cpu(pFindData->FileNameLength); | ||
407 | } else if(cfile->srch_inf.info_level == 0x104) { | ||
408 | FILE_BOTH_DIRECTORY_INFO * pFindData = | ||
409 | (FILE_BOTH_DIRECTORY_INFO *)current_entry; | ||
410 | filename = &pFindData->FileName[0]; | ||
411 | len = le32_to_cpu(pFindData->FileNameLength); | ||
412 | } else { | ||
413 | cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); | ||
414 | } | ||
415 | |||
416 | if(filename) { | ||
417 | if(cfile->srch_inf.unicode) { | ||
418 | __le16 *ufilename = (__le16 *)filename; | ||
419 | if(len == 2) { | ||
420 | /* check for . */ | ||
421 | if(ufilename[0] == UNICODE_DOT) | ||
422 | rc = 1; | ||
423 | } else if(len == 4) { | ||
424 | /* check for .. */ | ||
425 | if((ufilename[0] == UNICODE_DOT) | ||
426 | &&(ufilename[1] == UNICODE_DOT)) | ||
427 | rc = 2; | ||
428 | } | ||
429 | } else /* ASCII */ { | ||
430 | if(len == 1) { | ||
431 | if(filename[0] == '.') | ||
432 | rc = 1; | ||
433 | } else if(len == 2) { | ||
434 | if((filename[0] == '.') && (filename[1] == '.')) | ||
435 | rc = 2; | ||
436 | } | ||
437 | } | ||
438 | } | ||
439 | |||
440 | return rc; | ||
441 | } | ||
442 | |||
443 | /* find the corresponding entry in the search */ | ||
444 | /* Note that the SMB server returns search entries for . and .. which | ||
445 | complicates logic here if we choose to parse for them and we do not | ||
446 | assume that they are located in the findfirst return buffer.*/ | ||
447 | /* We start counting in the buffer with entry 2 and increment for every | ||
448 | entry (do not increment for . or .. entry) */ | ||
449 | static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | ||
450 | struct file *file, char **ppCurrentEntry, int *num_to_ret) | ||
451 | { | ||
452 | int rc = 0; | ||
453 | int pos_in_buf = 0; | ||
454 | loff_t first_entry_in_buffer; | ||
455 | loff_t index_to_find = file->f_pos; | ||
456 | struct cifsFileInfo * cifsFile = file->private_data; | ||
457 | /* check if index in the buffer */ | ||
458 | |||
459 | if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL)) | ||
460 | return -ENOENT; | ||
461 | |||
462 | *ppCurrentEntry = NULL; | ||
463 | first_entry_in_buffer = | ||
464 | cifsFile->srch_inf.index_of_last_entry - | ||
465 | cifsFile->srch_inf.entries_in_buffer; | ||
466 | /* dump_cifs_file_struct(file, "In fce ");*/ | ||
467 | if(index_to_find < first_entry_in_buffer) { | ||
468 | /* close and restart search */ | ||
469 | cFYI(1,("search backing up - close and restart search")); | ||
470 | cifsFile->invalidHandle = TRUE; | ||
471 | CIFSFindClose(xid, pTcon, cifsFile->netfid); | ||
472 | kfree(cifsFile->search_resume_name); | ||
473 | cifsFile->search_resume_name = NULL; | ||
474 | if(cifsFile->srch_inf.ntwrk_buf_start) { | ||
475 | cFYI(1,("freeing SMB ff cache buf on search rewind")); | ||
476 | cifs_buf_release(cifsFile->srch_inf.ntwrk_buf_start); | ||
477 | } | ||
478 | rc = initiate_cifs_search(xid,file); | ||
479 | if(rc) { | ||
480 | cFYI(1,("error %d reinitiating a search on rewind",rc)); | ||
481 | return rc; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && | ||
486 | (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ | ||
487 | cFYI(1,("calling findnext2")); | ||
488 | rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf); | ||
489 | if(rc) | ||
490 | return -ENOENT; | ||
491 | } | ||
492 | if(index_to_find < cifsFile->srch_inf.index_of_last_entry) { | ||
493 | /* we found the buffer that contains the entry */ | ||
494 | /* scan and find it */ | ||
495 | int i; | ||
496 | char * current_entry; | ||
497 | char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + | ||
498 | smbCalcSize((struct smb_hdr *) | ||
499 | cifsFile->srch_inf.ntwrk_buf_start); | ||
500 | /* dump_cifs_file_struct(file,"found entry in fce "); */ | ||
501 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry | ||
502 | - cifsFile->srch_inf.entries_in_buffer; | ||
503 | pos_in_buf = index_to_find - first_entry_in_buffer; | ||
504 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); | ||
505 | current_entry = cifsFile->srch_inf.srch_entries_start; | ||
506 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { | ||
507 | /* go entry to next entry figuring out which we need to start with */ | ||
508 | /* if( . or ..) | ||
509 | skip */ | ||
510 | rc = cifs_entry_is_dot(current_entry,cifsFile); | ||
511 | if(rc == 1) /* is . or .. so skip */ { | ||
512 | cFYI(1,("Entry is .")); /* BB removeme BB */ | ||
513 | /* continue; */ | ||
514 | } else if (rc == 2 ) { | ||
515 | cFYI(1,("Entry is ..")); /* BB removeme BB */ | ||
516 | /* continue; */ | ||
517 | } | ||
518 | current_entry = nxt_dir_entry(current_entry,end_of_smb); | ||
519 | } | ||
520 | if((current_entry == NULL) && (i < pos_in_buf)) { | ||
521 | /* BB fixme - check if we should flag this error */ | ||
522 | cERROR(1,("reached end of buf searching for pos in buf" | ||
523 | " %d index to find %lld rc %d", | ||
524 | pos_in_buf,index_to_find,rc)); | ||
525 | } | ||
526 | rc = 0; | ||
527 | *ppCurrentEntry = current_entry; | ||
528 | } else { | ||
529 | cFYI(1,("index not in buffer - could not findnext into it")); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { | ||
534 | cFYI(1,("can not return entries when pos_in_buf beyond last entry")); | ||
535 | *num_to_ret = 0; | ||
536 | } else | ||
537 | *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; | ||
538 | /* dump_cifs_file_struct(file, "end fce ");*/ | ||
539 | |||
540 | return rc; | ||
541 | } | ||
542 | |||
543 | /* inode num, inode type and filename returned */ | ||
544 | static int cifs_get_name_from_search_buf(struct qstr *pqst, | ||
545 | char *current_entry, __u16 level, unsigned int unicode, | ||
546 | struct cifs_sb_info * cifs_sb, ino_t *pinum) | ||
547 | { | ||
548 | int rc = 0; | ||
549 | unsigned int len = 0; | ||
550 | char * filename; | ||
551 | struct nls_table * nlt = cifs_sb->local_nls; | ||
552 | |||
553 | *pinum = 0; | ||
554 | |||
555 | if(level == SMB_FIND_FILE_UNIX) { | ||
556 | FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; | ||
557 | |||
558 | filename = &pFindData->FileName[0]; | ||
559 | if(unicode) { | ||
560 | len = cifs_unicode_bytelen(filename); | ||
561 | } else { | ||
562 | /* BB should we make this strnlen of PATH_MAX? */ | ||
563 | len = strnlen(filename, PATH_MAX); | ||
564 | } | ||
565 | |||
566 | /* BB fixme - hash low and high 32 bits if not 64 bit arch BB fixme */ | ||
567 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) | ||
568 | *pinum = pFindData->UniqueId; | ||
569 | } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) { | ||
570 | FILE_DIRECTORY_INFO * pFindData = | ||
571 | (FILE_DIRECTORY_INFO *)current_entry; | ||
572 | filename = &pFindData->FileName[0]; | ||
573 | len = le32_to_cpu(pFindData->FileNameLength); | ||
574 | } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { | ||
575 | FILE_FULL_DIRECTORY_INFO * pFindData = | ||
576 | (FILE_FULL_DIRECTORY_INFO *)current_entry; | ||
577 | filename = &pFindData->FileName[0]; | ||
578 | len = le32_to_cpu(pFindData->FileNameLength); | ||
579 | } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { | ||
580 | SEARCH_ID_FULL_DIR_INFO * pFindData = | ||
581 | (SEARCH_ID_FULL_DIR_INFO *)current_entry; | ||
582 | filename = &pFindData->FileName[0]; | ||
583 | len = le32_to_cpu(pFindData->FileNameLength); | ||
584 | *pinum = pFindData->UniqueId; | ||
585 | } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { | ||
586 | FILE_BOTH_DIRECTORY_INFO * pFindData = | ||
587 | (FILE_BOTH_DIRECTORY_INFO *)current_entry; | ||
588 | filename = &pFindData->FileName[0]; | ||
589 | len = le32_to_cpu(pFindData->FileNameLength); | ||
590 | } else { | ||
591 | cFYI(1,("Unknown findfirst level %d",level)); | ||
592 | return -EINVAL; | ||
593 | } | ||
594 | if(unicode) { | ||
595 | /* BB fixme - test with long names */ | ||
596 | /* Note converted filename can be longer than in unicode */ | ||
597 | pqst->len = cifs_strfromUCS_le((char *)pqst->name,(wchar_t *)filename,len/2,nlt); | ||
598 | } else { | ||
599 | pqst->name = filename; | ||
600 | pqst->len = len; | ||
601 | } | ||
602 | pqst->hash = full_name_hash(pqst->name,pqst->len); | ||
603 | /* cFYI(1,("filldir on %s",pqst->name)); */ | ||
604 | return rc; | ||
605 | } | ||
606 | |||
607 | static int cifs_filldir(char *pfindEntry, struct file *file, | ||
608 | filldir_t filldir, void *direntry, char *scratch_buf) | ||
609 | { | ||
610 | int rc = 0; | ||
611 | struct qstr qstring; | ||
612 | struct cifsFileInfo * pCifsF; | ||
613 | unsigned obj_type; | ||
614 | ino_t inum; | ||
615 | struct cifs_sb_info * cifs_sb; | ||
616 | struct inode *tmp_inode; | ||
617 | struct dentry *tmp_dentry; | ||
618 | |||
619 | /* get filename and len into qstring */ | ||
620 | /* get dentry */ | ||
621 | /* decide whether to create and populate ionde */ | ||
622 | if((direntry == NULL) || (file == NULL)) | ||
623 | return -EINVAL; | ||
624 | |||
625 | pCifsF = file->private_data; | ||
626 | |||
627 | if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL)) | ||
628 | return -ENOENT; | ||
629 | |||
630 | if(file->f_dentry == NULL) | ||
631 | return -ENOENT; | ||
632 | |||
633 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
634 | |||
635 | qstring.name = scratch_buf; | ||
636 | rc = cifs_get_name_from_search_buf(&qstring,pfindEntry, | ||
637 | pCifsF->srch_inf.info_level, | ||
638 | pCifsF->srch_inf.unicode,cifs_sb, | ||
639 | &inum /* returned */); | ||
640 | |||
641 | if(rc) | ||
642 | return rc; | ||
643 | |||
644 | rc = construct_dentry(&qstring,file,&tmp_inode, &tmp_dentry); | ||
645 | if((tmp_inode == NULL) || (tmp_dentry == NULL)) | ||
646 | return -ENOMEM; | ||
647 | |||
648 | if(rc) { | ||
649 | /* inode created, we need to hash it with right inode number */ | ||
650 | if(inum != 0) { | ||
651 | /* BB fixme - hash the 2 32 quantities bits together if necessary BB */ | ||
652 | tmp_inode->i_ino = inum; | ||
653 | } | ||
654 | insert_inode_hash(tmp_inode); | ||
655 | } | ||
656 | |||
657 | if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { | ||
658 | unix_fill_in_inode(tmp_inode,(FILE_UNIX_INFO *)pfindEntry,&obj_type); | ||
659 | } else { | ||
660 | fill_in_inode(tmp_inode,(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type); | ||
661 | } | ||
662 | |||
663 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); | ||
664 | if(rc) { | ||
665 | cFYI(1,("filldir rc = %d",rc)); | ||
666 | } | ||
667 | |||
668 | dput(tmp_dentry); | ||
669 | return rc; | ||
670 | } | ||
671 | |||
672 | static int cifs_save_resume_key(const char *current_entry, | ||
673 | struct cifsFileInfo *cifsFile) | ||
674 | { | ||
675 | int rc = 0; | ||
676 | unsigned int len = 0; | ||
677 | __u16 level; | ||
678 | char * filename; | ||
679 | |||
680 | if((cifsFile == NULL) || (current_entry == NULL)) | ||
681 | return -EINVAL; | ||
682 | |||
683 | level = cifsFile->srch_inf.info_level; | ||
684 | |||
685 | if(level == SMB_FIND_FILE_UNIX) { | ||
686 | FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; | ||
687 | |||
688 | filename = &pFindData->FileName[0]; | ||
689 | if(cifsFile->srch_inf.unicode) { | ||
690 | len = cifs_unicode_bytelen(filename); | ||
691 | } else { | ||
692 | /* BB should we make this strnlen of PATH_MAX? */ | ||
693 | len = strnlen(filename, PATH_MAX); | ||
694 | } | ||
695 | cifsFile->srch_inf.resume_key = pFindData->ResumeKey; | ||
696 | } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) { | ||
697 | FILE_DIRECTORY_INFO * pFindData = | ||
698 | (FILE_DIRECTORY_INFO *)current_entry; | ||
699 | filename = &pFindData->FileName[0]; | ||
700 | len = le32_to_cpu(pFindData->FileNameLength); | ||
701 | cifsFile->srch_inf.resume_key = pFindData->FileIndex; | ||
702 | } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { | ||
703 | FILE_FULL_DIRECTORY_INFO * pFindData = | ||
704 | (FILE_FULL_DIRECTORY_INFO *)current_entry; | ||
705 | filename = &pFindData->FileName[0]; | ||
706 | len = le32_to_cpu(pFindData->FileNameLength); | ||
707 | cifsFile->srch_inf.resume_key = pFindData->FileIndex; | ||
708 | } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { | ||
709 | SEARCH_ID_FULL_DIR_INFO * pFindData = | ||
710 | (SEARCH_ID_FULL_DIR_INFO *)current_entry; | ||
711 | filename = &pFindData->FileName[0]; | ||
712 | len = le32_to_cpu(pFindData->FileNameLength); | ||
713 | cifsFile->srch_inf.resume_key = pFindData->FileIndex; | ||
714 | } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { | ||
715 | FILE_BOTH_DIRECTORY_INFO * pFindData = | ||
716 | (FILE_BOTH_DIRECTORY_INFO *)current_entry; | ||
717 | filename = &pFindData->FileName[0]; | ||
718 | len = le32_to_cpu(pFindData->FileNameLength); | ||
719 | cifsFile->srch_inf.resume_key = pFindData->FileIndex; | ||
720 | } else { | ||
721 | cFYI(1,("Unknown findfirst level %d",level)); | ||
722 | return -EINVAL; | ||
723 | } | ||
724 | cifsFile->srch_inf.resume_name_len = len; | ||
725 | cifsFile->srch_inf.presume_name = filename; | ||
726 | return rc; | ||
727 | } | ||
728 | |||
729 | int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | ||
730 | { | ||
731 | int rc = 0; | ||
732 | int xid,i; | ||
733 | struct cifs_sb_info *cifs_sb; | ||
734 | struct cifsTconInfo *pTcon; | ||
735 | struct cifsFileInfo *cifsFile = NULL; | ||
736 | char * current_entry; | ||
737 | int num_to_fill = 0; | ||
738 | char * tmp_buf = NULL; | ||
739 | char * end_of_smb; | ||
740 | |||
741 | xid = GetXid(); | ||
742 | |||
743 | if(file->f_dentry == NULL) { | ||
744 | FreeXid(xid); | ||
745 | return -EIO; | ||
746 | } | ||
747 | /* dump_cifs_file_struct(file, "Begin rdir "); */ | ||
748 | |||
749 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | ||
750 | pTcon = cifs_sb->tcon; | ||
751 | if(pTcon == NULL) | ||
752 | return -EINVAL; | ||
753 | |||
754 | /* cFYI(1,("readdir2 pos: %lld",file->f_pos)); */ | ||
755 | |||
756 | switch ((int) file->f_pos) { | ||
757 | case 0: | ||
758 | /*if (filldir(direntry, ".", 1, file->f_pos, | ||
759 | file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { | ||
760 | cERROR(1, ("Filldir for current dir failed ")); | ||
761 | rc = -ENOMEM; | ||
762 | break; | ||
763 | } | ||
764 | file->f_pos++; */ | ||
765 | case 1: | ||
766 | /* if (filldir(direntry, "..", 2, file->f_pos, | ||
767 | file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { | ||
768 | cERROR(1, ("Filldir for parent dir failed ")); | ||
769 | rc = -ENOMEM; | ||
770 | break; | ||
771 | } | ||
772 | file->f_pos++; */ | ||
773 | case 2: | ||
774 | /* 1) If search is active, | ||
775 | is in current search buffer? | ||
776 | if it before then restart search | ||
777 | if after then keep searching till find it */ | ||
778 | |||
779 | if(file->private_data == NULL) { | ||
780 | rc = initiate_cifs_search(xid,file); | ||
781 | cFYI(1,("initiate cifs search rc %d",rc)); | ||
782 | if(rc) { | ||
783 | FreeXid(xid); | ||
784 | return rc; | ||
785 | } | ||
786 | } | ||
787 | default: | ||
788 | if(file->private_data == NULL) { | ||
789 | rc = -EINVAL; | ||
790 | FreeXid(xid); | ||
791 | return rc; | ||
792 | } | ||
793 | cifsFile = file->private_data; | ||
794 | if (cifsFile->srch_inf.endOfSearch) { | ||
795 | if(cifsFile->srch_inf.emptyDir) { | ||
796 | cFYI(1, ("End of search, empty dir")); | ||
797 | rc = 0; | ||
798 | break; | ||
799 | } | ||
800 | } /* else { | ||
801 | cifsFile->invalidHandle = TRUE; | ||
802 | CIFSFindClose(xid, pTcon, cifsFile->netfid); | ||
803 | } | ||
804 | kfree(cifsFile->search_resume_name); | ||
805 | cifsFile->search_resume_name = NULL; */ | ||
806 | |||
807 | /* BB account for . and .. in f_pos as special case */ | ||
808 | /* dump_cifs_file_struct(file, "rdir after default ");*/ | ||
809 | |||
810 | rc = find_cifs_entry(xid,pTcon, file, | ||
811 | ¤t_entry,&num_to_fill); | ||
812 | if(rc) { | ||
813 | cFYI(1,("fce error %d",rc)); | ||
814 | goto rddir2_exit; | ||
815 | } else if (current_entry != NULL) { | ||
816 | cFYI(1,("entry %lld found",file->f_pos)); | ||
817 | } else { | ||
818 | cFYI(1,("could not find entry")); | ||
819 | goto rddir2_exit; | ||
820 | } | ||
821 | cFYI(1,("loop through %d times filling dir for net buf %p", | ||
822 | num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); | ||
823 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + | ||
824 | smbCalcSize((struct smb_hdr *) | ||
825 | cifsFile->srch_inf.ntwrk_buf_start); | ||
826 | tmp_buf = kmalloc(NAME_MAX+1,GFP_KERNEL); | ||
827 | for(i=0;(i<num_to_fill) && (rc == 0);i++) { | ||
828 | if(current_entry == NULL) { | ||
829 | /* evaluate whether this case is an error */ | ||
830 | cERROR(1,("past end of SMB num to fill %d i %d", | ||
831 | num_to_fill, i)); | ||
832 | break; | ||
833 | } | ||
834 | |||
835 | /* BB FIXME - need to enable the below code BB */ | ||
836 | |||
837 | /* if((!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) || | ||
838 | (cifsFile->srch_inf.info_level != | ||
839 | something that supports server inodes)) { | ||
840 | create dentry | ||
841 | create inode | ||
842 | fill in inode new_inode (getting local i_ino) | ||
843 | } | ||
844 | also create local inode for performance reasons (so we | ||
845 | have a cache of inode metadata) unless this new mount | ||
846 | parm says otherwise */ | ||
847 | |||
848 | rc = cifs_filldir(current_entry, file, | ||
849 | filldir, direntry,tmp_buf); | ||
850 | file->f_pos++; | ||
851 | if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) { | ||
852 | cFYI(1,("last entry in buf at pos %lld %s", | ||
853 | file->f_pos,tmp_buf)); /* BB removeme BB */ | ||
854 | cifs_save_resume_key(current_entry,cifsFile); | ||
855 | break; | ||
856 | } else | ||
857 | current_entry = nxt_dir_entry(current_entry,end_of_smb); | ||
858 | } | ||
859 | kfree(tmp_buf); | ||
860 | break; | ||
861 | } /* end switch */ | ||
862 | |||
863 | rddir2_exit: | ||
864 | /* dump_cifs_file_struct(file, "end rdir "); */ | ||
865 | FreeXid(xid); | ||
866 | return rc; | ||
867 | } | ||
diff --git a/fs/cifs/rfc1002pdu.h b/fs/cifs/rfc1002pdu.h new file mode 100644 index 000000000000..806c0ed06da9 --- /dev/null +++ b/fs/cifs/rfc1002pdu.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * fs/cifs/rfc1002pdu.h | ||
3 | * | ||
4 | * Protocol Data Unit definitions for RFC 1001/1002 support | ||
5 | * | ||
6 | * Copyright (c) International Business Machines Corp., 2004 | ||
7 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
8 | * | ||
9 | * This library is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU Lesser General Public License as published | ||
11 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This library is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
17 | * the GNU Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public License | ||
20 | * along with this library; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #pragma pack(1) | ||
25 | |||
26 | /* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ | ||
27 | |||
28 | /* RFC 1002 session packet types */ | ||
29 | #define RFC1002_SESSION_MESASAGE 0x00 | ||
30 | #define RFC1002_SESSION_REQUEST 0x81 | ||
31 | #define RFC1002_POSITIVE_SESSION_RESPONSE 0x82 | ||
32 | #define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83 | ||
33 | #define RFC1002_RETARGET_SESSION_RESPONSE 0x83 | ||
34 | #define RFC1002_SESSION_KEEP_ALIVE 0x85 | ||
35 | |||
36 | /* RFC 1002 flags (only one defined */ | ||
37 | #define RFC1002_LENGTH_EXTEND 0x80 /* high order bit of length (ie +64K) */ | ||
38 | |||
39 | struct rfc1002_session_packet { | ||
40 | __u8 type; | ||
41 | __u8 flags; | ||
42 | __u16 length; | ||
43 | union { | ||
44 | struct { | ||
45 | __u8 called_len; | ||
46 | __u8 called_name[32]; | ||
47 | __u8 scope1; /* null */ | ||
48 | __u8 calling_len; | ||
49 | __u8 calling_name[32]; | ||
50 | __u8 scope2; /* null */ | ||
51 | } session_req; | ||
52 | struct { | ||
53 | __u32 retarget_ip_addr; | ||
54 | __u16 port; | ||
55 | } retarget_resp; | ||
56 | __u8 neg_ses_resp_error_code; | ||
57 | /* POSITIVE_SESSION_RESPONSE packet does not include trailer. | ||
58 | SESSION_KEEP_ALIVE packet also does not include a trailer. | ||
59 | Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */ | ||
60 | } trailer; | ||
61 | }; | ||
62 | |||
63 | /* Negative Session Response error codes */ | ||
64 | #define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */ | ||
65 | #define RFC1002_NOT_LISTENING_CALLING 0x81 /* not listening on calling name */ | ||
66 | #define RFC1002_NOT_PRESENT 0x82 /* called name not present */ | ||
67 | #define RFC1002_INSUFFICIENT_RESOURCE 0x83 | ||
68 | #define RFC1002_UNSPECIFIED_ERROR 0x8F | ||
69 | |||
70 | /* RFC 1002 Datagram service packets are not defined here as they | ||
71 | are not needed for the network filesystem client unless we plan on | ||
72 | implementing broadcast resolution of the server ip address (from | ||
73 | server netbios name). Currently server names are resolved only via DNS | ||
74 | (tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/ | ||
75 | |||
76 | #define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER " | ||
77 | |||
78 | #pragma pack() /* resume default structure packing */ | ||
79 | |||
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c new file mode 100644 index 000000000000..efaa044523a7 --- /dev/null +++ b/fs/cifs/smbdes.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | Unix SMB/Netbios implementation. | ||
3 | Version 1.9. | ||
4 | |||
5 | a partial implementation of DES designed for use in the | ||
6 | SMB authentication protocol | ||
7 | |||
8 | Copyright (C) Andrew Tridgell 1998 | ||
9 | Modified by Steve French (sfrench@us.ibm.com) 2002,2004 | ||
10 | |||
11 | This program is free software; you can redistribute it and/or modify | ||
12 | it under the terms of the GNU General Public License as published by | ||
13 | the Free Software Foundation; either version 2 of the License, or | ||
14 | (at your option) any later version. | ||
15 | |||
16 | This program is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with this program; if not, write to the Free Software | ||
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | |||
26 | /* NOTES: | ||
27 | |||
28 | This code makes no attempt to be fast! In fact, it is a very | ||
29 | slow implementation | ||
30 | |||
31 | This code is NOT a complete DES implementation. It implements only | ||
32 | the minimum necessary for SMB authentication, as used by all SMB | ||
33 | products (including every copy of Microsoft Windows95 ever sold) | ||
34 | |||
35 | In particular, it can only do a unchained forward DES pass. This | ||
36 | means it is not possible to use this code for encryption/decryption | ||
37 | of data, instead it is only useful as a "hash" algorithm. | ||
38 | |||
39 | There is no entry point into this code that allows normal DES operation. | ||
40 | |||
41 | I believe this means that this code does not come under ITAR | ||
42 | regulations but this is NOT a legal opinion. If you are concerned | ||
43 | about the applicability of ITAR regulations to this code then you | ||
44 | should confirm it for yourself (and maybe let me know if you come | ||
45 | up with a different answer to the one above) | ||
46 | */ | ||
47 | #include <linux/slab.h> | ||
48 | #include "cifsencrypt.h" | ||
49 | #define uchar unsigned char | ||
50 | |||
51 | static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9, | ||
52 | 1, 58, 50, 42, 34, 26, 18, | ||
53 | 10, 2, 59, 51, 43, 35, 27, | ||
54 | 19, 11, 3, 60, 52, 44, 36, | ||
55 | 63, 55, 47, 39, 31, 23, 15, | ||
56 | 7, 62, 54, 46, 38, 30, 22, | ||
57 | 14, 6, 61, 53, 45, 37, 29, | ||
58 | 21, 13, 5, 28, 20, 12, 4 | ||
59 | }; | ||
60 | |||
61 | static uchar perm2[48] = { 14, 17, 11, 24, 1, 5, | ||
62 | 3, 28, 15, 6, 21, 10, | ||
63 | 23, 19, 12, 4, 26, 8, | ||
64 | 16, 7, 27, 20, 13, 2, | ||
65 | 41, 52, 31, 37, 47, 55, | ||
66 | 30, 40, 51, 45, 33, 48, | ||
67 | 44, 49, 39, 56, 34, 53, | ||
68 | 46, 42, 50, 36, 29, 32 | ||
69 | }; | ||
70 | |||
71 | static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2, | ||
72 | 60, 52, 44, 36, 28, 20, 12, 4, | ||
73 | 62, 54, 46, 38, 30, 22, 14, 6, | ||
74 | 64, 56, 48, 40, 32, 24, 16, 8, | ||
75 | 57, 49, 41, 33, 25, 17, 9, 1, | ||
76 | 59, 51, 43, 35, 27, 19, 11, 3, | ||
77 | 61, 53, 45, 37, 29, 21, 13, 5, | ||
78 | 63, 55, 47, 39, 31, 23, 15, 7 | ||
79 | }; | ||
80 | |||
81 | static uchar perm4[48] = { 32, 1, 2, 3, 4, 5, | ||
82 | 4, 5, 6, 7, 8, 9, | ||
83 | 8, 9, 10, 11, 12, 13, | ||
84 | 12, 13, 14, 15, 16, 17, | ||
85 | 16, 17, 18, 19, 20, 21, | ||
86 | 20, 21, 22, 23, 24, 25, | ||
87 | 24, 25, 26, 27, 28, 29, | ||
88 | 28, 29, 30, 31, 32, 1 | ||
89 | }; | ||
90 | |||
91 | static uchar perm5[32] = { 16, 7, 20, 21, | ||
92 | 29, 12, 28, 17, | ||
93 | 1, 15, 23, 26, | ||
94 | 5, 18, 31, 10, | ||
95 | 2, 8, 24, 14, | ||
96 | 32, 27, 3, 9, | ||
97 | 19, 13, 30, 6, | ||
98 | 22, 11, 4, 25 | ||
99 | }; | ||
100 | |||
101 | static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32, | ||
102 | 39, 7, 47, 15, 55, 23, 63, 31, | ||
103 | 38, 6, 46, 14, 54, 22, 62, 30, | ||
104 | 37, 5, 45, 13, 53, 21, 61, 29, | ||
105 | 36, 4, 44, 12, 52, 20, 60, 28, | ||
106 | 35, 3, 43, 11, 51, 19, 59, 27, | ||
107 | 34, 2, 42, 10, 50, 18, 58, 26, | ||
108 | 33, 1, 41, 9, 49, 17, 57, 25 | ||
109 | }; | ||
110 | |||
111 | static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; | ||
112 | |||
113 | static uchar sbox[8][4][16] = { | ||
114 | {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, | ||
115 | {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, | ||
116 | {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, | ||
117 | {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}}, | ||
118 | |||
119 | {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, | ||
120 | {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, | ||
121 | {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, | ||
122 | {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}}, | ||
123 | |||
124 | {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, | ||
125 | {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, | ||
126 | {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, | ||
127 | {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}}, | ||
128 | |||
129 | {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, | ||
130 | {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, | ||
131 | {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, | ||
132 | {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}}, | ||
133 | |||
134 | {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, | ||
135 | {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, | ||
136 | {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, | ||
137 | {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}}, | ||
138 | |||
139 | {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, | ||
140 | {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, | ||
141 | {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, | ||
142 | {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}}, | ||
143 | |||
144 | {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, | ||
145 | {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, | ||
146 | {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, | ||
147 | {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}}, | ||
148 | |||
149 | {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, | ||
150 | {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, | ||
151 | {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, | ||
152 | {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}} | ||
153 | }; | ||
154 | |||
155 | static void | ||
156 | permute(char *out, char *in, uchar * p, int n) | ||
157 | { | ||
158 | int i; | ||
159 | for (i = 0; i < n; i++) | ||
160 | out[i] = in[p[i] - 1]; | ||
161 | } | ||
162 | |||
163 | static void | ||
164 | lshift(char *d, int count, int n) | ||
165 | { | ||
166 | char out[64]; | ||
167 | int i; | ||
168 | for (i = 0; i < n; i++) | ||
169 | out[i] = d[(i + count) % n]; | ||
170 | for (i = 0; i < n; i++) | ||
171 | d[i] = out[i]; | ||
172 | } | ||
173 | |||
174 | static void | ||
175 | concat(char *out, char *in1, char *in2, int l1, int l2) | ||
176 | { | ||
177 | while (l1--) | ||
178 | *out++ = *in1++; | ||
179 | while (l2--) | ||
180 | *out++ = *in2++; | ||
181 | } | ||
182 | |||
183 | static void | ||
184 | xor(char *out, char *in1, char *in2, int n) | ||
185 | { | ||
186 | int i; | ||
187 | for (i = 0; i < n; i++) | ||
188 | out[i] = in1[i] ^ in2[i]; | ||
189 | } | ||
190 | |||
191 | static void | ||
192 | dohash(char *out, char *in, char *key, int forw) | ||
193 | { | ||
194 | int i, j, k; | ||
195 | char *pk1; | ||
196 | char c[28]; | ||
197 | char d[28]; | ||
198 | char *cd; | ||
199 | char ki[16][48]; | ||
200 | char *pd1; | ||
201 | char l[32], r[32]; | ||
202 | char *rl; | ||
203 | |||
204 | /* Have to reduce stack usage */ | ||
205 | pk1 = kmalloc(56+56+64+64,GFP_KERNEL); | ||
206 | if(pk1 == NULL) | ||
207 | return; | ||
208 | |||
209 | cd = pk1 + 56; | ||
210 | pd1= cd + 56; | ||
211 | rl = pd1 + 64; | ||
212 | |||
213 | permute(pk1, key, perm1, 56); | ||
214 | |||
215 | for (i = 0; i < 28; i++) | ||
216 | c[i] = pk1[i]; | ||
217 | for (i = 0; i < 28; i++) | ||
218 | d[i] = pk1[i + 28]; | ||
219 | |||
220 | for (i = 0; i < 16; i++) { | ||
221 | lshift(c, sc[i], 28); | ||
222 | lshift(d, sc[i], 28); | ||
223 | |||
224 | concat(cd, c, d, 28, 28); | ||
225 | permute(ki[i], cd, perm2, 48); | ||
226 | } | ||
227 | |||
228 | permute(pd1, in, perm3, 64); | ||
229 | |||
230 | for (j = 0; j < 32; j++) { | ||
231 | l[j] = pd1[j]; | ||
232 | r[j] = pd1[j + 32]; | ||
233 | } | ||
234 | |||
235 | for (i = 0; i < 16; i++) { | ||
236 | char *er; /* er[48] */ | ||
237 | char *erk; /* erk[48] */ | ||
238 | char b[8][6]; | ||
239 | char *cb; /* cb[32] */ | ||
240 | char *pcb; /* pcb[32] */ | ||
241 | char *r2; /* r2[32] */ | ||
242 | |||
243 | er = kmalloc(48+48+32+32+32, GFP_KERNEL); | ||
244 | if(er == NULL) { | ||
245 | kfree(pk1); | ||
246 | return; | ||
247 | } | ||
248 | erk = er+48; | ||
249 | cb = erk+48; | ||
250 | pcb = cb+32; | ||
251 | r2 = pcb+32; | ||
252 | |||
253 | permute(er, r, perm4, 48); | ||
254 | |||
255 | xor(erk, er, ki[forw ? i : 15 - i], 48); | ||
256 | |||
257 | for (j = 0; j < 8; j++) | ||
258 | for (k = 0; k < 6; k++) | ||
259 | b[j][k] = erk[j * 6 + k]; | ||
260 | |||
261 | for (j = 0; j < 8; j++) { | ||
262 | int m, n; | ||
263 | m = (b[j][0] << 1) | b[j][5]; | ||
264 | |||
265 | n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << | ||
266 | 1) | b[j][4]; | ||
267 | |||
268 | for (k = 0; k < 4; k++) | ||
269 | b[j][k] = | ||
270 | (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0; | ||
271 | } | ||
272 | |||
273 | for (j = 0; j < 8; j++) | ||
274 | for (k = 0; k < 4; k++) | ||
275 | cb[j * 4 + k] = b[j][k]; | ||
276 | permute(pcb, cb, perm5, 32); | ||
277 | |||
278 | xor(r2, l, pcb, 32); | ||
279 | |||
280 | for (j = 0; j < 32; j++) | ||
281 | l[j] = r[j]; | ||
282 | |||
283 | for (j = 0; j < 32; j++) | ||
284 | r[j] = r2[j]; | ||
285 | |||
286 | kfree(er); | ||
287 | } | ||
288 | |||
289 | concat(rl, r, l, 32, 32); | ||
290 | |||
291 | permute(out, rl, perm6, 64); | ||
292 | kfree(pk1); | ||
293 | } | ||
294 | |||
295 | static void | ||
296 | str_to_key(unsigned char *str, unsigned char *key) | ||
297 | { | ||
298 | int i; | ||
299 | |||
300 | key[0] = str[0] >> 1; | ||
301 | key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); | ||
302 | key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); | ||
303 | key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); | ||
304 | key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); | ||
305 | key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); | ||
306 | key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); | ||
307 | key[7] = str[6] & 0x7F; | ||
308 | for (i = 0; i < 8; i++) { | ||
309 | key[i] = (key[i] << 1); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | static void | ||
314 | smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw) | ||
315 | { | ||
316 | int i; | ||
317 | char *outb; /* outb[64] */ | ||
318 | char *inb; /* inb[64] */ | ||
319 | char *keyb; /* keyb[64] */ | ||
320 | unsigned char key2[8]; | ||
321 | |||
322 | outb = kmalloc(64 * 3,GFP_KERNEL); | ||
323 | if(outb == NULL) | ||
324 | return; | ||
325 | |||
326 | inb = outb + 64; | ||
327 | keyb = inb + 64; | ||
328 | |||
329 | str_to_key(key, key2); | ||
330 | |||
331 | for (i = 0; i < 64; i++) { | ||
332 | inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; | ||
333 | keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; | ||
334 | outb[i] = 0; | ||
335 | } | ||
336 | |||
337 | dohash(outb, inb, keyb, forw); | ||
338 | |||
339 | for (i = 0; i < 8; i++) { | ||
340 | out[i] = 0; | ||
341 | } | ||
342 | |||
343 | for (i = 0; i < 64; i++) { | ||
344 | if (outb[i]) | ||
345 | out[i / 8] |= (1 << (7 - (i % 8))); | ||
346 | } | ||
347 | kfree(outb); | ||
348 | } | ||
349 | |||
350 | void | ||
351 | E_P16(unsigned char *p14, unsigned char *p16) | ||
352 | { | ||
353 | unsigned char sp8[8] = | ||
354 | { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; | ||
355 | smbhash(p16, sp8, p14, 1); | ||
356 | smbhash(p16 + 8, sp8, p14 + 7, 1); | ||
357 | } | ||
358 | |||
359 | void | ||
360 | E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) | ||
361 | { | ||
362 | smbhash(p24, c8, p21, 1); | ||
363 | smbhash(p24 + 8, c8, p21 + 7, 1); | ||
364 | smbhash(p24 + 16, c8, p21 + 14, 1); | ||
365 | } | ||
366 | |||
367 | void | ||
368 | D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) | ||
369 | { | ||
370 | smbhash(out, in, p14, 0); | ||
371 | smbhash(out + 8, in + 8, p14 + 7, 0); | ||
372 | } | ||
373 | |||
374 | void | ||
375 | E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) | ||
376 | { | ||
377 | smbhash(out, in, p14, 1); | ||
378 | smbhash(out + 8, in + 8, p14 + 7, 1); | ||
379 | } | ||
380 | #if 0 | ||
381 | /* these routines are currently unneeded, but may be | ||
382 | needed later */ | ||
383 | void | ||
384 | cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key) | ||
385 | { | ||
386 | unsigned char buf[8]; | ||
387 | |||
388 | smbhash(buf, in, key, 1); | ||
389 | smbhash(out, buf, key + 9, 1); | ||
390 | } | ||
391 | |||
392 | void | ||
393 | cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key) | ||
394 | { | ||
395 | unsigned char buf[8]; | ||
396 | static unsigned char key2[8]; | ||
397 | |||
398 | smbhash(buf, in, key, 1); | ||
399 | key2[0] = key[7]; | ||
400 | smbhash(out, buf, key2, 1); | ||
401 | } | ||
402 | |||
403 | void | ||
404 | cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, int forw) | ||
405 | { | ||
406 | static unsigned char key2[8]; | ||
407 | |||
408 | smbhash(out, in, key, forw); | ||
409 | key2[0] = key[7]; | ||
410 | smbhash(out + 8, in + 8, key2, forw); | ||
411 | } | ||
412 | #endif /* unneeded routines */ | ||
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c new file mode 100644 index 000000000000..6103bcdfb16d --- /dev/null +++ b/fs/cifs/smbencrypt.c | |||
@@ -0,0 +1,285 @@ | |||
1 | /* | ||
2 | Unix SMB/Netbios implementation. | ||
3 | Version 1.9. | ||
4 | SMB parameters and setup | ||
5 | Copyright (C) Andrew Tridgell 1992-2000 | ||
6 | Copyright (C) Luke Kenneth Casson Leighton 1996-2000 | ||
7 | Modified by Jeremy Allison 1995. | ||
8 | Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003 | ||
9 | Modified by Steve French (sfrench@us.ibm.com) 2002-2003 | ||
10 | |||
11 | This program is free software; you can redistribute it and/or modify | ||
12 | it under the terms of the GNU General Public License as published by | ||
13 | the Free Software Foundation; either version 2 of the License, or | ||
14 | (at your option) any later version. | ||
15 | |||
16 | This program is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with this program; if not, write to the Free Software | ||
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/fs.h> | ||
28 | #include <linux/string.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/random.h> | ||
31 | #include "cifs_unicode.h" | ||
32 | #include "cifspdu.h" | ||
33 | #include "md5.h" | ||
34 | #include "cifs_debug.h" | ||
35 | #include "cifsencrypt.h" | ||
36 | |||
37 | #ifndef FALSE | ||
38 | #define FALSE 0 | ||
39 | #endif | ||
40 | #ifndef TRUE | ||
41 | #define TRUE 1 | ||
42 | #endif | ||
43 | |||
44 | /* following came from the other byteorder.h to avoid include conflicts */ | ||
45 | #define CVAL(buf,pos) (((unsigned char *)(buf))[pos]) | ||
46 | #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) | ||
47 | #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) | ||
48 | |||
49 | /*The following definitions come from libsmb/smbencrypt.c */ | ||
50 | |||
51 | void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); | ||
52 | void E_md4hash(const unsigned char *passwd, unsigned char *p16); | ||
53 | void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]); | ||
54 | static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, | ||
55 | unsigned char p24[24]); | ||
56 | void NTLMSSPOWFencrypt(unsigned char passwd[8], | ||
57 | unsigned char *ntlmchalresp, unsigned char p24[24]); | ||
58 | void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); | ||
59 | |||
60 | /* | ||
61 | This implements the X/Open SMB password encryption | ||
62 | It takes a password, a 8 byte "crypt key" and puts 24 bytes of | ||
63 | encrypted password into p24 */ | ||
64 | /* Note that password must be uppercased and null terminated */ | ||
65 | void | ||
66 | SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) | ||
67 | { | ||
68 | unsigned char p14[15], p21[21]; | ||
69 | |||
70 | memset(p21, '\0', 21); | ||
71 | memset(p14, '\0', 14); | ||
72 | strncpy((char *) p14, (char *) passwd, 14); | ||
73 | |||
74 | /* strupper((char *)p14); *//* BB at least uppercase the easy range */ | ||
75 | E_P16(p14, p21); | ||
76 | |||
77 | SMBOWFencrypt(p21, c8, p24); | ||
78 | |||
79 | memset(p14,0,15); | ||
80 | memset(p21,0,21); | ||
81 | } | ||
82 | |||
83 | /* Routines for Windows NT MD4 Hash functions. */ | ||
84 | static int | ||
85 | _my_wcslen(__u16 * str) | ||
86 | { | ||
87 | int len = 0; | ||
88 | while (*str++ != 0) | ||
89 | len++; | ||
90 | return len; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Convert a string into an NT UNICODE string. | ||
95 | * Note that regardless of processor type | ||
96 | * this must be in intel (little-endian) | ||
97 | * format. | ||
98 | */ | ||
99 | |||
100 | static int | ||
101 | _my_mbstowcs(__u16 * dst, const unsigned char *src, int len) | ||
102 | { /* not a very good conversion routine - change/fix */ | ||
103 | int i; | ||
104 | __u16 val; | ||
105 | |||
106 | for (i = 0; i < len; i++) { | ||
107 | val = *src; | ||
108 | SSVAL(dst, 0, val); | ||
109 | dst++; | ||
110 | src++; | ||
111 | if (val == 0) | ||
112 | break; | ||
113 | } | ||
114 | return i; | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * Creates the MD4 Hash of the users password in NT UNICODE. | ||
119 | */ | ||
120 | |||
121 | void | ||
122 | E_md4hash(const unsigned char *passwd, unsigned char *p16) | ||
123 | { | ||
124 | int len; | ||
125 | __u16 wpwd[129]; | ||
126 | |||
127 | /* Password cannot be longer than 128 characters */ | ||
128 | if(passwd) { | ||
129 | len = strlen((char *) passwd); | ||
130 | if (len > 128) { | ||
131 | len = 128; | ||
132 | } | ||
133 | /* Password must be converted to NT unicode */ | ||
134 | _my_mbstowcs(wpwd, passwd, len); | ||
135 | } else | ||
136 | len = 0; | ||
137 | |||
138 | wpwd[len] = 0; /* Ensure string is null terminated */ | ||
139 | /* Calculate length in bytes */ | ||
140 | len = _my_wcslen(wpwd) * sizeof (__u16); | ||
141 | |||
142 | mdfour(p16, (unsigned char *) wpwd, len); | ||
143 | memset(wpwd,0,129 * 2); | ||
144 | } | ||
145 | |||
146 | /* Does both the NT and LM owfs of a user's password */ | ||
147 | void | ||
148 | nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) | ||
149 | { | ||
150 | char passwd[514]; | ||
151 | |||
152 | memset(passwd, '\0', 514); | ||
153 | if (strlen(pwd) < 513) | ||
154 | strcpy(passwd, pwd); | ||
155 | else | ||
156 | memcpy(passwd, pwd, 512); | ||
157 | /* Calculate the MD4 hash (NT compatible) of the password */ | ||
158 | memset(nt_p16, '\0', 16); | ||
159 | E_md4hash(passwd, nt_p16); | ||
160 | |||
161 | /* Mangle the passwords into Lanman format */ | ||
162 | passwd[14] = '\0'; | ||
163 | /* strupper(passwd); */ | ||
164 | |||
165 | /* Calculate the SMB (lanman) hash functions of the password */ | ||
166 | |||
167 | memset(p16, '\0', 16); | ||
168 | E_P16((unsigned char *) passwd, (unsigned char *) p16); | ||
169 | |||
170 | /* clear out local copy of user's password (just being paranoid). */ | ||
171 | memset(passwd, '\0', sizeof (passwd)); | ||
172 | } | ||
173 | |||
174 | /* Does the NTLMv2 owfs of a user's password */ | ||
175 | #if 0 /* function not needed yet - but will be soon */ | ||
176 | static void | ||
177 | ntv2_owf_gen(const unsigned char owf[16], const char *user_n, | ||
178 | const char *domain_n, unsigned char kr_buf[16], | ||
179 | const struct nls_table *nls_codepage) | ||
180 | { | ||
181 | wchar_t * user_u; | ||
182 | wchar_t * dom_u; | ||
183 | int user_l, domain_l; | ||
184 | struct HMACMD5Context ctx; | ||
185 | |||
186 | /* might as well do one alloc to hold both (user_u and dom_u) */ | ||
187 | user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL); | ||
188 | if(user_u == NULL) | ||
189 | return; | ||
190 | dom_u = user_u + 1024; | ||
191 | |||
192 | /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); | ||
193 | push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */ | ||
194 | |||
195 | /* BB user and domain may need to be uppercased */ | ||
196 | user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage); | ||
197 | domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage); | ||
198 | |||
199 | user_l++; /* trailing null */ | ||
200 | domain_l++; | ||
201 | |||
202 | hmac_md5_init_limK_to_64(owf, 16, &ctx); | ||
203 | hmac_md5_update((const unsigned char *) user_u, user_l * 2, &ctx); | ||
204 | hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx); | ||
205 | hmac_md5_final(kr_buf, &ctx); | ||
206 | |||
207 | kfree(user_u); | ||
208 | } | ||
209 | #endif | ||
210 | |||
211 | /* Does the des encryption from the NT or LM MD4 hash. */ | ||
212 | static void | ||
213 | SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, | ||
214 | unsigned char p24[24]) | ||
215 | { | ||
216 | unsigned char p21[21]; | ||
217 | |||
218 | memset(p21, '\0', 21); | ||
219 | |||
220 | memcpy(p21, passwd, 16); | ||
221 | E_P24(p21, c8, p24); | ||
222 | } | ||
223 | |||
224 | /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ | ||
225 | void | ||
226 | NTLMSSPOWFencrypt(unsigned char passwd[8], | ||
227 | unsigned char *ntlmchalresp, unsigned char p24[24]) | ||
228 | { | ||
229 | unsigned char p21[21]; | ||
230 | |||
231 | memset(p21, '\0', 21); | ||
232 | memcpy(p21, passwd, 8); | ||
233 | memset(p21 + 8, 0xbd, 8); | ||
234 | |||
235 | E_P24(p21, ntlmchalresp, p24); | ||
236 | } | ||
237 | |||
238 | /* Does the NT MD4 hash then des encryption. */ | ||
239 | |||
240 | void | ||
241 | SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) | ||
242 | { | ||
243 | unsigned char p21[21]; | ||
244 | |||
245 | memset(p21, '\0', 21); | ||
246 | |||
247 | E_md4hash(passwd, p21); | ||
248 | SMBOWFencrypt(p21, c8, p24); | ||
249 | } | ||
250 | |||
251 | |||
252 | /* Does the md5 encryption from the NT hash for NTLMv2. */ | ||
253 | /* These routines will be needed later */ | ||
254 | #if 0 | ||
255 | static void | ||
256 | SMBOWFencrypt_ntv2(const unsigned char kr[16], | ||
257 | const struct data_blob * srv_chal, | ||
258 | const struct data_blob * cli_chal, unsigned char resp_buf[16]) | ||
259 | { | ||
260 | struct HMACMD5Context ctx; | ||
261 | |||
262 | hmac_md5_init_limK_to_64(kr, 16, &ctx); | ||
263 | hmac_md5_update(srv_chal->data, srv_chal->length, &ctx); | ||
264 | hmac_md5_update(cli_chal->data, cli_chal->length, &ctx); | ||
265 | hmac_md5_final(resp_buf, &ctx); | ||
266 | } | ||
267 | |||
268 | static void | ||
269 | SMBsesskeygen_ntv2(const unsigned char kr[16], | ||
270 | const unsigned char *nt_resp, __u8 sess_key[16]) | ||
271 | { | ||
272 | struct HMACMD5Context ctx; | ||
273 | |||
274 | hmac_md5_init_limK_to_64(kr, 16, &ctx); | ||
275 | hmac_md5_update(nt_resp, 16, &ctx); | ||
276 | hmac_md5_final((unsigned char *) sess_key, &ctx); | ||
277 | } | ||
278 | |||
279 | static void | ||
280 | SMBsesskeygen_ntv1(const unsigned char kr[16], | ||
281 | const unsigned char *nt_resp, __u8 sess_key[16]) | ||
282 | { | ||
283 | mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16); | ||
284 | } | ||
285 | #endif | ||
diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h new file mode 100644 index 000000000000..e21f1384661f --- /dev/null +++ b/fs/cifs/smberr.h | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * fs/cifs/smberr.h | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2002,2004 | ||
5 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
6 | * | ||
7 | * See Error Codes section of the SNIA CIFS Specification | ||
8 | * for more information | ||
9 | * | ||
10 | * This library is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU Lesser General Public License as published | ||
12 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This library is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
18 | * the GNU Lesser General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU Lesser General Public License | ||
21 | * along with this library; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | #define SUCCESS 0 /* The request was successful. */ | ||
26 | #define ERRDOS 0x01 /* Error is from the core DOS operating system set */ | ||
27 | #define ERRSRV 0x02 /* Error is generated by the file server daemon */ | ||
28 | #define ERRHRD 0x03 /* Error is a hardware error. */ | ||
29 | #define ERRCMD 0xFF /* Command was not in the "SMB" format. */ | ||
30 | |||
31 | /* The following error codes may be generated with the SUCCESS error class.*/ | ||
32 | |||
33 | #define SUCCESS 0 /* The request was successful. */ | ||
34 | |||
35 | /* The following error codes may be generated with the ERRDOS error class.*/ | ||
36 | |||
37 | #define ERRbadfunc 1 /* Invalid function. The server did not recognize or could not perform a system call generated by the server, e.g., set the DIRECTORY attribute on a data file, invalid seek mode. */ | ||
38 | #define ERRbadfile 2 /*File not found. The last component of a file's pathname could not be found. */ | ||
39 | #define ERRbadpath 3 /* Directory invalid. A directory component in a pathname could not be found. */ | ||
40 | #define ERRnofids 4 /* Too many open files. The server has no file handles available. */ | ||
41 | #define ERRnoaccess 5 /* Access denied, the client's context does not permit the requested function. This includes the following conditions: invalid rename command, write to Fid open for read only, read on Fid open for write only, attempt to delete a non-empty directory */ | ||
42 | #define ERRbadfid 6 /* Invalid file handle. The file handle specified was not recognized by the server. */ | ||
43 | #define ERRbadmcb 7 /* Memory control blocks destroyed. */ | ||
44 | #define ERRnomem 8 /* Insufficient server memory to perform the requested function. */ | ||
45 | #define ERRbadmem 9 /* Invalid memory block address. */ | ||
46 | #define ERRbadenv 10 /* Invalid environment. */ | ||
47 | #define ERRbadformat 11 /* Invalid format. */ | ||
48 | #define ERRbadaccess 12 /* Invalid open mode. */ | ||
49 | #define ERRbaddata 13 /* Invalid data (generated only by IOCTL calls within the server). */ | ||
50 | #define ERRbaddrive 15 /* Invalid drive specified. */ | ||
51 | #define ERRremcd 16 /* A Delete Directory request attempted to remove the server's current directory. */ | ||
52 | #define ERRdiffdevice 17 /* Not same device (e.g., a cross volume rename was attempted */ | ||
53 | #define ERRnofiles 18 /* A File Search command can find no more files matching the specified criteria. */ | ||
54 | #define ERRgeneral 31 | ||
55 | #define ERRbadshare 32 /* The sharing mode specified for an Open conflicts with existing FIDs on the file. */ | ||
56 | #define ERRlock 33 /* A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process. */ | ||
57 | #define ERRunsup 50 | ||
58 | #define ERRnosuchshare 67 | ||
59 | #define ERRfilexists 80 /* The file named in the request already exists. */ | ||
60 | #define ERRinvparm 87 | ||
61 | #define ERRdiskfull 112 | ||
62 | #define ERRinvname 123 | ||
63 | #define ERRinvlevel 124 | ||
64 | #define ERRdirnotempty 145 | ||
65 | #define ERRnotlocked 158 | ||
66 | #define ERRalreadyexists 183 | ||
67 | #define ERRbadpipe 230 | ||
68 | #define ERRpipebusy 231 | ||
69 | #define ERRpipeclosing 232 | ||
70 | #define ERRnotconnected 233 | ||
71 | #define ERRmoredata 234 | ||
72 | #define ERReasnotsupported 282 | ||
73 | #define ErrQuota 0x200 /* The operation would cause a quota limit to be exceeded. */ | ||
74 | #define ErrNotALink 0x201 /* A link operation was performed on a pathname that | ||
75 | was not a link. */ | ||
76 | |||
77 | /* Following error codes may be generated with the ERRSRV error | ||
78 | class.*/ | ||
79 | |||
80 | #define ERRerror 1 /* Non-specific error code. It is returned under the following conditions: resource other than disk space exhausted (e.g. TIDs), first SMB command was not negotiate, multiple negotiates attempted, and internal server error. */ | ||
81 | #define ERRbadpw 2 /* Bad password - name/password pair in a TreeConnect or Session Setup are invalid. */ | ||
82 | #define ERRbadtype 3 /* used for indicating DFS referral needed */ | ||
83 | #define ERRaccess 4 /* The client does not have the necessary access rights within the specified context for requested function. */ | ||
84 | #define ERRinvtid 5 /* The Tid specified in a command was invalid. */ | ||
85 | #define ERRinvnetname 6 /* Invalid network name in tree connect. */ | ||
86 | #define ERRinvdevice 7 /* Invalid device - printer request made to non-printer connection or non-printer request made to printer connection. */ | ||
87 | #define ERRqfull 49 /* Print queue full (files) -- returned by open print file. */ | ||
88 | #define ERRqtoobig 50 /* Print queue full -- no space. */ | ||
89 | #define ERRqeof 51 /* EOF on print queue dump */ | ||
90 | #define ERRinvpfid 52 /* Invalid print file FID. */ | ||
91 | #define ERRsmbcmd 64 /* The server did not recognize the command received. */ | ||
92 | #define ERRsrverror 65 /* The server encountered an internal error, e.g., system file unavailable. */ | ||
93 | #define ERRbadBID 66 /* (obsolete) */ | ||
94 | #define ERRfilespecs 67 /* The Fid and pathname parameters contained an invalid combination of values. */ | ||
95 | #define ERRbadLink 68 /* (obsolete) */ | ||
96 | #define ERRbadpermits 69 /* The access permissions specified for a file or directory are not a valid combination. */ | ||
97 | #define ERRbadPID 70 | ||
98 | #define ERRsetattrmode 71 /* attribute (mode) is invalid */ | ||
99 | #define ERRpaused 81 /* Server is paused */ | ||
100 | #define ERRmsgoff 82 /* reserved - messaging off */ | ||
101 | #define ERRnoroom 83 /* reserved - no room for message */ | ||
102 | #define ERRrmuns 87 /* reserved - too many remote names */ | ||
103 | #define ERRtimeout 88 /* operation timed out */ | ||
104 | #define ERRnoresource 89 /* No resources available for request */ | ||
105 | #define ERRtoomanyuids 90 /* Too many UIDs active on this session */ | ||
106 | #define ERRbaduid 91 /* The UID is not known as a valid user */ | ||
107 | #define ERRusempx 250 /* temporarily unable to use raw */ | ||
108 | #define ERRusestd 251 /* temporarily unable to use either raw or mpx */ | ||
109 | #define ERR_NOTIFY_ENUM_DIR 1024 | ||
110 | #define ERRaccountexpired 2239 | ||
111 | #define ERRbadclient 2240 | ||
112 | #define ERRbadLogonTime 2241 | ||
113 | #define ERRpasswordExpired 2242 | ||
114 | #define ERRnetlogonNotStarted 2455 | ||
115 | #define ERRnosupport 0xFFFF | ||
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c new file mode 100644 index 000000000000..af13e526b150 --- /dev/null +++ b/fs/cifs/transport.c | |||
@@ -0,0 +1,619 @@ | |||
1 | /* | ||
2 | * fs/cifs/transport.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 | |||
22 | #include <linux/fs.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/wait.h> | ||
25 | #include <linux/net.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <asm/uaccess.h> | ||
28 | #include <asm/processor.h> | ||
29 | #include <linux/mempool.h> | ||
30 | #include "cifspdu.h" | ||
31 | #include "cifsglob.h" | ||
32 | #include "cifsproto.h" | ||
33 | #include "cifs_debug.h" | ||
34 | |||
35 | extern mempool_t *cifs_mid_poolp; | ||
36 | extern kmem_cache_t *cifs_oplock_cachep; | ||
37 | |||
38 | static struct mid_q_entry * | ||
39 | AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | ||
40 | { | ||
41 | struct mid_q_entry *temp; | ||
42 | |||
43 | if (ses == NULL) { | ||
44 | cERROR(1, ("Null session passed in to AllocMidQEntry ")); | ||
45 | return NULL; | ||
46 | } | ||
47 | if (ses->server == NULL) { | ||
48 | cERROR(1, ("Null TCP session in AllocMidQEntry")); | ||
49 | return NULL; | ||
50 | } | ||
51 | |||
52 | temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS); | ||
53 | if (temp == NULL) | ||
54 | return temp; | ||
55 | else { | ||
56 | memset(temp, 0, sizeof (struct mid_q_entry)); | ||
57 | temp->mid = smb_buffer->Mid; /* always LE */ | ||
58 | temp->pid = current->pid; | ||
59 | temp->command = smb_buffer->Command; | ||
60 | cFYI(1, ("For smb_command %d", temp->command)); | ||
61 | do_gettimeofday(&temp->when_sent); | ||
62 | temp->ses = ses; | ||
63 | temp->tsk = current; | ||
64 | } | ||
65 | |||
66 | spin_lock(&GlobalMid_Lock); | ||
67 | list_add_tail(&temp->qhead, &ses->server->pending_mid_q); | ||
68 | atomic_inc(&midCount); | ||
69 | temp->midState = MID_REQUEST_ALLOCATED; | ||
70 | spin_unlock(&GlobalMid_Lock); | ||
71 | return temp; | ||
72 | } | ||
73 | |||
74 | static void | ||
75 | DeleteMidQEntry(struct mid_q_entry *midEntry) | ||
76 | { | ||
77 | spin_lock(&GlobalMid_Lock); | ||
78 | midEntry->midState = MID_FREE; | ||
79 | list_del(&midEntry->qhead); | ||
80 | atomic_dec(&midCount); | ||
81 | spin_unlock(&GlobalMid_Lock); | ||
82 | cifs_buf_release(midEntry->resp_buf); | ||
83 | mempool_free(midEntry, cifs_mid_poolp); | ||
84 | } | ||
85 | |||
86 | struct oplock_q_entry * | ||
87 | AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon) | ||
88 | { | ||
89 | struct oplock_q_entry *temp; | ||
90 | if ((pinode== NULL) || (tcon == NULL)) { | ||
91 | cERROR(1, ("Null parms passed to AllocOplockQEntry")); | ||
92 | return NULL; | ||
93 | } | ||
94 | temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep, | ||
95 | SLAB_KERNEL); | ||
96 | if (temp == NULL) | ||
97 | return temp; | ||
98 | else { | ||
99 | temp->pinode = pinode; | ||
100 | temp->tcon = tcon; | ||
101 | temp->netfid = fid; | ||
102 | spin_lock(&GlobalMid_Lock); | ||
103 | list_add_tail(&temp->qhead, &GlobalOplock_Q); | ||
104 | spin_unlock(&GlobalMid_Lock); | ||
105 | } | ||
106 | return temp; | ||
107 | |||
108 | } | ||
109 | |||
110 | void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry) | ||
111 | { | ||
112 | spin_lock(&GlobalMid_Lock); | ||
113 | /* should we check if list empty first? */ | ||
114 | list_del(&oplockEntry->qhead); | ||
115 | spin_unlock(&GlobalMid_Lock); | ||
116 | kmem_cache_free(cifs_oplock_cachep, oplockEntry); | ||
117 | } | ||
118 | |||
119 | int | ||
120 | smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | ||
121 | unsigned int smb_buf_length, struct sockaddr *sin) | ||
122 | { | ||
123 | int rc = 0; | ||
124 | int i = 0; | ||
125 | struct msghdr smb_msg; | ||
126 | struct kvec iov; | ||
127 | unsigned len = smb_buf_length + 4; | ||
128 | |||
129 | if(ssocket == NULL) | ||
130 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | ||
131 | iov.iov_base = smb_buffer; | ||
132 | iov.iov_len = len; | ||
133 | |||
134 | smb_msg.msg_name = sin; | ||
135 | smb_msg.msg_namelen = sizeof (struct sockaddr); | ||
136 | smb_msg.msg_control = NULL; | ||
137 | smb_msg.msg_controllen = 0; | ||
138 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ | ||
139 | |||
140 | /* smb header is converted in header_assemble. bcc and rest of SMB word | ||
141 | area, and byte area if necessary, is converted to littleendian in | ||
142 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send | ||
143 | Flags2 is converted in SendReceive */ | ||
144 | |||
145 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | ||
146 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | ||
147 | dump_smb(smb_buffer, len); | ||
148 | |||
149 | while (len > 0) { | ||
150 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); | ||
151 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | ||
152 | i++; | ||
153 | if(i > 60) { | ||
154 | cERROR(1, | ||
155 | ("sends on sock %p stuck for 30 seconds", | ||
156 | ssocket)); | ||
157 | rc = -EAGAIN; | ||
158 | break; | ||
159 | } | ||
160 | msleep(500); | ||
161 | continue; | ||
162 | } | ||
163 | if (rc < 0) | ||
164 | break; | ||
165 | iov.iov_base += rc; | ||
166 | iov.iov_len -= rc; | ||
167 | len -= rc; | ||
168 | } | ||
169 | |||
170 | if (rc < 0) { | ||
171 | cERROR(1,("Error %d sending data on socket to server.", rc)); | ||
172 | } else { | ||
173 | rc = 0; | ||
174 | } | ||
175 | |||
176 | return rc; | ||
177 | } | ||
178 | |||
179 | #ifdef CIFS_EXPERIMENTAL | ||
180 | /* BB finish off this function, adding support for writing set of pages as iovec */ | ||
181 | /* and also adding support for operations that need to parse the response smb */ | ||
182 | |||
183 | int | ||
184 | smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | ||
185 | unsigned int smb_buf_length, struct kvec * write_vector /* page list */, struct sockaddr *sin) | ||
186 | { | ||
187 | int rc = 0; | ||
188 | int i = 0; | ||
189 | struct msghdr smb_msg; | ||
190 | number_of_pages += 1; /* account for SMB header */ | ||
191 | struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec)); | ||
192 | if(i=0;i<num_pages-1;i++ | ||
193 | unsigned len = smb_buf_length + 4; | ||
194 | |||
195 | if(ssocket == NULL) | ||
196 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | ||
197 | iov.iov_base = smb_buffer; | ||
198 | iov.iov_len = len; | ||
199 | |||
200 | smb_msg.msg_name = sin; | ||
201 | smb_msg.msg_namelen = sizeof (struct sockaddr); | ||
202 | smb_msg.msg_control = NULL; | ||
203 | smb_msg.msg_controllen = 0; | ||
204 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ | ||
205 | |||
206 | /* smb header is converted in header_assemble. bcc and rest of SMB word | ||
207 | area, and byte area if necessary, is converted to littleendian in | ||
208 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send | ||
209 | Flags2 is converted in SendReceive */ | ||
210 | |||
211 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | ||
212 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | ||
213 | dump_smb(smb_buffer, len); | ||
214 | |||
215 | while (len > 0) { | ||
216 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, len?); | ||
217 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | ||
218 | i++; | ||
219 | if(i > 60) { | ||
220 | cERROR(1, | ||
221 | ("sends on sock %p stuck for 30 seconds", | ||
222 | ssocket)); | ||
223 | rc = -EAGAIN; | ||
224 | break; | ||
225 | } | ||
226 | msleep(500); | ||
227 | continue; | ||
228 | } | ||
229 | if (rc < 0) | ||
230 | break; | ||
231 | iov.iov_base += rc; | ||
232 | iov.iov_len -= rc; | ||
233 | len -= rc; | ||
234 | } | ||
235 | |||
236 | if (rc < 0) { | ||
237 | cERROR(1,("Error %d sending data on socket to server.", rc)); | ||
238 | } else { | ||
239 | rc = 0; | ||
240 | } | ||
241 | |||
242 | return rc; | ||
243 | } | ||
244 | |||
245 | |||
246 | int | ||
247 | CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | ||
248 | struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op) | ||
249 | { | ||
250 | int rc = 0; | ||
251 | unsigned long timeout = 15 * HZ; | ||
252 | struct mid_q_entry *midQ = NULL; | ||
253 | |||
254 | if (ses == NULL) { | ||
255 | cERROR(1,("Null smb session")); | ||
256 | return -EIO; | ||
257 | } | ||
258 | if(ses->server == NULL) { | ||
259 | cERROR(1,("Null tcp session")); | ||
260 | return -EIO; | ||
261 | } | ||
262 | if(pbytes_returned == NULL) | ||
263 | return -EIO; | ||
264 | else | ||
265 | *pbytes_returned = 0; | ||
266 | |||
267 | |||
268 | |||
269 | /* Ensure that we do not send more than 50 overlapping requests | ||
270 | to the same server. We may make this configurable later or | ||
271 | use ses->maxReq */ | ||
272 | if(long_op == -1) { | ||
273 | /* oplock breaks must not be held up */ | ||
274 | atomic_inc(&ses->server->inFlight); | ||
275 | } else { | ||
276 | spin_lock(&GlobalMid_Lock); | ||
277 | while(1) { | ||
278 | if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ | ||
279 | spin_unlock(&GlobalMid_Lock); | ||
280 | wait_event(ses->server->request_q, | ||
281 | atomic_read(&ses->server->inFlight) | ||
282 | < cifs_max_pending); | ||
283 | spin_lock(&GlobalMid_Lock); | ||
284 | } else { | ||
285 | if(ses->server->tcpStatus == CifsExiting) { | ||
286 | spin_unlock(&GlobalMid_Lock); | ||
287 | return -ENOENT; | ||
288 | } | ||
289 | |||
290 | /* can not count locking commands against total since | ||
291 | they are allowed to block on server */ | ||
292 | |||
293 | if(long_op < 3) { | ||
294 | /* update # of requests on the wire to server */ | ||
295 | atomic_inc(&ses->server->inFlight); | ||
296 | } | ||
297 | spin_unlock(&GlobalMid_Lock); | ||
298 | break; | ||
299 | } | ||
300 | } | ||
301 | } | ||
302 | /* make sure that we sign in the same order that we send on this socket | ||
303 | and avoid races inside tcp sendmsg code that could cause corruption | ||
304 | of smb data */ | ||
305 | |||
306 | down(&ses->server->tcpSem); | ||
307 | |||
308 | if (ses->server->tcpStatus == CifsExiting) { | ||
309 | rc = -ENOENT; | ||
310 | goto cifs_out_label; | ||
311 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { | ||
312 | cFYI(1,("tcp session dead - return to caller to retry")); | ||
313 | rc = -EAGAIN; | ||
314 | goto cifs_out_label; | ||
315 | } else if (ses->status != CifsGood) { | ||
316 | /* check if SMB session is bad because we are setting it up */ | ||
317 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && | ||
318 | (in_buf->Command != SMB_COM_NEGOTIATE)) { | ||
319 | rc = -EAGAIN; | ||
320 | goto cifs_out_label; | ||
321 | } /* else ok - we are setting up session */ | ||
322 | } | ||
323 | midQ = AllocMidQEntry(in_buf, ses); | ||
324 | if (midQ == NULL) { | ||
325 | up(&ses->server->tcpSem); | ||
326 | /* If not lock req, update # of requests on wire to server */ | ||
327 | if(long_op < 3) { | ||
328 | atomic_dec(&ses->server->inFlight); | ||
329 | wake_up(&ses->server->request_q); | ||
330 | } | ||
331 | return -ENOMEM; | ||
332 | } | ||
333 | |||
334 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | ||
335 | up(&ses->server->tcpSem); | ||
336 | cERROR(1, | ||
337 | ("Illegal length, greater than maximum frame, %d ", | ||
338 | in_buf->smb_buf_length)); | ||
339 | DeleteMidQEntry(midQ); | ||
340 | /* If not lock req, update # of requests on wire to server */ | ||
341 | if(long_op < 3) { | ||
342 | atomic_dec(&ses->server->inFlight); | ||
343 | wake_up(&ses->server->request_q); | ||
344 | } | ||
345 | return -EIO; | ||
346 | } | ||
347 | |||
348 | /* BB can we sign efficiently in this path? */ | ||
349 | rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); | ||
350 | |||
351 | midQ->midState = MID_REQUEST_SUBMITTED; | ||
352 | /* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec, | ||
353 | (struct sockaddr *) &(ses->server->addr.sockAddr));*/ | ||
354 | if(rc < 0) { | ||
355 | DeleteMidQEntry(midQ); | ||
356 | up(&ses->server->tcpSem); | ||
357 | /* If not lock req, update # of requests on wire to server */ | ||
358 | if(long_op < 3) { | ||
359 | atomic_dec(&ses->server->inFlight); | ||
360 | wake_up(&ses->server->request_q); | ||
361 | } | ||
362 | return rc; | ||
363 | } else | ||
364 | up(&ses->server->tcpSem); | ||
365 | cifs_out_label: | ||
366 | if(midQ) | ||
367 | DeleteMidQEntry(midQ); | ||
368 | |||
369 | if(long_op < 3) { | ||
370 | atomic_dec(&ses->server->inFlight); | ||
371 | wake_up(&ses->server->request_q); | ||
372 | } | ||
373 | |||
374 | return rc; | ||
375 | } | ||
376 | |||
377 | |||
378 | #endif /* CIFS_EXPERIMENTAL */ | ||
379 | |||
380 | int | ||
381 | SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | ||
382 | struct smb_hdr *in_buf, struct smb_hdr *out_buf, | ||
383 | int *pbytes_returned, const int long_op) | ||
384 | { | ||
385 | int rc = 0; | ||
386 | unsigned int receive_len; | ||
387 | unsigned long timeout; | ||
388 | struct mid_q_entry *midQ; | ||
389 | |||
390 | if (ses == NULL) { | ||
391 | cERROR(1,("Null smb session")); | ||
392 | return -EIO; | ||
393 | } | ||
394 | if(ses->server == NULL) { | ||
395 | cERROR(1,("Null tcp session")); | ||
396 | return -EIO; | ||
397 | } | ||
398 | |||
399 | /* Ensure that we do not send more than 50 overlapping requests | ||
400 | to the same server. We may make this configurable later or | ||
401 | use ses->maxReq */ | ||
402 | if(long_op == -1) { | ||
403 | /* oplock breaks must not be held up */ | ||
404 | atomic_inc(&ses->server->inFlight); | ||
405 | } else { | ||
406 | spin_lock(&GlobalMid_Lock); | ||
407 | while(1) { | ||
408 | if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ | ||
409 | spin_unlock(&GlobalMid_Lock); | ||
410 | wait_event(ses->server->request_q, | ||
411 | atomic_read(&ses->server->inFlight) | ||
412 | < cifs_max_pending); | ||
413 | spin_lock(&GlobalMid_Lock); | ||
414 | } else { | ||
415 | if(ses->server->tcpStatus == CifsExiting) { | ||
416 | spin_unlock(&GlobalMid_Lock); | ||
417 | return -ENOENT; | ||
418 | } | ||
419 | |||
420 | /* can not count locking commands against total since | ||
421 | they are allowed to block on server */ | ||
422 | |||
423 | if(long_op < 3) { | ||
424 | /* update # of requests on the wire to server */ | ||
425 | atomic_inc(&ses->server->inFlight); | ||
426 | } | ||
427 | spin_unlock(&GlobalMid_Lock); | ||
428 | break; | ||
429 | } | ||
430 | } | ||
431 | } | ||
432 | /* make sure that we sign in the same order that we send on this socket | ||
433 | and avoid races inside tcp sendmsg code that could cause corruption | ||
434 | of smb data */ | ||
435 | |||
436 | down(&ses->server->tcpSem); | ||
437 | |||
438 | if (ses->server->tcpStatus == CifsExiting) { | ||
439 | rc = -ENOENT; | ||
440 | goto out_unlock; | ||
441 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { | ||
442 | cFYI(1,("tcp session dead - return to caller to retry")); | ||
443 | rc = -EAGAIN; | ||
444 | goto out_unlock; | ||
445 | } else if (ses->status != CifsGood) { | ||
446 | /* check if SMB session is bad because we are setting it up */ | ||
447 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && | ||
448 | (in_buf->Command != SMB_COM_NEGOTIATE)) { | ||
449 | rc = -EAGAIN; | ||
450 | goto out_unlock; | ||
451 | } /* else ok - we are setting up session */ | ||
452 | } | ||
453 | midQ = AllocMidQEntry(in_buf, ses); | ||
454 | if (midQ == NULL) { | ||
455 | up(&ses->server->tcpSem); | ||
456 | /* If not lock req, update # of requests on wire to server */ | ||
457 | if(long_op < 3) { | ||
458 | atomic_dec(&ses->server->inFlight); | ||
459 | wake_up(&ses->server->request_q); | ||
460 | } | ||
461 | return -ENOMEM; | ||
462 | } | ||
463 | |||
464 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | ||
465 | up(&ses->server->tcpSem); | ||
466 | cERROR(1, | ||
467 | ("Illegal length, greater than maximum frame, %d ", | ||
468 | in_buf->smb_buf_length)); | ||
469 | DeleteMidQEntry(midQ); | ||
470 | /* If not lock req, update # of requests on wire to server */ | ||
471 | if(long_op < 3) { | ||
472 | atomic_dec(&ses->server->inFlight); | ||
473 | wake_up(&ses->server->request_q); | ||
474 | } | ||
475 | return -EIO; | ||
476 | } | ||
477 | |||
478 | rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); | ||
479 | |||
480 | midQ->midState = MID_REQUEST_SUBMITTED; | ||
481 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | ||
482 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | ||
483 | if(rc < 0) { | ||
484 | DeleteMidQEntry(midQ); | ||
485 | up(&ses->server->tcpSem); | ||
486 | /* If not lock req, update # of requests on wire to server */ | ||
487 | if(long_op < 3) { | ||
488 | atomic_dec(&ses->server->inFlight); | ||
489 | wake_up(&ses->server->request_q); | ||
490 | } | ||
491 | return rc; | ||
492 | } else | ||
493 | up(&ses->server->tcpSem); | ||
494 | if (long_op == -1) | ||
495 | goto cifs_no_response_exit; | ||
496 | else if (long_op == 2) /* writes past end of file can take looooong time */ | ||
497 | timeout = 300 * HZ; | ||
498 | else if (long_op == 1) | ||
499 | timeout = 45 * HZ; /* should be greater than | ||
500 | servers oplock break timeout (about 43 seconds) */ | ||
501 | else if (long_op > 2) { | ||
502 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
503 | } else | ||
504 | timeout = 15 * HZ; | ||
505 | /* wait for 15 seconds or until woken up due to response arriving or | ||
506 | due to last connection to this server being unmounted */ | ||
507 | if (signal_pending(current)) { | ||
508 | /* if signal pending do not hold up user for full smb timeout | ||
509 | but we still give response a change to complete */ | ||
510 | timeout = 2 * HZ; | ||
511 | } | ||
512 | |||
513 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
514 | if(timeout != MAX_SCHEDULE_TIMEOUT) { | ||
515 | timeout += jiffies; | ||
516 | wait_event(ses->server->response_q, | ||
517 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
518 | time_after(jiffies, timeout) || | ||
519 | ((ses->server->tcpStatus != CifsGood) && | ||
520 | (ses->server->tcpStatus != CifsNew))); | ||
521 | } else { | ||
522 | wait_event(ses->server->response_q, | ||
523 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
524 | ((ses->server->tcpStatus != CifsGood) && | ||
525 | (ses->server->tcpStatus != CifsNew))); | ||
526 | } | ||
527 | |||
528 | spin_lock(&GlobalMid_Lock); | ||
529 | if (midQ->resp_buf) { | ||
530 | spin_unlock(&GlobalMid_Lock); | ||
531 | receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf); | ||
532 | } else { | ||
533 | cERROR(1,("No response buffer")); | ||
534 | if(midQ->midState == MID_REQUEST_SUBMITTED) { | ||
535 | if(ses->server->tcpStatus == CifsExiting) | ||
536 | rc = -EHOSTDOWN; | ||
537 | else { | ||
538 | ses->server->tcpStatus = CifsNeedReconnect; | ||
539 | midQ->midState = MID_RETRY_NEEDED; | ||
540 | } | ||
541 | } | ||
542 | |||
543 | if (rc != -EHOSTDOWN) { | ||
544 | if(midQ->midState == MID_RETRY_NEEDED) { | ||
545 | rc = -EAGAIN; | ||
546 | cFYI(1,("marking request for retry")); | ||
547 | } else { | ||
548 | rc = -EIO; | ||
549 | } | ||
550 | } | ||
551 | spin_unlock(&GlobalMid_Lock); | ||
552 | DeleteMidQEntry(midQ); | ||
553 | /* If not lock req, update # of requests on wire to server */ | ||
554 | if(long_op < 3) { | ||
555 | atomic_dec(&ses->server->inFlight); | ||
556 | wake_up(&ses->server->request_q); | ||
557 | } | ||
558 | return rc; | ||
559 | } | ||
560 | |||
561 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | ||
562 | cERROR(1, | ||
563 | ("Frame too large received. Length: %d Xid: %d", | ||
564 | receive_len, xid)); | ||
565 | rc = -EIO; | ||
566 | } else { /* rcvd frame is ok */ | ||
567 | |||
568 | if (midQ->resp_buf && out_buf | ||
569 | && (midQ->midState == MID_RESPONSE_RECEIVED)) { | ||
570 | out_buf->smb_buf_length = receive_len; | ||
571 | memcpy((char *)out_buf + 4, | ||
572 | (char *)midQ->resp_buf + 4, | ||
573 | receive_len); | ||
574 | |||
575 | dump_smb(out_buf, 92); | ||
576 | /* convert the length into a more usable form */ | ||
577 | if((receive_len > 24) && | ||
578 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { | ||
579 | rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */ | ||
580 | if(rc) | ||
581 | cFYI(1,("Unexpected signature received from server")); | ||
582 | } | ||
583 | |||
584 | *pbytes_returned = out_buf->smb_buf_length; | ||
585 | |||
586 | /* BB special case reconnect tid and reconnect uid here? */ | ||
587 | rc = map_smb_to_linux_error(out_buf); | ||
588 | |||
589 | /* convert ByteCount if necessary */ | ||
590 | if (receive_len >= | ||
591 | sizeof (struct smb_hdr) - | ||
592 | 4 /* do not count RFC1001 header */ + | ||
593 | (2 * out_buf->WordCount) + 2 /* bcc */ ) | ||
594 | BCC(out_buf) = le16_to_cpu(BCC(out_buf)); | ||
595 | } else { | ||
596 | rc = -EIO; | ||
597 | cFYI(1,("Bad MID state? ")); | ||
598 | } | ||
599 | } | ||
600 | cifs_no_response_exit: | ||
601 | DeleteMidQEntry(midQ); | ||
602 | |||
603 | if(long_op < 3) { | ||
604 | atomic_dec(&ses->server->inFlight); | ||
605 | wake_up(&ses->server->request_q); | ||
606 | } | ||
607 | |||
608 | return rc; | ||
609 | |||
610 | out_unlock: | ||
611 | up(&ses->server->tcpSem); | ||
612 | /* If not lock req, update # of requests on wire to server */ | ||
613 | if(long_op < 3) { | ||
614 | atomic_dec(&ses->server->inFlight); | ||
615 | wake_up(&ses->server->request_q); | ||
616 | } | ||
617 | |||
618 | return rc; | ||
619 | } | ||
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c new file mode 100644 index 000000000000..549afa184fd6 --- /dev/null +++ b/fs/cifs/xattr.c | |||
@@ -0,0 +1,334 @@ | |||
1 | /* | ||
2 | * fs/cifs/xattr.c | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2003 | ||
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 | |||
22 | #include <linux/fs.h> | ||
23 | #include <linux/posix_acl_xattr.h> | ||
24 | #include "cifsfs.h" | ||
25 | #include "cifspdu.h" | ||
26 | #include "cifsglob.h" | ||
27 | #include "cifsproto.h" | ||
28 | #include "cifs_debug.h" | ||
29 | |||
30 | #define MAX_EA_VALUE_SIZE 65535 | ||
31 | #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib" | ||
32 | #define CIFS_XATTR_USER_PREFIX "user." | ||
33 | #define CIFS_XATTR_SYSTEM_PREFIX "system." | ||
34 | #define CIFS_XATTR_OS2_PREFIX "os2." | ||
35 | #define CIFS_XATTR_SECURITY_PREFIX ".security" | ||
36 | #define CIFS_XATTR_TRUSTED_PREFIX "trusted." | ||
37 | #define XATTR_TRUSTED_PREFIX_LEN 8 | ||
38 | #define XATTR_SECURITY_PREFIX_LEN 9 | ||
39 | /* BB need to add server (Samba e.g) support for security and trusted prefix */ | ||
40 | |||
41 | |||
42 | |||
43 | int cifs_removexattr(struct dentry * direntry, const char * ea_name) | ||
44 | { | ||
45 | int rc = -EOPNOTSUPP; | ||
46 | #ifdef CONFIG_CIFS_XATTR | ||
47 | int xid; | ||
48 | struct cifs_sb_info *cifs_sb; | ||
49 | struct cifsTconInfo *pTcon; | ||
50 | struct super_block * sb; | ||
51 | char * full_path; | ||
52 | |||
53 | if(direntry == NULL) | ||
54 | return -EIO; | ||
55 | if(direntry->d_inode == NULL) | ||
56 | return -EIO; | ||
57 | sb = direntry->d_inode->i_sb; | ||
58 | if(sb == NULL) | ||
59 | return -EIO; | ||
60 | xid = GetXid(); | ||
61 | |||
62 | cifs_sb = CIFS_SB(sb); | ||
63 | pTcon = cifs_sb->tcon; | ||
64 | |||
65 | down(&sb->s_vfs_rename_sem); | ||
66 | full_path = build_path_from_dentry(direntry); | ||
67 | up(&sb->s_vfs_rename_sem); | ||
68 | if(full_path == NULL) { | ||
69 | FreeXid(xid); | ||
70 | return -ENOMEM; | ||
71 | } | ||
72 | if(ea_name == NULL) { | ||
73 | cFYI(1,("Null xattr names not supported")); | ||
74 | } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) | ||
75 | && (strncmp(ea_name,CIFS_XATTR_OS2_PREFIX,4))) { | ||
76 | cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name)); | ||
77 | /* BB what if no namespace prefix? */ | ||
78 | /* Should we just pass them to server, except for | ||
79 | system and perhaps security prefixes? */ | ||
80 | } else { | ||
81 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
82 | goto remove_ea_exit; | ||
83 | |||
84 | ea_name+=5; /* skip past user. prefix */ | ||
85 | rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,NULL, | ||
86 | (__u16)0, cifs_sb->local_nls); | ||
87 | } | ||
88 | remove_ea_exit: | ||
89 | if (full_path) | ||
90 | kfree(full_path); | ||
91 | FreeXid(xid); | ||
92 | #endif | ||
93 | return rc; | ||
94 | } | ||
95 | |||
96 | int cifs_setxattr(struct dentry * direntry, const char * ea_name, | ||
97 | const void * ea_value, size_t value_size, int flags) | ||
98 | { | ||
99 | int rc = -EOPNOTSUPP; | ||
100 | #ifdef CONFIG_CIFS_XATTR | ||
101 | int xid; | ||
102 | struct cifs_sb_info *cifs_sb; | ||
103 | struct cifsTconInfo *pTcon; | ||
104 | struct super_block * sb; | ||
105 | char * full_path; | ||
106 | |||
107 | if(direntry == NULL) | ||
108 | return -EIO; | ||
109 | if(direntry->d_inode == NULL) | ||
110 | return -EIO; | ||
111 | sb = direntry->d_inode->i_sb; | ||
112 | if(sb == NULL) | ||
113 | return -EIO; | ||
114 | xid = GetXid(); | ||
115 | |||
116 | cifs_sb = CIFS_SB(sb); | ||
117 | pTcon = cifs_sb->tcon; | ||
118 | |||
119 | down(&sb->s_vfs_rename_sem); | ||
120 | full_path = build_path_from_dentry(direntry); | ||
121 | up(&sb->s_vfs_rename_sem); | ||
122 | if(full_path == NULL) { | ||
123 | FreeXid(xid); | ||
124 | return -ENOMEM; | ||
125 | } | ||
126 | /* return dos attributes as pseudo xattr */ | ||
127 | /* return alt name if available as pseudo attr */ | ||
128 | |||
129 | /* if proc/fs/cifs/streamstoxattr is set then | ||
130 | search server for EAs or streams to | ||
131 | returns as xattrs */ | ||
132 | if(value_size > MAX_EA_VALUE_SIZE) { | ||
133 | cFYI(1,("size of EA value too large")); | ||
134 | if(full_path) | ||
135 | kfree(full_path); | ||
136 | FreeXid(xid); | ||
137 | return -EOPNOTSUPP; | ||
138 | } | ||
139 | |||
140 | if(ea_name == NULL) { | ||
141 | cFYI(1,("Null xattr names not supported")); | ||
142 | } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) { | ||
143 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
144 | goto set_ea_exit; | ||
145 | if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) { | ||
146 | cFYI(1,("attempt to set cifs inode metadata")); | ||
147 | } | ||
148 | ea_name += 5; /* skip past user. prefix */ | ||
149 | rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, | ||
150 | (__u16)value_size, cifs_sb->local_nls); | ||
151 | } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { | ||
152 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
153 | goto set_ea_exit; | ||
154 | |||
155 | ea_name += 4; /* skip past os2. prefix */ | ||
156 | rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, | ||
157 | (__u16)value_size, cifs_sb->local_nls); | ||
158 | } else { | ||
159 | int temp; | ||
160 | temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS, | ||
161 | strlen(POSIX_ACL_XATTR_ACCESS)); | ||
162 | if (temp == 0) { | ||
163 | #ifdef CONFIG_CIFS_POSIX | ||
164 | rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value, | ||
165 | (const int)value_size, ACL_TYPE_ACCESS, | ||
166 | cifs_sb->local_nls); | ||
167 | cFYI(1,("set POSIX ACL rc %d",rc)); | ||
168 | #else | ||
169 | cFYI(1,("set POSIX ACL not supported")); | ||
170 | #endif | ||
171 | } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { | ||
172 | #ifdef CONFIG_CIFS_POSIX | ||
173 | rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value, | ||
174 | (const int)value_size, ACL_TYPE_DEFAULT, | ||
175 | cifs_sb->local_nls); | ||
176 | cFYI(1,("set POSIX default ACL rc %d",rc)); | ||
177 | #else | ||
178 | cFYI(1,("set default POSIX ACL not supported")); | ||
179 | #endif | ||
180 | } else { | ||
181 | cFYI(1,("illegal xattr request %s (only user namespace supported)",ea_name)); | ||
182 | /* BB what if no namespace prefix? */ | ||
183 | /* Should we just pass them to server, except for | ||
184 | system and perhaps security prefixes? */ | ||
185 | } | ||
186 | } | ||
187 | |||
188 | set_ea_exit: | ||
189 | if (full_path) | ||
190 | kfree(full_path); | ||
191 | FreeXid(xid); | ||
192 | #endif | ||
193 | return rc; | ||
194 | } | ||
195 | |||
196 | ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, | ||
197 | void * ea_value, size_t buf_size) | ||
198 | { | ||
199 | ssize_t rc = -EOPNOTSUPP; | ||
200 | #ifdef CONFIG_CIFS_XATTR | ||
201 | int xid; | ||
202 | struct cifs_sb_info *cifs_sb; | ||
203 | struct cifsTconInfo *pTcon; | ||
204 | struct super_block * sb; | ||
205 | char * full_path; | ||
206 | |||
207 | if(direntry == NULL) | ||
208 | return -EIO; | ||
209 | if(direntry->d_inode == NULL) | ||
210 | return -EIO; | ||
211 | sb = direntry->d_inode->i_sb; | ||
212 | if(sb == NULL) | ||
213 | return -EIO; | ||
214 | |||
215 | xid = GetXid(); | ||
216 | |||
217 | cifs_sb = CIFS_SB(sb); | ||
218 | pTcon = cifs_sb->tcon; | ||
219 | |||
220 | down(&sb->s_vfs_rename_sem); | ||
221 | full_path = build_path_from_dentry(direntry); | ||
222 | up(&sb->s_vfs_rename_sem); | ||
223 | if(full_path == NULL) { | ||
224 | FreeXid(xid); | ||
225 | return -ENOMEM; | ||
226 | } | ||
227 | /* return dos attributes as pseudo xattr */ | ||
228 | /* return alt name if available as pseudo attr */ | ||
229 | if(ea_name == NULL) { | ||
230 | cFYI(1,("Null xattr names not supported")); | ||
231 | } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) { | ||
232 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
233 | goto get_ea_exit; | ||
234 | |||
235 | if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) { | ||
236 | cFYI(1,("attempt to query cifs inode metadata")); | ||
237 | /* revalidate/getattr then populate from inode */ | ||
238 | } /* BB add else when above is implemented */ | ||
239 | ea_name += 5; /* skip past user. prefix */ | ||
240 | rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, | ||
241 | buf_size, cifs_sb->local_nls); | ||
242 | } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { | ||
243 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
244 | goto get_ea_exit; | ||
245 | |||
246 | ea_name += 4; /* skip past os2. prefix */ | ||
247 | rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, | ||
248 | buf_size, cifs_sb->local_nls); | ||
249 | } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { | ||
250 | #ifdef CONFIG_CIFS_POSIX | ||
251 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, | ||
252 | ea_value, buf_size, ACL_TYPE_ACCESS, | ||
253 | cifs_sb->local_nls); | ||
254 | #else | ||
255 | cFYI(1,("query POSIX ACL not supported yet")); | ||
256 | #endif /* CONFIG_CIFS_POSIX */ | ||
257 | } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { | ||
258 | #ifdef CONFIG_CIFS_POSIX | ||
259 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, | ||
260 | ea_value, buf_size, ACL_TYPE_DEFAULT, | ||
261 | cifs_sb->local_nls); | ||
262 | #else | ||
263 | cFYI(1,("query POSIX default ACL not supported yet")); | ||
264 | #endif | ||
265 | } else if(strncmp(ea_name, | ||
266 | CIFS_XATTR_TRUSTED_PREFIX,XATTR_TRUSTED_PREFIX_LEN) == 0) { | ||
267 | cFYI(1,("Trusted xattr namespace not supported yet")); | ||
268 | } else if(strncmp(ea_name, | ||
269 | CIFS_XATTR_SECURITY_PREFIX,XATTR_SECURITY_PREFIX_LEN) == 0) { | ||
270 | cFYI(1,("Security xattr namespace not supported yet")); | ||
271 | } else { | ||
272 | cFYI(1,("illegal xattr name request %s (only user namespace supported)",ea_name)); | ||
273 | } | ||
274 | |||
275 | /* We could add an additional check for streams ie | ||
276 | if proc/fs/cifs/streamstoxattr is set then | ||
277 | search server for EAs or streams to | ||
278 | returns as xattrs */ | ||
279 | |||
280 | if(rc == -EINVAL) | ||
281 | rc = -EOPNOTSUPP; | ||
282 | |||
283 | get_ea_exit: | ||
284 | if (full_path) | ||
285 | kfree(full_path); | ||
286 | FreeXid(xid); | ||
287 | #endif | ||
288 | return rc; | ||
289 | } | ||
290 | |||
291 | ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) | ||
292 | { | ||
293 | ssize_t rc = -EOPNOTSUPP; | ||
294 | #ifdef CONFIG_CIFS_XATTR | ||
295 | int xid; | ||
296 | struct cifs_sb_info *cifs_sb; | ||
297 | struct cifsTconInfo *pTcon; | ||
298 | struct super_block * sb; | ||
299 | char * full_path; | ||
300 | |||
301 | if(direntry == NULL) | ||
302 | return -EIO; | ||
303 | if(direntry->d_inode == NULL) | ||
304 | return -EIO; | ||
305 | sb = direntry->d_inode->i_sb; | ||
306 | if(sb == NULL) | ||
307 | return -EIO; | ||
308 | xid = GetXid(); | ||
309 | |||
310 | cifs_sb = CIFS_SB(sb); | ||
311 | pTcon = cifs_sb->tcon; | ||
312 | |||
313 | down(&sb->s_vfs_rename_sem); | ||
314 | full_path = build_path_from_dentry(direntry); | ||
315 | up(&sb->s_vfs_rename_sem); | ||
316 | if(full_path == NULL) { | ||
317 | FreeXid(xid); | ||
318 | return -ENOMEM; | ||
319 | } | ||
320 | /* return dos attributes as pseudo xattr */ | ||
321 | /* return alt name if available as pseudo attr */ | ||
322 | |||
323 | /* if proc/fs/cifs/streamstoxattr is set then | ||
324 | search server for EAs or streams to | ||
325 | returns as xattrs */ | ||
326 | rc = CIFSSMBQAllEAs(xid,pTcon,full_path,data,buf_size, | ||
327 | cifs_sb->local_nls); | ||
328 | |||
329 | if (full_path) | ||
330 | kfree(full_path); | ||
331 | FreeXid(xid); | ||
332 | #endif | ||
333 | return rc; | ||
334 | } | ||