diff -urN linux-2.4.27/Documentation/Configure.help linux-2.4.27-cifs-1.20c/Documentation/Configure.help --- linux-2.4.27/Documentation/Configure.help Fri Aug 13 16:50:31 2004 +++ linux-2.4.27-cifs-1.20c/Documentation/Configure.help Fri Aug 13 18:07:33 2004 @@ -17856,6 +17856,34 @@ If you don't know what all this is about, say N. +CIFS (Common Internet File System) support +CONFIG_CIFS + This is the client VFS module for the Common Internet File System + (CIFS) protocol which is the successor to the Server Message Block + (SMB) protocol, the native file sharing mechanism for most early + PC operating systems. CIFS is fully supported by current network + file servers such as Windows 2000, Windows 2003 (including + Windows XP) as well by Samba (which provides excellent CIFS + server support for Linux and many other operating systems). + The smbfs module should be used instead of this cifs module for + mounting to older SMB servers such as OS/2. The smbfs and cifs + modules can coexist and do not conflict. + + The intent of this module is to provide the most advanced network + file system function for CIFS compliant servers, including better + POSIX compliance, secure per-user session establishment, high + performance safe distributed caching (oplock), optional packet + signing, Unicode support and other internationalization improvements + For more information see the project page at + http://us1.samba.org/samba/Linux_CIFS_client.html + +CIFS Debugging +CONFIG_CIFS_DEBUG + If you are experiencing any problems with the CIFS filesystem, say + Y here. This will result in additional debugging messages to be + written to the system log. Under normal circumstances, this + results in very little overhead. + SMB file system support (to mount Windows shares etc.) CONFIG_SMB_FS SMB (Server Message Block) is the protocol Windows for Workgroups diff -urN linux-2.4.27/Documentation/filesystems/00-INDEX linux-2.4.27-cifs-1.20c/Documentation/filesystems/00-INDEX --- linux-2.4.27/Documentation/filesystems/00-INDEX Fri Jan 16 11:26:04 2004 +++ linux-2.4.27-cifs-1.20c/Documentation/filesystems/00-INDEX Fri Aug 13 18:07:33 2004 @@ -10,6 +10,8 @@ - info for the BeOS file system (BFS) bfs.txt - info for the SCO UnixWare Boot Filesystem (BFS). +cifs.txt + - info on the Common Internet File System (CIFS) coda.txt - description of the CODA filesystem. cramfs.txt diff -urN linux-2.4.27/Documentation/filesystems/cifs.txt linux-2.4.27-cifs-1.20c/Documentation/filesystems/cifs.txt --- linux-2.4.27/Documentation/filesystems/cifs.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/Documentation/filesystems/cifs.txt Fri Aug 13 18:07:33 2004 @@ -0,0 +1,51 @@ + This is the client VFS module for the Common Internet File System + (CIFS) protocol which is the successor to the Server Message Block + (SMB) protocol, the native file sharing mechanism for most early + PC operating systems. CIFS is fully supported by current network + file servers such as Windows 2000, Windows 2003 (including + Windows XP) as well by Samba (which provides excellent CIFS + server support for Linux and many other operating systems), so + this network filesystem client can mount to a wide variety of + servers. The smbfs module should be used instead of this cifs module + for mounting to older SMB servers such as OS/2. The smbfs and cifs + modules can coexist and do not conflict. The CIFS VFS filesystem + module is designed to work well with servers that implement the + newer versions (dialects) of the SMB/CIFS protocol such as Samba, + the program written by Andrew Tridgell that turns any Unix host + into a SMB/CIFS file server. + + The intent of this module is to provide the most advanced network + file system function for CIFS compliant servers, including better + POSIX compliance, secure per-user session establishment, high + performance safe distributed caching (oplock), optional packet + signing, large files, Unicode support and other internationalization + improvements. Since both Samba server and this filesystem client support + the CIFS Unix extensions, the combination can provide a reasonable + alternative to NFSv4 for fileserving in some Linux to Linux environments, + not just in Linux to Windows environments. + + This filesystem has an optional mount utility (mount.cifs) that can + be obtained from the project page and installed in the path in the same + directory with the other mount helpers (such as mount.smbfs). + Mounting using the cifs filesystem without installing the mount helper + requires specifying the server's ip address. + + For Linux 2.4: + mount //anything/here /mnt_target -o + user=username,pass=password,unc=//ip_address_of_server/sharename + + For Linux 2.5: + mount //ip_address_of_server/sharename /mnt_target -o user=username, pass=password + + + For more information on the module see the project page at + + http://us1.samba.org/samba/Linux_CIFS_client.html + + For more information on CIFS see: + + http://www.snia.org/tech_activities/CIFS + + or the Samba site: + + http://www.samba.org diff -urN linux-2.4.27/fs/Config.in linux-2.4.27-cifs-1.20c/fs/Config.in --- linux-2.4.27/fs/Config.in Thu Feb 5 17:30:51 2004 +++ linux-2.4.27-cifs-1.20c/fs/Config.in Fri Aug 13 18:07:33 2004 @@ -139,6 +139,10 @@ define_bool CONFIG_LOCKD_V4 y fi + dep_tristate 'CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)' CONFIG_CIFS $CONFIG_INET + dep_mbool ' CIFS statistics' CONFIG_CIFS_STATS $CONFIG_CIFS + dep_mbool ' CIFS POSIX Protocol Extensions' CONFIG_CIFS_POSIX $CONFIG_CIFS + dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET if [ "$CONFIG_SMB_FS" != "n" ]; then bool ' Use a default NLS' CONFIG_SMB_NLS_DEFAULT diff -urN linux-2.4.27/fs/Makefile linux-2.4.27-cifs-1.20c/fs/Makefile --- linux-2.4.27/fs/Makefile Fri Feb 13 15:57:07 2004 +++ linux-2.4.27-cifs-1.20c/fs/Makefile Fri Aug 13 18:07:33 2004 @@ -37,6 +37,7 @@ subdir-$(CONFIG_VFAT_FS) += vfat subdir-$(CONFIG_BFS_FS) += bfs subdir-$(CONFIG_ISO9660_FS) += isofs +subdir-$(CONFIG_CIFS) += cifs subdir-$(CONFIG_DEVFS_FS) += devfs subdir-$(CONFIG_HFSPLUS_FS) += hfsplus # Before hfs to find wrapped HFS+ subdir-$(CONFIG_HFS_FS) += hfs diff -urN linux-2.4.27/fs/cifs/AUTHORS linux-2.4.27-cifs-1.20c/fs/cifs/AUTHORS --- linux-2.4.27/fs/cifs/AUTHORS Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/AUTHORS Wed Jul 14 00:25:04 2004 @@ -0,0 +1,37 @@ +Original Author +=============== +Steve French (sfrench@samba.org) + +The author wishes to express his appreciation and thanks to: +Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS +improvements. Thanks to IBM for allowing me the time and test resources to pursue +this project. Jim McDonough from IBM (and the Samba Team) for his help. +The IBM Linux JFS team for explaining many esoteric Linux filesystem features. +Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client) +for proving years ago that a very good smb/cifs client could be done on a Unix like +operating system. Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin +and others for their work on the Linux smbfs module over the years. Thanks to +the other members of the Storage Network Industry Association CIFS Technical +Workgroup for their work specifying this highly complex protocol and finally +thanks to the Samba team for their technical advice and encouragement. + +Patch Contributors +------------------ +Zwane Mwaikambo +Andi Kleen +Amrut Joshi +Shobhit Dayal +Sergey Vlasov +Richard Hughes +Yury Umanets + +Test case and Bug Report contributors +------------------------------------- +Thanks to those in the community who have submitted detailed bug reports +and debug of problems they have found: Jochen Dolze, David Blaine, +Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori, +Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen, +Olaf Kirch, Kieron Briggs, Nick Millington and others. + +And thanks to the IBM LTC and Power test teams and SuSE testers for +finding multiple bugs during excellent stress test runs. diff -urN linux-2.4.27/fs/cifs/CHANGES linux-2.4.27-cifs-1.20c/fs/cifs/CHANGES --- linux-2.4.27/fs/cifs/CHANGES Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/CHANGES Wed Jul 14 00:25:04 2004 @@ -0,0 +1,572 @@ +Version 1.20 +------------ +Make transaction counts more consistent. Merge /proc/fs/cifs/SimultaneousOps +info into /proc/fs/cifs/DebugData. Fix oops in rare oops in readdir +(in build_wildcard_path_from_dentry). Fix mknod to pass type field +(block/char/fifo) properly. Remove spurious mount warning log entry when +credentials passed as mount argument. Set major/minor device number in +inode for block and char devices when unix extensions enabled. + +Version 1.19 +------------ +Fix /proc/fs/cifs/Stats and DebugData display to handle larger +amounts of return data. Properly limit requests to MAX_REQ (50 +is the usual maximum active multiplex SMB/CIFS requests per server). +Do not kill cifsd (and thus hurt the other SMB session) when more than one +session to the same server (but with different userids) exists and one +of the two user's smb sessions is being removed while leaving the other. +Do not loop reconnecting in cifsd demultiplex thread when admin +kills the thread without going through unmount. + +Version 1.18 +------------ +Do not rename hardlinked files (since that should be a noop). Flush +cached write behind data when reopening a file after session abend, +except when already in write. Grab per socket sem during reconnect +to avoid oops in sendmsg if overlapping with reconnect. Do not +reset cached inode file size on readdir for files open for write on +client. + + +Version 1.17 +------------ +Update number of blocks in file so du command is happier (in Linux a fake +blocksize of 512 is required for calculating number of blocks in inode). +Fix prepare write of partial pages to read in data from server if possible. +Fix race on tcpStatus field between unmount and reconnection code, causing +cifsd process sometimes to hang around forever. Improve out of memory +checks in cifs_filldir + +Version 1.16 +------------ +Fix incorrect file size in file handle based setattr on big endian hardware. +Fix oops in build_path_from_dentry when out of memory. Add checks for invalid +and closing file structs in writepage/partialpagewrite. Add statistics +for each mounted share (new menuconfig option). Fix endianness problem in +volume information displayed in /proc/fs/cifs/DebugData (only affects +affects big endian architectures). Prevent renames while constructing +path names for open, mkdir and rmdir. + +Version 1.15 +------------ +Change to mempools for alloc smb request buffers and multiplex structs +to better handle low memory problems (and potential deadlocks). + +Version 1.14 +------------ +Fix incomplete listings of large directories on Samba servers when Unix +extensions enabled. Fix oops when smb_buffer can not be allocated. Fix +rename deadlock when writing out dirty pages at same time. + +Version 1.13 +------------ +Fix open of files in which O_CREATE can cause the mode to change in +some cases. Fix case in which retry of write overlaps file close. +Fix PPC64 build error. Reduce excessive stack usage in smb password +hashing. Fix overwrite of Linux user's view of file mode to Windows servers. + +Version 1.12 +------------ +Fixes for large file copy, signal handling, socket retry, buffer +allocation and low memory situations. + +Version 1.11 +------------ +Better port 139 support to Windows servers (RFC1001/RFC1002 Session_Initialize) +also now allowing support for specifying client netbiosname. NT4 support added. + +Version 1.10 +------------ +Fix reconnection (and certain failed mounts) to properly wake up the +blocked users thread so it does not seem hung (in some cases was blocked +until the cifs receive timeout expired). Fix spurious error logging +to kernel log when application with open network files killed. + +Version 1.09 +------------ +Fix /proc/fs module unload warning message (that could be logged +to the kernel log). Fix intermittent failure in connectathon +test7 (hardlink count not immediately refreshed in case in which +inode metadata can be incorrectly kept cached when time near zero) + +Version 1.08 +------------ +Allow file_mode and dir_mode (specified at mount time) to be enforced +locally (the server already enforced its own ACLs too) for servers +that do not report the correct mode (do not support the +CIFS Unix Extensions). + +Version 1.07 +------------ +Fix some small memory leaks in some unmount error paths. Fix major leak +of cache pages in readpages causing multiple read oriented stress +testcases (including fsx, and even large file copy) to fail over time. + +Version 1.06 +------------ +Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated with server. +This allows files that differ only in case and improves performance of file +creation and file open to such servers. Fix semaphore conflict which causes +slow delete of open file to Samba (which unfortunately can cause an oplock +break to self while vfs_unlink held i_sem) which can hang for 20 seconds. + +Version 1.05 +------------ +fixes to cifs_readpages for fsx test case + +Version 1.04 +------------ +Fix caching data integrity bug when extending file size especially when no +oplock on file. Fix spurious logging of valid already parsed mount options +that are parsed outside of the cifs vfs such as nosuid. + + +Version 1.03 +------------ +Connect to server when port number override not specified, and tcp port +unitialized. Reset search to restart at correct file when kernel routine +filldir returns error during large directory searches (readdir). + +Version 1.02 +------------ +Fix caching problem when files opened by multiple clients in which +page cache could contain stale data, and write through did +not occur often enough while file was still open when read ahead +(read oplock) not allowed. Treat "sep=" when first mount option +as an overrride of comma as the default separator between mount +options. + +Version 1.01 +------------ +Allow passwords longer than 16 bytes. Allow null password string. + +Version 1.00 +------------ +Gracefully clean up failed mounts when attempting to mount to servers such as +Windows 98 that terminate tcp sessions during prototocol negotiation. Handle +embedded commas in mount parsing of passwords. + +Version 0.99 +------------ +Invalidate local inode cached pages on oplock break and when last file +instance is closed so that the client does not continue using stale local +copy rather than later modified server copy of file. Do not reconnect +when server drops the tcp session prematurely before negotiate +protocol response. Fix oops in roepen_file when dentry freed. Allow +the support for CIFS Unix Extensions to be disabled via proc interface. + +Version 0.98 +------------ +Fix hang in commit_write during reconnection of open files under heavy load. +Fix unload_nls oops in a mount failure path. Serialize writes to same socket +which also fixes any possible races when cifs signatures are enabled in SMBs +being sent out of signature sequence number order. + +Version 0.97 +------------ +Fix byte range locking bug (endian problem) causing bad offset and +length. + +Version 0.96 +------------ +Fix oops (in send_sig) caused by CIFS unmount code trying to +wake up the demultiplex thread after it had exited. Do not log +error on harmless oplock release of closed handle. + +Version 0.95 +------------ +Fix unsafe global variable usage and password hash failure on gcc 3.3.1 +Fix problem reconnecting secondary mounts to same server after session +failure. Fix invalid dentry - race in mkdir when directory gets created +by another client between the lookup and mkdir. + +Version 0.94 +------------ +Fix to list processing in reopen_files. Fix reconnection when server hung +but tcpip session still alive. Set proper timeout on socket read. + +Version 0.93 +------------ +Add missing mount options including iocharset. SMP fixes in write and open. +Fix errors in reconnecting after TCP session failure. Fix module unloading +of default nls codepage + +Version 0.92 +------------ +Active smb transactions should never go negative (fix double FreeXid). Fix +list processing in file routines. Check return code on kmalloc in open. +Fix spinlock usage for SMP. + +Version 0.91 +------------ +Fix oops in reopen_files when invalid dentry. drop dentry on server rename +and on revalidate errors. Fix cases where pid is now tgid. Fix return code +on create hard link when server does not support them. + +Version 0.90 +------------ +Fix scheduling while atomic error in getting inode info on newly created file. +Fix truncate of existing files opened with O_CREAT but not O_TRUNC set. + +Version 0.89 +------------ +Fix oops on write to dead tcp session. Remove error log write for case when file open +O_CREAT but not O_EXCL + +Version 0.88 +------------ +Fix non-POSIX behavior on rename of open file and delete of open file by taking +advantage of trans2 SetFileInfo rename facility if available on target server. +Retry on ENOSPC and EAGAIN socket errors. + +Version 0.87 +------------ +Fix oops on big endian readdir. Set blksize to be even power of two (2**blkbits) to fix +allocation size miscalculation. After oplock token lost do not read through +cache. + +Version 0.86 +------------ +Fix oops on empty file readahead. Fix for file size handling for locally cached files. + +Version 0.85 +------------ +Fix oops in mkdir when server fails to return inode info. Fix oops in reopen_files +during auto reconnection to server after server recovered from failure. + +Version 0.84 +------------ +Finish support for Linux 2.5 open/create changes, which removes the +redundant NTCreate/QPathInfo/close that was sent during file create. +Enable oplock by default. Enable packet signing by default (needed to +access many recent Windows servers) + +Version 0.83 +------------ +Fix oops when mounting to long server names caused by inverted parms to kmalloc. +Fix MultiuserMount (/proc/fs/cifs configuration setting) so that when enabled +we will choose a cifs user session (smb uid) that better matches the local +uid if a) the mount uid does not match the current uid and b) we have another +session to the same server (ip address) for a different mount which +matches the current local uid. + +Version 0.82 +------------ +Add support for mknod of block or character devices. Fix oplock +code (distributed caching) to properly send response to oplock +break from server. + +Version 0.81 +------------ +Finish up CIFS packet digital signing for the default +NTLM security case. This should help Windows 2003 +network interoperability since it is common for +packet signing to be required now. Fix statfs (stat -f) +which recently started returning errors due to +invalid value (-1 instead of 0) being set in the +struct kstatfs f_ffiles field. + +Version 0.80 +----------- +Fix oops on stopping oplock thread when removing cifs when +built as module. + +Version 0.79 +------------ +Fix mount options for ro (readonly), uid, gid and file and directory mode. + +Version 0.78 +------------ +Fix errors displayed on failed mounts to be more understandable. +Fixed various incorrect or misleading smb to posix error code mappings. + +Version 0.77 +------------ +Fix display of NTFS DFS junctions to display as symlinks. +They are the network equivalent. Fix oops in +cifs_partialpagewrite caused by missing spinlock protection +of openfile linked list. Allow writebehind caching errors to +be returned to the application at file close. + +Version 0.76 +------------ +Clean up options displayed in /proc/mounts by show_options to +be more consistent with other filesystems. + +Version 0.75 +------------ +Fix delete of readonly file to Windows servers. Reflect +presence or absence of read only dos attribute in mode +bits for servers that do not support CIFS Unix extensions. +Fix shortened results on readdir of large directories to +servers supporting CIFS Unix extensions (caused by +incorrect resume key). + +Version 0.74 +------------ +Fix truncate bug (set file size) that could cause hangs e.g. running fsx + +Version 0.73 +------------ +unload nls if mount fails. + +Version 0.72 +------------ +Add resume key support to search (readdir) code to workaround +Windows bug. Add /proc/fs/cifs/LookupCacheEnable which +allows disabling caching of attribute information for +lookups. + +Version 0.71 +------------ +Add more oplock handling (distributed caching code). Remove +dead code. Remove excessive stack space utilization from +symlink routines. + +Version 0.70 +------------ +Fix oops in get dfs referral (triggered when null path sent in to +mount). Add support for overriding rsize at mount time. + +Version 0.69 +------------ +Fix buffer overrun in readdir which caused intermittent kernel oopses. +Fix writepage code to release kmap on write data. Allow "-ip=" new +mount option to be passed in on parameter distinct from the first part +(server name portion of) the UNC name. Allow override of the +tcp port of the target server via new mount option "-port=" + +Version 0.68 +------------ +Fix search handle leak on rewind. Fix setuid and gid so that they are +reflected in the local inode immediately. Cleanup of whitespace +to make 2.4 and 2.5 versions more consistent. + + +Version 0.67 +------------ +Fix signal sending so that captive thread (cifsd) exits on umount +(which was causing the warning in kmem_cache_free of the request buffers +at rmmod time). This had broken as a sideeffect of the recent global +kernel change to daemonize. Fix memory leak in readdir code which +showed up in "ls -R" (and applications that did search rewinding). + +Version 0.66 +------------ +Reconnect tids and fids after session reconnection (still do not +reconnect byte range locks though). Fix problem caching +lookup information for directory inodes, improving performance, +especially in deep directory trees. Fix various build warnings. + +Version 0.65 +------------ +Finish fixes to commit write for caching/readahead consistency. fsx +now works to Samba servers. Fix oops caused when readahead +was interrupted by a signal. + +Version 0.64 +------------ +Fix data corruption (in partial page after truncate) that caused fsx to +fail to Windows servers. Cleaned up some extraneous error logging in +common error paths. Add generic sendfile support. + +Version 0.63 +------------ +Fix memory leak in AllocMidQEntry. +Finish reconnection logic, so connection with server can be dropped +(or server rebooted) and the cifs client will reconnect. + +Version 0.62 +------------ +Fix temporary socket leak when bad userid or password specified +(or other SMBSessSetup failure). Increase maximum buffer size to slightly +over 16K to allow negotiation of up to Samba and Windows server default read +sizes. Add support for readpages + +Version 0.61 +------------ +Fix oops when username not passed in on mount. Extensive fixes and improvements +to error logging (strip redundant newlines, change debug macros to ensure newline +passed in and to be more consistent). Fix writepage wrong file handle problem, +a readonly file handle could be incorrectly used to attempt to write out +file updates through the page cache to multiply open files. This could cause +the iozone benchmark to fail on the fwrite test. Fix bug mounting two different +shares to the same Windows server when using different usernames +(doing this to Samba servers worked but Windows was rejecting it) - now it is +possible to use different userids when connecting to the same server from a +Linux client. Fix oops when treeDisconnect called during unmount on +previously freed socket. + +Version 0.60 +------------ +Fix oops in readpages caused by not setting address space operations in inode in +rare code path. + +Version 0.59 +------------ +Includes support for deleting of open files and renaming over existing files (per POSIX +requirement). Add readlink support for Windows junction points (directory symlinks). + +Version 0.58 +------------ +Changed read and write to go through pagecache. Added additional address space operations. +Memory mapped operations now working. + +Version 0.57 +------------ +Added writepage code for additional memory mapping support. Fixed leak in xids causing +the simultaneous operations counter (/proc/fs/cifs/SimultaneousOps) to increase on +every stat call. Additional formatting cleanup. + +Version 0.56 +------------ +Fix bigendian bug in order of time conversion. Merge 2.5 to 2.4 version. Formatting cleanup. + +Version 0.55 +------------ +Fixes from Zwane Mwaikambo for adding missing return code checking in a few places. +Also included a modified version of his fix to protect global list manipulation of +the smb session and tree connection and mid related global variables. + +Version 0.54 +------------ +Fix problem with captive thread hanging around at unmount time. Adjust to 2.5.42-pre +changes to superblock layout. Remove wasteful allocation of smb buffers (now the send +buffer is reused for responses). Add more oplock handling. Additional minor cleanup. + +Version 0.53 +------------ +More stylistic updates to better match kernel style. Add additional statistics +for filesystem which can be viewed via /proc/fs/cifs. Add more pieces of NTLMv2 +and CIFS Packet Signing enablement. + +Version 0.52 +------------ +Replace call to sleep_on with safer wait_on_event. +Make stylistic changes to better match kernel style recommendations. +Remove most typedef usage (except for the PDUs themselves). + +Version 0.51 +------------ +Update mount so the -unc mount option is no longer required (the ip address can be specified +in a UNC style device name. Implementation of readpage/writepage started. + +Version 0.50 +------------ +Fix intermittent problem with incorrect smb header checking on badly +fragmented tcp responses + +Version 0.49 +------------ +Fixes to setting of allocation size and file size. + +Version 0.48 +------------ +Various 2.5.38 fixes. Now works on 2.5.38 + +Version 0.47 +------------ +Prepare for 2.5 kernel merge. Remove ifdefs. + +Version 0.46 +------------ +Socket buffer management fixes. Fix dual free. + +Version 0.45 +------------ +Various big endian fixes for hardlinks and symlinks and also for dfs. + +Version 0.44 +------------ +Various big endian fixes for servers with Unix extensions such as Samba + +Version 0.43 +------------ +Various FindNext fixes for incorrect filenames on large directory searches on big endian +clients. basic posix file i/o tests now work on big endian machines, not just le + +Version 0.42 +------------ +SessionSetup and NegotiateProtocol now work from Big Endian machines. +Various Big Endian fixes found during testing on the Linux on 390. Various fixes for compatibility with older +versions of 2.4 kernel (now builds and works again on kernels at least as early as 2.4.7). + +Version 0.41 +------------ +Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked +files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked. + +Version 0.40 +------------ +Implemented "Raw" (i.e. not encapsulated in SPNEGO) NTLMSSP (i.e. the Security Provider Interface used to negotiate +session advanced session authentication). Raw NTLMSSP is preferred by Windows 2000 Professional and Windows XP. +Began implementing support for SPNEGO encapsulation of NTLMSSP based session authentication blobs +(which is the mechanism preferred by Windows 2000 server in the absence of Kerberos). + +Version 0.38 +------------ +Introduced optional mount helper utility mount.cifs and made coreq changes to cifs vfs to enable +it. Fixed a few bugs in the DFS code (e.g. bcc two bytes too short and incorrect uid in PDU). + +Version 0.37 +------------ +Rewrote much of connection and mount/unmount logic to handle bugs with +multiple uses to same share, multiple users to same server etc. + +Version 0.36 +------------ +Fixed major problem with dentry corruption (missing call to dput) + +Version 0.35 +------------ +Rewrite of readdir code to fix bug. Various fixes for bigendian machines. +Begin adding oplock support. Multiusermount and oplockEnabled flags added to /proc/fs/cifs +although corresponding function not fully implemented in the vfs yet + +Version 0.34 +------------ +Fixed dentry caching bug, misc. cleanup + +Version 0.33 +------------ +Fixed 2.5 support to handle build and configure changes as well as misc. 2.5 changes. Now can build +on current 2.5 beta version (2.5.24) of the Linux kernel as well as on 2.4 Linux kernels. +Support for STATUS codes (newer 32 bit NT error codes) added. DFS support begun to be added. + +Version 0.32 +------------ +Unix extensions (symlink, readlink, hardlink, chmod and some chgrp and chown) implemented +and tested against Samba 2.2.5 + + +Version 0.31 +------------ +1) Fixed lockrange to be correct (it was one byte too short) + +2) Fixed GETLK (i.e. the fcntl call to test a range of bytes in a file to see if locked) to correctly +show range as locked when there is a conflict with an existing lock. + +3) default file perms are now 2767 (indicating support for mandatory locks) instead of 777 for directories +in most cases. Eventually will offer optional ability to query server for the correct perms. + +3) Fixed eventual trap when mounting twice to different shares on the same server when the first succeeded +but the second one was invalid and failed (the second one was incorrectly disconnecting the tcp and smb +session) + +4) Fixed error logging of valid mount options + +5) Removed logging of password field. + +6) Moved negotiate, treeDisconnect and uloggoffX (only tConx and SessSetup remain in connect.c) to cifssmb.c +and cleaned them up and made them more consistent with other cifs functions. + +7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways +(with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed, +nor is the symlink support using the Unix extensions + +8) Started adding the readlink and follow_link code + +Version 0.3 +----------- +Initial drop + diff -urN linux-2.4.27/fs/cifs/Makefile linux-2.4.27-cifs-1.20c/fs/cifs/Makefile --- linux-2.4.27/fs/cifs/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/Makefile Wed Jul 14 00:25:04 2004 @@ -0,0 +1,10 @@ +# +# Makefile for Linux CIFS VFS client +# +O_TARGET := cifs.o + +obj-y := 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 cifsencrypt.o + +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.27/fs/cifs/README linux-2.4.27-cifs-1.20c/fs/cifs/README --- linux-2.4.27/fs/cifs/README Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/README Wed Jul 14 00:25:04 2004 @@ -0,0 +1,356 @@ +The CIFS VFS support for Linux supports many advanced network filesystem +features such as heirarchical dfs like namespace, hardlinks, locking and more. +It was designed to comply with the SNIA CIFS Technical Reference (which +supersedes the 1992 X/Open SMB Standard) as well as to perform best practice +practical interoperability with Windows 2000, Windows XP, Samba and equivalent +servers. + +For questions or bug reports please contact: + sfrench@samba.org (sfrench@us.ibm.com) + +Build instructions: +================== +For Linux 2.4: +1) Get the kernel source (e.g.from http://www.kernel.org) +and download the cifs vfs source (see the project page +at http://us1.samba.org/samba/Linux_CIFS_client.html) +and change directory into the top of the kernel directory +then patch the kernel (e.g. "patch -p1 < cifs_24.patch") +to add the cifs vfs to your kernel configure options if +it has not already been added (e.g. current SuSE and UL +users do not need to apply the cifs_24.patch since the cifs vfs is +already in the kernel configure menu) and then +mkdir linux/fs/cifs and then copy the current cifs vfs files from +the cifs download to your kernel build directory e.g. + + cp /fs/cifs/* to /fs/cifs + +2) make menuconfig (or make xconfig) +3) select cifs from within the network filesystem choices +4) save and exit +5) make dep +6) make modules (or "make" if CIFS VFS not to be built as a module) + +For Linux 2.5: +1) Download the kernel (e.g. from http://www.kernel.org or from bitkeeper +at bk://linux.bkbits.net/linux-2.5) and change directory into the top +of the kernel directory tree (e.g. /usr/src/linux-2.5.73) +2) make menuconfig (or make xconfig) +3) select cifs from within the network filesystem choices +4) save and exit +5) make + + +Installation instructions: +========================= +If you have built the CIFS vfs as module (successfully) simply +type "make modules_install" (or if you prefer, manually copy the file to +the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o). + +If you have built the CIFS vfs into the kernel itself, follow the instructions +for your distribution on how to install a new kernel (usually you +would simply type "make install"). + +If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on +the CIFS VFS web site) copy it to the same directory in which mount.smbfs and +similar files reside (usually /sbin). Although the helper software is not +required, mount.cifs is recommended. Eventually the Samba 3.0 utility program +"net" may also be helpful since it may someday provide easier mount syntax for +users who are used to Windows e.g. net use +Note that running the Winbind pam/nss module (logon service) on all of your +Linux clients is useful in mapping Uids and Gids consistently across the +domain to the proper network user. The mount.cifs mount helper can be +trivially built from Samba 3.0 or later source e.g. by executing: + + gcc samba/source/client/mount.cifs.c -o mount.cifs + +Note that when the mount.cifs utility is run suid (allowing user mounts), +in order to reduce risks, the "nosuid" mount flag is passed in on mount to +disallow execution of an suid program mounted on the remote target. +When mount is executed as root, nosuid is not passed in by default, +and execution of suid programs on the remote target would be enabled +by default. This can be changed, as with nfs and other filesystems, +by simply specifying "nosuid" among the mount options. For user mounts +though to be able to pass the suid flag to mount requires rebuilding +mount.cifs with the following flag: + + gcc samba/source/client/mount.cifs.c -DCIFS_ALLOW_USR_SUID -o mount.cifs + +There is a corresponding manual page for cifs mounting in the Samba 3.0 and +later source tree in docs/manpages/mount.cifs.8 + +Samba Considerations +==================== +To get the maximum benefit from the CIFS VFS, we recommend using a server that +supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or +Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. +Note that uid, gid and file permissions will display default values if you do +not have a server that supports the Unix extensions for CIFS (such as Samba +2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add +the line: + + unix extensions = yes + +to your smb.conf file on the server. Note that the following smb.conf settings +are also useful (on the Samba server) when the majority of clients are Unix or +Linux: + + case sensitive = yes + delete readonly = yes + ea support = yes + +Note that ea support is required for supporting Linux xattrs. +Some administrators also change the "map archive" and the "create mask" +parameters from their default values. Creating special devices (mknod) +remotely may require specifying a mkdev function to Samba if you are not using +Samba 3.0.5 or later. For more information on these see the manual pages +("man smb.conf") on the Samba server system. Note that the cifs vfs, +unlike the smbfs vfs, does not read the smb.conf on the client system +(the few optional settings are passed in on mount via -o parameters instead). +Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete +open files (required for strict POSIX compliance). Windows Servers already +supported this feature. Samba server does not allow symlinks that refer to files +outside of the share, so in Samba versions prior to 3.0.5, most symlinks to +files with absolute paths (ie beginning with slash) such as: + ln -s /mnt/foo bar +would be forbidden. Samba 3.0.5 server or later includes the ability to create +such symlinks safely by converting unsafe symlinks (ie symlinks to server +files that are outside of the share) to a samba specific format on the server +that is ignored by local server applications and non-cifs clients and that will +not be traversed by the Samba server). This is opaque to the Linux client +application using the cifs vfs. Absolute symlinks will work to Samba 3.0.5 or +later, but only for remote clients using the CIFS Unix extensions, and will +be invisbile to Windows clients and typically will not affect local +applications running on the same server as Samba. + +Use instructions: +================ +Once the CIFS VFS support is built into the kernel or installed as a module +(cifs.o), you can use mount syntax like the following to access Samba or Windows +servers: + + mount -t cifs //9.53.216.11/e$ /mnt -o user=myname,pass=mypassword + +Before -o the option -v may be specified to make the mount.cifs +mount helper display the mount steps more verbosely. +After -o the following commonly used cifs vfs specific options +are supported: + + user= + pass= + domain= + +Other cifs mount options are described below. Use of TCP names (in addition to +ip addresses) is available if the mount helper (mount.cifs) is installed. If +you do not trust the server to which are mounted, or if you do not have +cifs signing enabled (and the physical network is insecure), consider use +of the standard mount options "noexec" and "nosuid" to reduce the risk of +running an altered binary on your local system (downloaded from a hostile server +or altered by a hostile router). + +When using the mount helper mount.cifs, passwords may be specified via alternate +mechanisms, instead of specifying it after -o using the normal "pass=" syntax +on the command line: +1) By including it in a credential file. Specify credentials=filename as one +of the mount options. Credential files contain two lines + username=someuser + password=your_password +2) By specifying the password in the PASSWD environment variable (similarly +the user name can be taken from the USER environment variable). +3) By specifying the password in a file by name via PASSWD_FILE +4) By specifying the password in a file by file descriptor via PASSWD_FD + +If no password is provided, mount.cifs will prompt for password entry + +Restrictions +============ +Servers must support the NTLM SMB dialect (which is the most recent, supported +by Samba and Windows NT version 4, 2000 and XP and many other SMB/CIFS servers) +Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC +1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a +problem as most servers support this. IPv6 support is planned for the future. + +CIFS VFS Mount Options +====================== +A partial list of the supported mount options follows: + user The user name to use when trying to establish + the CIFS session. + password The user password. If the mount helper is + installed, the user will be prompted for password + if it is not supplied. + ip The ip address of the target server + unc The target server Universal Network Name (export) to + mount. + domain Set the SMB/CIFS workgroup name prepended to the + username during CIFS session establishment + uid If CIFS Unix extensions are not supported by the server + this overrides the default uid for inodes. For mounts to + servers which do support the CIFS Unix extensions, such + as a properly configured Samba server, the server provides + the uid, gid and mode. For servers which do not support + the Unix extensions, the default uid (and gid) returned on + lookup of existing files is the uid (gid) of the person + who executed the mount (root, except when mount.cifs + is configured setuid for user mounts) unless the "uid=" + (gid) mount option is specified. For the uid (gid) of newly + created files and directories, ie files created since + the last mount of the server share, the expected uid + (gid) is cached as as long as the inode remains in + memory on the client. Also note that permission + checks (authorization checks) on accesses to a file occur + at the server, but there are cases in which an administrator + may want to restrict at the client as well. For those + servers which do not report a uid/gid owner + (such as Windows), permissions can also be checked at the + client, and a crude form of client side permission checking + can be enabled by specifying file_mode and dir_mode on + the client + gid If CIFS Unix extensions are not supported by the server + this overrides the default gid for inodes. + file_mode If CIFS Unix extensions are not supported by the server + this overrides the default mode for file inodes. + dir_mode If CIFS Unix extensions are not supported by the server + this overrides the default mode for directory inodes. + port attempt to contact the server on this tcp port, before + trying the usual ports (port 445, then 139). + iocharset Codepage used to convert local path names to and from + Unicode. Unicode is used by default for network path + names if the server supports it. If iocharset is + not specified then the nls_default specified + during the local client kernel build will be used. + If server does not support Unicode, this parameter is + unused. + rsize default read size + wsize default write size + rw mount the network share read-write (note that the + server may still consider the share read-only) + ro mount network share read-only + version used to distinguish different versions of the + mount helper utility (not typically needed) + sep if first mount option (after the -o), overrides + the comma as the separator between the mount + parms. e.g. + -o user=myname,password=mypassword,domain=mydom + could be passed instead with period as the separator by + -o sep=.user=myname.password=mypassword.domain=mydom + this might be useful when comma is contained within username + or password or domain. This option is less important + when the cifs mount helper cifs.mount (version 1.1 or later) + is used. + nosuid Do not allow remote executables with the suid bit + program to be executed. This is only meaningful for mounts + to servers such as Samba which support the CIFS Unix Extensions. + If you do not trust the servers in your network (your mount + targets) it is recommended that you specify this option for + greater security. + suid Allow remote files on this mountpoint with suid enabled to + be executed (default for mounts when executed as root, + nosuid is default for user mounts). + credentials Although ignored by the cifs kernel component, it is used by + the mount helper, mount.cifs. When mount.cifs is installed it + opens and reads the credential file specified in order + to obtain the userid and password arguments which are passed to + the cifs vfs. + guest Although ignored by the kernel component, the mount.cifs + mount helper will not prompt the user for a password + if guest is specified on the mount options. If no + password is specified a null password will be used. + +The mount.cifs mount helper also accepts a few mount options before -o +including: + + -S take password from stdin (equivalent to setting the environment + variable "PASSWD_FD=0" + -V print mount.cifs version + -? display simple usage information + +With recent 2.6 kernel versions of modutils, the version of the cifs kernel +module can be displayed via modinfo. + +Misc /proc/fs/cifs Flags and Debug Info +======================================= +Informational pseudo-files: +DebugData Displays information about active CIFS sessions + and shares. +Stats Lists summary resource usage information as well as per + share statistics, if CONFIG_CIFS_STATS in enabled + in the kernel configuration. + +Configuration pseudo-files: +MultiuserMount If set to one, more than one CIFS session to + the same server ip address can be established + if more than one uid accesses the same mount + point and if the uids user/password mapping + information is available. (default is 0) +PacketSigningEnabled If set to one, cifs packet signing is enabled + and will be used if the server requires + it. If set to two, cifs packet signing is + required even if the server considers packet + signing optional. (default 1) +cifsFYI If set to one, additional debug information is + logged to the system error log. (default 0) +ExtendedSecurity If set to one, SPNEGO session establishment + is allowed which enables more advanced + secure CIFS session establishment (default 0) +NTLMV2Enabled If set to one, more secure password hashes + are used when the server supports them and + when kerberos is not negotiated (default 0) +traceSMB If set to one, debug information is logged to the + system error log with the start of smb requests + and responses (default 0) +LookupCacheEnable If set to one, inode information is kept cached + for one second improving performance of lookups + (default 1) +OplockEnabled If set to one, safe distributed caching enabled. + (default 1) +LinuxExtensionsEnabled If set to one then the client will attempt to + use the CIFS "UNIX" extensions which are optional + protocol enhancements that allow CIFS servers + to return accurate UID/GID information as well + as support symbolic links. If you use servers + such as Samba that support the CIFS Unix + extensions but do not want to use symbolic link + support and want to map the uid and gid fields + to values supplied at mount (rather than the + actual values, then set this to zero. (default 1) + +These experimental features and tracing can be enabled by changing flags in +/proc/fs/cifs (after the cifs module has been installed or built into the +kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable +tracing to the kernel message log type: + + echo 1 > /proc/fs/cifs/cifsFYI + +and for more extensive tracing including the start of smb requests and responses + + echo 1 > /proc/fs/cifs/traceSMB + +Three other experimental features are under development and to test +require enabling an ifdef (e.g. by adding "#define CIFS_FCNTL" in cifsglob.h) + + CONFIG_CIFS_QUOTA + + CONFIG_CIFS_XATTR + + CONFIG_CIFS_FCNTL (fcntl needed for support of directory change + notification and perhaps later for file leases) + +Per share (per client mount) statistics are available in /proc/fs/cifs/DebugData +if the kernel was configured with cifs statistics enabled. The statistics +represent the number of successful (ie non-zero return code from the server) +SMB responses to some of the more common commands (open, delete, mkdir etc.). +Also recorded is the total bytes read and bytes written to the server for +that share. Note that due to client caching effects this can be less than the +number of bytes read and written by the application running on the client. +The statistics for the number of total SMBs and oplock breaks are different in +that they represent all for that share, not just those for which the server +returned success. + +Also note that "cat /proc/fs/cifs/DebugData" will display information about +the active sessions and the shares that are mounted. Note: NTLMv2 enablement +will not work since they its implementation is not quite complete yet. +Do not alter these configuration values unless you are doing specific testing. +Enabling extended security works to Windows 2000 Workstations and XP but not to +Windows 2000 server or Samba since it does not usually send "raw NTLMSSP" +(instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not +complete in the CIFS VFS yet). diff -urN linux-2.4.27/fs/cifs/TODO linux-2.4.27-cifs-1.20c/fs/cifs/TODO --- linux-2.4.27/fs/cifs/TODO Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/TODO Wed Jul 14 00:25:04 2004 @@ -0,0 +1,106 @@ +version 1.16 May 27, 2004 + +A Partial List of Missing Features +================================== + +Contributions are welcome. There are plenty of opportunities +for visible, important contributions to this module. Here +is a partial list of the known problems and missing features: + +a) Support for SecurityDescriptors for chmod/chgrp/chown so +these can be supported for Windows servers + +b) Better pam/winbind integration + +c) multi-user mounts - multiplexed sessionsetups over single vc +(ie tcp session) - prettying up needed + +d) Kerberos/SPNEGO session setup support - (started) + +e) NTLMv2 authentication (mostly implemented) + +f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup +used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM +and raw NTLMSSP already. This is important when enabling +extended security and mounting to Windows 2003 Servers + +f) Directory entry caching relies on a 1 second timer, rather than +using FindNotify or equivalent. - (started) + +g) A few byte range testcases fail due to POSIX vs. Windows/CIFS +style byte range lock differences + +h) quota support + +i) support for the Linux 2.5 kernel new feature get_xattr and set_xattr +which will allow us to expose dos attributes as well as real +ACLs. This support has been started in the current code, but is +ifdeffed out. + +k) finish writepages support (multi-page write behind for improved +performance) and syncpage + +l) hook lower into the sockets api (as NFS/SunRPC does) to avoid the +extra copy in/out of the socket buffers in some cases. + +m) finish support for IPv6. This is mostly complete but +needs a simple inet_pton like function to convert ipv6 +addresses in string representation. + +o) Better optimize open (and pathbased setfilesize) to reduce the +oplock breaks coming from windows srv. Piggyback identical file +opens on top of each other by incrementing reference count rather +than resending (helps reduce server resource utilization and avoid +spurious oplock breaks). + +p) Improve performance of readpages by sending more than one read +at a time when 8 pages or more are requested. Evaluate whether +reads larger than 16K would be helpful. + +q) For support of Windows9x/98 we need to retry failed mounts +to *SMBSERVER (default server name) with the uppercase hostname +in the RFC1001 session_init request. + +r) Add Extended Attributed support (for storing UID/GID info +to Windows servers) + +s) Finish fcntl D_NOTIFY support so kde and gnome file list windows +will autorefresh + +t) Add GUI tool to configure /proc/fs/cifs settings and for display of +the CIFS statistics + +KNOWN BUGS (updated May 27, 2004) +==================================== +1) existing symbolic links (Windows reparse points) are recognized but +can not be created remotely. They are implemented for Samba and those that +support the CIFS Unix extensions but Samba has a bug currently handling +symlink text beginning with slash +2) follow_link and readdir code does not follow dfs junctions +but recognizes them +3) create of new files to FAT partitions on Windows servers can +succeed but still return access denied (appears to be Windows +server not cifs client problem) and has not been reproduced recently. +NTFS partitions do not have this problem. +4) debug connectathon lock test case 10 which fails against +Samba (may be unmappable due to POSIX to Windows lock model +differences but worth investigating). Also debug Samba to +see why lock test case 7 takes longer to complete to Samba +than to Windows. + +Misc testing to do +================== +1) check out max path names and max path name components against various server +types. Try nested symlinks. Return max path name in stat -f information + +2) Modify file portion of ltp so it can run against a mounted network +share and run it against cifs vfs. + +3) Additional performance testing and optimization using iozone and similar - +there are some easy changes that can be done to parallelize sequential writes, +and when signing is disabled to request larger read sizes (larger than +negotiated size) and send larger write sizes to modern servers. + +4) More exhaustively test the recently added NT4 support against various +NT4 service pack levels. + diff -urN linux-2.4.27/fs/cifs/asn1.c linux-2.4.27-cifs-1.20c/fs/cifs/asn1.c --- linux-2.4.27/fs/cifs/asn1.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/asn1.c Wed Jul 14 00:25:04 2004 @@ -0,0 +1,614 @@ +/* + * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in + * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich + * + * Copyright (c) 2000 RP Internet (www.rpi.net.au). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifs_debug.h" + +/***************************************************************************** + * + * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse) + * + *****************************************************************************/ + +/* Class */ +#define ASN1_UNI 0 /* Universal */ +#define ASN1_APL 1 /* Application */ +#define ASN1_CTX 2 /* Context */ +#define ASN1_PRV 3 /* Private */ + +/* Tag */ +#define ASN1_EOC 0 /* End Of Contents or N/A */ +#define ASN1_BOL 1 /* Boolean */ +#define ASN1_INT 2 /* Integer */ +#define ASN1_BTS 3 /* Bit String */ +#define ASN1_OTS 4 /* Octet String */ +#define ASN1_NUL 5 /* Null */ +#define ASN1_OJI 6 /* Object Identifier */ +#define ASN1_OJD 7 /* Object Description */ +#define ASN1_EXT 8 /* External */ +#define ASN1_SEQ 16 /* Sequence */ +#define ASN1_SET 17 /* Set */ +#define ASN1_NUMSTR 18 /* Numerical String */ +#define ASN1_PRNSTR 19 /* Printable String */ +#define ASN1_TEXSTR 20 /* Teletext String */ +#define ASN1_VIDSTR 21 /* Video String */ +#define ASN1_IA5STR 22 /* IA5 String */ +#define ASN1_UNITIM 23 /* Universal Time */ +#define ASN1_GENTIM 24 /* General Time */ +#define ASN1_GRASTR 25 /* Graphical String */ +#define ASN1_VISSTR 26 /* Visible String */ +#define ASN1_GENSTR 27 /* General String */ + +/* Primitive / Constructed methods*/ +#define ASN1_PRI 0 /* Primitive */ +#define ASN1_CON 1 /* Constructed */ + +/* + * Error codes. + */ +#define ASN1_ERR_NOERROR 0 +#define ASN1_ERR_DEC_EMPTY 2 +#define ASN1_ERR_DEC_EOC_MISMATCH 3 +#define ASN1_ERR_DEC_LENGTH_MISMATCH 4 +#define ASN1_ERR_DEC_BADVALUE 5 + +#define SPNEGO_OID_LEN 7 +#define NTLMSSP_OID_LEN 10 +unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; +unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; + +/* + * ASN.1 context. + */ +struct asn1_ctx { + int error; /* Error condition */ + unsigned char *pointer; /* Octet just to be decoded */ + unsigned char *begin; /* First octet */ + unsigned char *end; /* Octet after last octet */ +}; + +/* + * Octet string (not null terminated) + */ +struct asn1_octstr { + unsigned char *data; + unsigned int len; +}; + +static void +asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len) +{ + ctx->begin = buf; + ctx->end = buf + len; + ctx->pointer = buf; + ctx->error = ASN1_ERR_NOERROR; +} + +static unsigned char +asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch) +{ + if (ctx->pointer >= ctx->end) { + ctx->error = ASN1_ERR_DEC_EMPTY; + return 0; + } + *ch = *(ctx->pointer)++; + return 1; +} + +static unsigned char +asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) +{ + unsigned char ch; + + *tag = 0; + + do { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + *tag <<= 7; + *tag |= ch & 0x7F; + } while ((ch & 0x80) == 0x80); + return 1; +} + +static unsigned char +asn1_id_decode(struct asn1_ctx *ctx, + unsigned int *cls, unsigned int *con, unsigned int *tag) +{ + unsigned char ch; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *cls = (ch & 0xC0) >> 6; + *con = (ch & 0x20) >> 5; + *tag = (ch & 0x1F); + + if (*tag == 0x1F) { + if (!asn1_tag_decode(ctx, tag)) + return 0; + } + return 1; +} + +static unsigned char +asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len) +{ + unsigned char ch, cnt; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + if (ch == 0x80) + *def = 0; + else { + *def = 1; + + if (ch < 0x80) + *len = ch; + else { + cnt = (unsigned char) (ch & 0x7F); + *len = 0; + + while (cnt > 0) { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + *len <<= 8; + *len |= ch; + cnt--; + } + } + } + return 1; +} + +static unsigned char +asn1_header_decode(struct asn1_ctx *ctx, + unsigned char **eoc, + unsigned int *cls, unsigned int *con, unsigned int *tag) +{ + unsigned int def, len; + + if (!asn1_id_decode(ctx, cls, con, tag)) + return 0; + + if (!asn1_length_decode(ctx, &def, &len)) + return 0; + + if (def) + *eoc = ctx->pointer + len; + else + *eoc = NULL; + return 1; +} + +static unsigned char +asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc) +{ + unsigned char ch; + + if (eoc == 0) { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + if (ch != 0x00) { + ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + if (ch != 0x00) { + ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; + return 0; + } + return 1; + } else { + if (ctx->pointer != eoc) { + ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH; + return 0; + } + return 1; + } +} + +/* static unsigned char asn1_null_decode(struct asn1_ctx *ctx, + unsigned char *eoc) +{ + ctx->pointer = eoc; + return 1; +} + +static unsigned char asn1_long_decode(struct asn1_ctx *ctx, + unsigned char *eoc, long *integer) +{ + unsigned char ch; + unsigned int len; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer = (signed char) ch; + len = 1; + + while (ctx->pointer < eoc) { + if (++len > sizeof(long)) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer <<= 8; + *integer |= ch; + } + return 1; +} + +static unsigned char asn1_uint_decode(struct asn1_ctx *ctx, + unsigned char *eoc, + unsigned int *integer) +{ + unsigned char ch; + unsigned int len; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer = ch; + if (ch == 0) + len = 0; + else + len = 1; + + while (ctx->pointer < eoc) { + if (++len > sizeof(unsigned int)) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer <<= 8; + *integer |= ch; + } + return 1; +} + +static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx, + unsigned char *eoc, + unsigned long *integer) +{ + unsigned char ch; + unsigned int len; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer = ch; + if (ch == 0) + len = 0; + else + len = 1; + + while (ctx->pointer < eoc) { + if (++len > sizeof(unsigned long)) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer <<= 8; + *integer |= ch; + } + return 1; +} + +static unsigned char +asn1_octets_decode(struct asn1_ctx *ctx, + unsigned char *eoc, + unsigned char **octets, unsigned int *len) +{ + unsigned char *ptr; + + *len = 0; + + *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC); + if (*octets == NULL) { + return 0; + } + + ptr = *octets; + while (ctx->pointer < eoc) { + if (!asn1_octet_decode(ctx, (unsigned char *) ptr++)) { + kfree(*octets); + *octets = NULL; + return 0; + } + (*len)++; + } + return 1; +} */ + +static unsigned char +asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid) +{ + unsigned char ch; + + *subid = 0; + + do { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *subid <<= 7; + *subid |= ch & 0x7F; + } while ((ch & 0x80) == 0x80); + return 1; +} + +static unsigned char +asn1_oid_decode(struct asn1_ctx *ctx, + unsigned char *eoc, unsigned long **oid, unsigned int *len) +{ + unsigned long subid; + unsigned int size; + unsigned long *optr; + + size = eoc - ctx->pointer + 1; + *oid = kmalloc(size * sizeof (unsigned long), GFP_ATOMIC); + if (*oid == NULL) { + return 0; + } + + optr = *oid; + + if (!asn1_subid_decode(ctx, &subid)) { + kfree(*oid); + *oid = NULL; + return 0; + } + + if (subid < 40) { + optr[0] = 0; + optr[1] = subid; + } else if (subid < 80) { + optr[0] = 1; + optr[1] = subid - 40; + } else { + optr[0] = 2; + optr[1] = subid - 80; + } + + *len = 2; + optr += 2; + + while (ctx->pointer < eoc) { + if (++(*len) > size) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + kfree(*oid); + *oid = NULL; + return 0; + } + + if (!asn1_subid_decode(ctx, optr++)) { + kfree(*oid); + *oid = NULL; + return 0; + } + } + return 1; +} + +static int +compare_oid(unsigned long *oid1, unsigned int oid1len, + unsigned long *oid2, unsigned int oid2len) +{ + unsigned int i; + + if (oid1len != oid2len) + return 0; + else { + for (i = 0; i < oid1len; i++) { + if (oid1[i] != oid2[i]) + return 0; + } + return 1; + } +} + + /* BB check for endian conversion issues here */ + +int +decode_negTokenInit(unsigned char *security_blob, int length, + enum securityEnum *secType) +{ + struct asn1_ctx ctx; + unsigned char *end; + unsigned char *sequence_end; + unsigned long *oid; + unsigned int cls, con, tag, oidlen, rc; + int use_ntlmssp = FALSE; + + *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default */ + + /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */ + + asn1_open(&ctx, security_blob, length); + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, ("Error decoding negTokenInit header ")); + return 0; + } else if ((cls != ASN1_APL) || (con != ASN1_CON) + || (tag != ASN1_EOC)) { + cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag)); + return 0; + } else { + /* remember to free obj->oid */ + rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); + if (rc) { + if ((tag == ASN1_OJI) && (cls == ASN1_PRI)) { + rc = asn1_oid_decode(&ctx, end, &oid, &oidlen); + if (rc) { + rc = compare_oid(oid, oidlen, + SPNEGO_OID, + SPNEGO_OID_LEN); + kfree(oid); + } + } else + rc = 0; + } + + if (!rc) { + cFYI(1, ("Error decoding negTokenInit header")); + return 0; + } + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, ("Error decoding negTokenInit ")); + return 0; + } else if ((cls != ASN1_CTX) || (con != ASN1_CON) + || (tag != ASN1_EOC)) { + cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 0", + cls, con, tag, end, *end)); + return 0; + } + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, ("Error decoding negTokenInit ")); + return 0; + } else if ((cls != ASN1_UNI) || (con != ASN1_CON) + || (tag != ASN1_SEQ)) { + cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 1", + cls, con, tag, end, *end)); + return 0; + } + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, ("Error decoding 2nd part of negTokenInit ")); + return 0; + } else if ((cls != ASN1_CTX) || (con != ASN1_CON) + || (tag != ASN1_EOC)) { + cFYI(1, + ("cls = %d con = %d tag = %d end = %p (%d) exit 0", + cls, con, tag, end, *end)); + return 0; + } + + if (asn1_header_decode + (&ctx, &sequence_end, &cls, &con, &tag) == 0) { + cFYI(1, ("Error decoding 2nd part of negTokenInit ")); + return 0; + } else if ((cls != ASN1_UNI) || (con != ASN1_CON) + || (tag != ASN1_SEQ)) { + cFYI(1, + ("cls = %d con = %d tag = %d end = %p (%d) exit 1", + cls, con, tag, end, *end)); + return 0; + } + + while (!asn1_eoc_decode(&ctx, sequence_end)) { + rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); + if (!rc) { + cFYI(1, + ("Error 1 decoding negTokenInit header exit 2")); + return 0; + } + if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { + asn1_oid_decode(&ctx, end, &oid, &oidlen); + cFYI(1, + ("OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx", + oidlen, *oid, *(oid + 1), *(oid + 2), + *(oid + 3))); + rc = compare_oid(oid, oidlen, NTLMSSP_OID, + NTLMSSP_OID_LEN); + kfree(oid); + if (rc) + use_ntlmssp = TRUE; + } else { + cFYI(1,("This should be an oid what is going on? ")); + } + } + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, + ("Error decoding last part of negTokenInit exit 3")); + return 0; + } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { /* tag = 3 indicating mechListMIC */ + cFYI(1, + ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)", + cls, con, tag, end, *end)); + return 0; + } + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, + ("Error decoding last part of negTokenInit exit 5")); + return 0; + } else if ((cls != ASN1_UNI) || (con != ASN1_CON) + || (tag != ASN1_SEQ)) { + cFYI(1, + ("Exit 6 cls = %d con = %d tag = %d end = %p (%d)", + cls, con, tag, end, *end)); + } + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, + ("Error decoding last part of negTokenInit exit 7")); + return 0; + } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { + cFYI(1, + ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)", + cls, con, tag, end, *end)); + return 0; + } + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, + ("Error decoding last part of negTokenInit exit 9")); + return 0; + } else if ((cls != ASN1_UNI) || (con != ASN1_PRI) + || (tag != ASN1_GENSTR)) { + cFYI(1, + ("Exit 10 cls = %d con = %d tag = %d end = %p (%d)", + cls, con, tag, end, *end)); + return 0; + } + cFYI(1, ("Need to call asn1_octets_decode() function for this %s", ctx.pointer)); /* is this UTF-8 or ASCII? */ + } + + /* if (use_kerberos) + *secType = Kerberos + else */ + if (use_ntlmssp) { + *secType = NTLMSSP; + } + + return 1; +} diff -urN linux-2.4.27/fs/cifs/cifs_debug.c linux-2.4.27-cifs-1.20c/fs/cifs/cifs_debug.c --- linux-2.4.27/fs/cifs/cifs_debug.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifs_debug.c Wed Jul 14 00:25:04 2004 @@ -0,0 +1,797 @@ +/* + * fs/cifs_debug.c + * + * Copyright (C) International Business Machines Corp., 2000,2003 + * + * Modified by Steve French (sfrench@us.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" + +void +cifs_dump_mem(char *label, void *data, int length) +{ + int i, j; + int *intptr = data; + char *charptr = data; + char buf[10], line[80]; + + printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n", + label, length, data); + for (i = 0; i < length; i += 16) { + line[0] = 0; + for (j = 0; (j < 4) && (i + j * 4 < length); j++) { + sprintf(buf, " %08x", intptr[i / 4 + j]); + strcat(line, buf); + } + buf[0] = ' '; + buf[2] = 0; + for (j = 0; (j < 16) && (i + j < length); j++) { + buf[1] = isprint(charptr[i + j]) ? charptr[i + j] : '.'; + strcat(line, buf); + } + printk(KERN_DEBUG "%s\n", line); + } +} + +#ifdef CONFIG_PROC_FS +int +cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, + int count, int *eof, void *data) +{ + struct list_head *tmp; + struct list_head *tmp1; + struct mid_q_entry * mid_entry; + struct cifsSesInfo *ses; + struct cifsTconInfo *tcon; + int i; + int length = 0; + char * original_buf = buf; + + *beginBuffer = buf + offset; + + + length = + sprintf(buf, + "Display Internal CIFS Data Structures for Debugging\n" + "---------------------------------------------------\n"); + buf += length; + + length = sprintf(buf, "Servers:\n"); + buf += length; + + i = 0; + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalSMBSessionList) { + i++; + ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); + length = + sprintf(buf, + "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\tTCP status: %d", + i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), + ses->serverOS, ses->serverNOS, ses->capabilities,ses->status,ses->server->tcpStatus); + buf += length; + if(ses->server) { + buf += sprintf(buf, "\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", + atomic_read(&ses->server->socketUseCount), + ses->server->secMode, + atomic_read(&ses->server->inFlight)); + + length = sprintf(buf, "\nMIDs: \n"); + buf += length; + + spin_lock(&GlobalMid_Lock); + list_for_each(tmp1, &ses->server->pending_mid_q) { + mid_entry = list_entry(tmp1, struct + mid_q_entry, + qhead); + if(mid_entry) { + 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); + buf += length; + } + } + spin_unlock(&GlobalMid_Lock); + } + + } + read_unlock(&GlobalSMBSeslock); + sprintf(buf, "\n"); + buf++; + + length = sprintf(buf, "\nShares:\n"); + buf += length; + + i = 0; + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalTreeConnectionList) { + i++; + tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + length = + sprintf(buf, + "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", + i, tcon->treeName, + atomic_read(&tcon->useCount), + tcon->nativeFileSystem, + tcon->fsDevInfo.DeviceCharacteristics, + tcon->fsAttrInfo.Attributes, + tcon->fsAttrInfo.MaxPathNameComponentLength,tcon->tidStatus); + buf += length; + if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_DISK) + length = sprintf(buf, " type: DISK "); + else if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_CD_ROM) + length = sprintf(buf, " type: CDROM "); + else + length = + sprintf(buf, " type: %d ", + tcon->fsDevInfo.DeviceType); + buf += length; + if(tcon->tidStatus == CifsNeedReconnect) { + buf += sprintf(buf, "\tDISCONNECTED "); + length += 14; + } + } + read_unlock(&GlobalSMBSeslock); + + length = sprintf(buf, "\n"); + buf += length; + + /* BB add code to dump additional info such as TCP session info now */ + /* Now calculate total size of returned data */ + length = buf - original_buf; + + if(offset + count >= length) + *eof = 1; + if(length < offset) { + *eof = 1; + return 0; + } else { + length = length - offset; + } + if (length > count) + length = count; + + return length; +} + +#ifdef CONFIG_CIFS_STATS +int +cifs_stats_read(char *buf, char **beginBuffer, off_t offset, + int count, int *eof, void *data) +{ + int item_length,i,length; + struct list_head *tmp; + struct cifsTconInfo *tcon; + + *beginBuffer = buf + offset; + + length = sprintf(buf, + "Resources in use\nCIFS Session: %d\n", + sesInfoAllocCount.counter); + buf += length; + item_length = + sprintf(buf,"Share (unique mount targets): %d\n", + tconInfoAllocCount.counter); + length += item_length; + buf += item_length; + item_length = + sprintf(buf,"SMB Request/Response Buffer: %d\n", + bufAllocCount.counter); + length += item_length; + buf += item_length; + item_length = + sprintf(buf,"Operations (MIDs): %d\n", + midCount.counter); + length += item_length; + buf += item_length; + item_length = sprintf(buf, + "\n%d session %d share reconnects\n", + tcpSesReconnectCount.counter,tconInfoReconnectCount.counter); + length += item_length; + buf += item_length; + + item_length = sprintf(buf, + "Total vfs operations: %d maximum at one time: %d\n", + GlobalCurrentXid,GlobalMaxActiveXid); + length += item_length; + buf += item_length; + + i = 0; + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalTreeConnectionList) { + i++; + tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + item_length = sprintf(buf,"\n%d) %s",i, tcon->treeName); + buf += item_length; + length += item_length; + if(tcon->tidStatus == CifsNeedReconnect) { + buf += sprintf(buf, "\tDISCONNECTED "); + length += 14; + } + item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d", + atomic_read(&tcon->num_smbs_sent), + atomic_read(&tcon->num_oplock_brks)); + buf += item_length; + length += item_length; + item_length = sprintf(buf,"\nReads: %d Bytes %lld", + atomic_read(&tcon->num_reads), + (long long)(tcon->bytes_read)); + buf += item_length; + length += item_length; + item_length = sprintf(buf,"\nWrites: %d Bytes: %lld", + atomic_read(&tcon->num_writes), + (long long)(tcon->bytes_written)); + buf += item_length; + length += item_length; + item_length = sprintf(buf, + "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d", + atomic_read(&tcon->num_opens), + atomic_read(&tcon->num_deletes), + atomic_read(&tcon->num_mkdirs), + atomic_read(&tcon->num_rmdirs)); + buf += item_length; + length += item_length; + item_length = sprintf(buf, + "\nRenames: %d T2 Renames %d", + atomic_read(&tcon->num_renames), + atomic_read(&tcon->num_t2renames)); + buf += item_length; + length += item_length; + } + read_unlock(&GlobalSMBSeslock); + + buf += sprintf(buf,"\n"); + length++; + + if(offset + count >= length) + *eof = 1; + if(length < offset) { + *eof = 1; + return 0; + } else { + length = length - offset; + } + if (length > count) + length = count; + + return length; +} +#endif + +struct proc_dir_entry *proc_fs_cifs; +read_proc_t cifs_txanchor_read; +static read_proc_t cifsFYI_read; +static write_proc_t cifsFYI_write; +static read_proc_t oplockEnabled_read; +static write_proc_t oplockEnabled_write; +static read_proc_t lookupFlag_read; +static write_proc_t lookupFlag_write; +static read_proc_t traceSMB_read; +static write_proc_t traceSMB_write; +static read_proc_t multiuser_mount_read; +static write_proc_t multiuser_mount_write; +static read_proc_t extended_security_read; +static write_proc_t extended_security_write; +static read_proc_t ntlmv2_enabled_read; +static write_proc_t ntlmv2_enabled_write; +static read_proc_t packet_signing_enabled_read; +static write_proc_t packet_signing_enabled_write; +static read_proc_t quotaEnabled_read; +static write_proc_t quotaEnabled_write; +static read_proc_t linuxExtensionsEnabled_read; +static write_proc_t linuxExtensionsEnabled_write; + +void +cifs_proc_init(void) +{ + struct proc_dir_entry *pde; + + proc_fs_cifs = proc_mkdir("cifs", proc_root_fs); + if (proc_fs_cifs == NULL) + return; + + proc_fs_cifs->owner = THIS_MODULE; + create_proc_read_entry("DebugData", 0, proc_fs_cifs, + cifs_debug_data_read, NULL); + +#ifdef CONFIG_CIFS_STATS + create_proc_read_entry("Stats", 0, proc_fs_cifs, + cifs_stats_read, NULL); +#endif + pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, + cifsFYI_read, NULL); + if (pde) + pde->write_proc = cifsFYI_write; + + pde = + create_proc_read_entry("traceSMB", 0, proc_fs_cifs, + traceSMB_read, NULL); + if (pde) + pde->write_proc = traceSMB_write; + + pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs, + oplockEnabled_read, NULL); + if (pde) + pde->write_proc = oplockEnabled_write; + + pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs, + quotaEnabled_read, NULL); + if (pde) + pde->write_proc = quotaEnabled_write; + + pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, + linuxExtensionsEnabled_read, NULL); + if (pde) + pde->write_proc = linuxExtensionsEnabled_write; + + pde = + create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs, + multiuser_mount_read, NULL); + if (pde) + pde->write_proc = multiuser_mount_write; + + pde = + create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, + extended_security_read, NULL); + if (pde) + pde->write_proc = extended_security_write; + + pde = + create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, + lookupFlag_read, NULL); + if (pde) + pde->write_proc = lookupFlag_write; + + pde = + create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, + ntlmv2_enabled_read, NULL); + if (pde) + pde->write_proc = ntlmv2_enabled_write; + + pde = + create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, + packet_signing_enabled_read, NULL); + if (pde) + pde->write_proc = packet_signing_enabled_write; +} + +void +cifs_proc_clean(void) +{ + if (proc_fs_cifs == NULL) + return; + + remove_proc_entry("DebugData", proc_fs_cifs); + remove_proc_entry("cifsFYI", proc_fs_cifs); + remove_proc_entry("traceSMB", proc_fs_cifs); +#ifdef CONFIG_CIFS_STATS + remove_proc_entry("Stats", proc_fs_cifs); +#endif + remove_proc_entry("MultiuserMount", proc_fs_cifs); + remove_proc_entry("OplockEnabled", proc_fs_cifs); + remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); + remove_proc_entry("ExtendedSecurity",proc_fs_cifs); + remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); + remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); + remove_proc_entry("QuotaEnabled",proc_fs_cifs); + remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); + remove_proc_entry("cifs", proc_root_fs); +} + +static int +cifsFYI_read(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", cifsFYI); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +cifsFYI_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + cifsFYI = 0; + else if (c == '1' || c == 'y' || c == 'Y') + cifsFYI = 1; + + return count; +} + +static int +oplockEnabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", oplockEnabled); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +oplockEnabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + oplockEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + oplockEnabled = 1; + + return count; +} + +static int +quotaEnabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", quotaEnabled); +/* could also check if quotas are enabled in kernel + as a whole first */ + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +quotaEnabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + quotaEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + quotaEnabled = 1; + + return count; +} + +static int +linuxExtensionsEnabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", linuxExtEnabled); +/* could also check if quotas are enabled in kernel + as a whole first */ + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +linuxExtensionsEnabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + linuxExtEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + linuxExtEnabled = 1; + + return count; +} + + +static int +lookupFlag_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", lookupCacheEnabled); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +lookupFlag_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + lookupCacheEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + lookupCacheEnabled = 1; + + return count; +} +static int +traceSMB_read(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", traceSMB); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +traceSMB_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + traceSMB = 0; + else if (c == '1' || c == 'y' || c == 'Y') + traceSMB = 1; + + return count; +} + +static int +multiuser_mount_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", multiuser_mount); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +multiuser_mount_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + multiuser_mount = 0; + else if (c == '1' || c == 'y' || c == 'Y') + multiuser_mount = 1; + + return count; +} + +static int +extended_security_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", extended_security); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +extended_security_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + extended_security = 0; + else if (c == '1' || c == 'y' || c == 'Y') + extended_security = 1; + + return count; +} + +static int +ntlmv2_enabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", ntlmv2_support); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +ntlmv2_enabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + ntlmv2_support = 0; + else if (c == '1' || c == 'y' || c == 'Y') + ntlmv2_support = 1; + + return count; +} + +static int +packet_signing_enabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", sign_CIFS_PDUs); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +packet_signing_enabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + sign_CIFS_PDUs = 0; + else if (c == '1' || c == 'y' || c == 'Y') + sign_CIFS_PDUs = 1; + else if (c == '2') + sign_CIFS_PDUs = 2; + + return count; +} + + +#endif diff -urN linux-2.4.27/fs/cifs/cifs_debug.h linux-2.4.27-cifs-1.20c/fs/cifs/cifs_debug.h --- linux-2.4.27/fs/cifs/cifs_debug.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifs_debug.h Wed Jul 14 00:25:04 2004 @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2000,2002 + * Modified by Steve French (sfrench@us.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * +*/ +#define CIFS_DEBUG /* BB temporary */ + +#ifndef _H_CIFS_DEBUG +#define _H_CIFS_DEBUG + +void cifs_dump_mem(char *label, void *data, int length); +extern int traceSMB; /* flag which enables the function below */ +void dump_smb(struct smb_hdr *, int); + +/* + * debug ON + * -------- + */ +#ifdef CIFS_DEBUG + + +/* information message: e.g., configuration, major event */ +extern int cifsFYI; +#define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg) + +#define cFYI(button,prspec) if (button) cifsfyi prspec + +#define cifswarn(format, arg...) printk(KERN_WARNING ": " format "\n" , ## arg) + +/* debug event message: */ +extern int cifsERROR; + +#define cEVENT(format,arg...) if (cifsERROR) printk(KERN_EVENT __FILE__ ": " format "\n" , ## arg) + +/* error event message: e.g., i/o error */ +#define cifserror(format,arg...) if (cifsERROR) printk(KERN_ERR " CIFS VFS: " format "\n" "" , ## arg) + +#define cERROR(button, prspec) if (button) cifserror prspec + +/* + * debug OFF + * --------- + */ +#else /* _CIFS_DEBUG */ +#define cERROR(button,prspec) +#define cEVENT(format,arg...) +#define cFYI(button, prspec) +#define cifserror(format,arg...) +#endif /* _CIFS_DEBUG */ + +#endif /* _H_CIFS_DEBUG */ diff -urN linux-2.4.27/fs/cifs/cifs_fs_sb.h linux-2.4.27-cifs-1.20c/fs/cifs/cifs_fs_sb.h --- linux-2.4.27/fs/cifs/cifs_fs_sb.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifs_fs_sb.h Wed Jul 14 00:25:04 2004 @@ -0,0 +1,32 @@ +/* + * fs/cifs/cifs_fs_sb.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + */ +#ifndef _CIFS_FS_SB_H +#define _CIFS_FS_SB_H + +struct cifs_sb_info { + struct cifsTconInfo *tcon; /* primary mount */ + struct list_head nested_tcon_q; + struct nls_table *local_nls; + unsigned int rsize; + unsigned int wsize; + uid_t mnt_uid; + gid_t mnt_gid; + mode_t mnt_file_mode; + mode_t mnt_dir_mode; +}; +#endif /* _CIFS_FS_SB_H */ diff -urN linux-2.4.27/fs/cifs/cifs_unicode.c linux-2.4.27-cifs-1.20c/fs/cifs/cifs_unicode.c --- linux-2.4.27/fs/cifs/cifs_unicode.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifs_unicode.c Wed Jul 14 00:25:04 2004 @@ -0,0 +1,87 @@ +/* + * fs/cifs/cifs_unicode.c + * + * Copyright (c) International Business Machines Corp., 2000,2002 + * Modified by Steve French (sfrench@us.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include "cifs_unicode.h" +#include "cifs_uniupr.h" +#include "cifspdu.h" +#include "cifs_debug.h" + +/* + * NAME: cifs_strfromUCS() + * + * FUNCTION: Convert little-endian unicode string to character string + * + */ +int +cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */ + int len, const struct nls_table *codepage) +{ + int i; + int outlen = 0; + + for (i = 0; (i < len) && from[i]; i++) { + int charlen; + /* 2.4.0 kernel or greater */ + charlen = + codepage->uni2char(le16_to_cpu(from[i]), &to[outlen], + NLS_MAX_CHARSET_SIZE); + if (charlen > 0) { + outlen += charlen; + } else { + to[outlen++] = '?'; + } + } + to[outlen] = 0; + return outlen; +} + +/* + * NAME: cifs_strtoUCS() + * + * FUNCTION: Convert character string to unicode string + * + */ +int +cifs_strtoUCS(wchar_t * to, const char *from, int len, + const struct nls_table *codepage) +{ + int charlen; + int i; + + for (i = 0; len && *from; i++, from += charlen, len -= charlen) { + + /* works for 2.4.0 kernel or later */ + charlen = codepage->char2uni(from, len, &to[i]); + if (charlen < 1) { + cERROR(1, + ("cifs_strtoUCS: char2uni returned %d", + charlen)); + to[i] = cpu_to_le16(0x003f); /* a question mark */ + charlen = 1; + } + to[i] = cpu_to_le16(to[i]); + + } + + to[i] = 0; + return i; +} + diff -urN linux-2.4.27/fs/cifs/cifs_unicode.h linux-2.4.27-cifs-1.20c/fs/cifs/cifs_unicode.h --- linux-2.4.27/fs/cifs/cifs_unicode.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifs_unicode.h Wed Jul 14 00:25:04 2004 @@ -0,0 +1,353 @@ +/* + * cifs_unicode: Unicode kernel case support + * + * Function: + * Convert a unicode character to upper or lower case using + * compressed tables. + * + * Copyright (c) International Business Machines Corp., 2000,2002 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Notes: + * These APIs are based on the C library functions. The semantics + * should match the C functions but with expanded size operands. + * + * The upper/lower functions are based on a table created by mkupr. + * This is a compressed table of upper and lower case conversion. + * + */ + +#include +#include +#include + +#define UNIUPR_NOLOWER /* Example to not expand lower case tables */ + +/* Just define what we want from uniupr.h. We don't want to define the tables + * in each source file. + */ +#ifndef UNICASERANGE_DEFINED +struct UniCaseRange { + wchar_t start; + wchar_t end; + signed char *table; +}; +#endif /* UNICASERANGE_DEFINED */ + +#ifndef UNIUPR_NOUPPER +extern signed char CifsUniUpperTable[512]; +extern const struct UniCaseRange CifsUniUpperRange[]; +#endif /* UNIUPR_NOUPPER */ + +#ifndef UNIUPR_NOLOWER +extern signed char UniLowerTable[512]; +extern struct UniCaseRange UniLowerRange[]; +#endif /* UNIUPR_NOLOWER */ + +#ifdef __KERNEL__ +int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *); +int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *); +#endif + +/* + * UniStrcat: Concatenate the second string to the first + * + * Returns: + * Address of the first string + */ +static inline wchar_t * +UniStrcat(wchar_t * ucs1, const wchar_t * ucs2) +{ + wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */ + + while (*ucs1++) ; /* To end of first string */ + ucs1--; /* Return to the null */ + while ((*ucs1++ = *ucs2++)) ; /* copy string 2 over */ + return anchor; +} + +/* + * UniStrchr: Find a character in a string + * + * Returns: + * Address of first occurrence of character in string + * or NULL if the character is not in the string + */ +static inline wchar_t * +UniStrchr(const wchar_t * ucs, wchar_t uc) +{ + while ((*ucs != uc) && *ucs) + ucs++; + + if (*ucs == uc) + return (wchar_t *) ucs; + return NULL; +} + +/* + * UniStrcmp: Compare two strings + * + * Returns: + * < 0: First string is less than second + * = 0: Strings are equal + * > 0: First string is greater than second + */ +static inline int +UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2) +{ + while ((*ucs1 == *ucs2) && *ucs1) { + ucs1++; + ucs2++; + } + return (int) *ucs1 - (int) *ucs2; +} + +/* + * UniStrcpy: Copy a string + */ +static inline wchar_t * +UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2) +{ + wchar_t *anchor = ucs1; /* save the start of result string */ + + while ((*ucs1++ = *ucs2++)) ; + return anchor; +} + +/* + * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes) + */ +static inline size_t +UniStrlen(const wchar_t * ucs1) +{ + int i = 0; + + while (*ucs1++) + i++; + return i; +} + +/* + * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a string (length limited) + */ +static inline size_t +UniStrnlen(const wchar_t * ucs1, int maxlen) +{ + int i = 0; + + while (*ucs1++) { + i++; + if (i >= maxlen) + break; + } + return i; +} + +/* + * UniStrncat: Concatenate length limited string + */ +static inline wchar_t * +UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n) +{ + wchar_t *anchor = ucs1; /* save pointer to string 1 */ + + while (*ucs1++) ; + ucs1--; /* point to null terminator of s1 */ + while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */ + ucs1++; + ucs2++; + } + *ucs1 = 0; /* Null terminate the result */ + return (anchor); +} + +/* + * UniStrncmp: Compare length limited string + */ +static inline int +UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) +{ + if (!n) + return 0; /* Null strings are equal */ + while ((*ucs1 == *ucs2) && *ucs1 && --n) { + ucs1++; + ucs2++; + } + return (int) *ucs1 - (int) *ucs2; +} + +/* + * UniStrncmp_le: Compare length limited string - native to little-endian + */ +static inline int +UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) +{ + if (!n) + return 0; /* Null strings are equal */ + while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) { + ucs1++; + ucs2++; + } + return (int) *ucs1 - (int) __le16_to_cpu(*ucs2); +} + +/* + * UniStrncpy: Copy length limited string with pad + */ +static inline wchar_t * +UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n) +{ + wchar_t *anchor = ucs1; + + while (n-- && *ucs2) /* Copy the strings */ + *ucs1++ = *ucs2++; + + n++; + while (n--) /* Pad with nulls */ + *ucs1++ = 0; + return anchor; +} + +/* + * UniStrncpy_le: Copy length limited string with pad to little-endian + */ +static inline wchar_t * +UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n) +{ + wchar_t *anchor = ucs1; + + while (n-- && *ucs2) /* Copy the strings */ + *ucs1++ = __le16_to_cpu(*ucs2++); + + n++; + while (n--) /* Pad with nulls */ + *ucs1++ = 0; + return anchor; +} + +/* + * UniStrstr: Find a string in a string + * + * Returns: + * Address of first match found + * NULL if no matching string is found + */ +static inline wchar_t * +UniStrstr(const wchar_t * ucs1, const wchar_t * ucs2) +{ + const wchar_t *anchor1 = ucs1; + const wchar_t *anchor2 = ucs2; + + while (*ucs1) { + if (*ucs1 == *ucs2) { /* Partial match found */ + ucs1++; + ucs2++; + } else { + if (!*ucs2) /* Match found */ + return (wchar_t *) anchor1; + ucs1 = ++anchor1; /* No match */ + ucs2 = anchor2; + } + } + + if (!*ucs2) /* Both end together */ + return (wchar_t *) anchor1; /* Match found */ + return NULL; /* No match */ +} + +#ifndef UNIUPR_NOUPPER +/* + * UniToupper: Convert a unicode character to upper case + */ +static inline wchar_t +UniToupper(register wchar_t uc) +{ + register const struct UniCaseRange *rp; + + if (uc < sizeof (CifsUniUpperTable)) { /* Latin characters */ + return uc + CifsUniUpperTable[uc]; /* Use base tables */ + } else { + rp = CifsUniUpperRange; /* Use range tables */ + while (rp->start) { + if (uc < rp->start) /* Before start of range */ + return uc; /* Uppercase = input */ + if (uc <= rp->end) /* In range */ + return uc + rp->table[uc - rp->start]; + rp++; /* Try next range */ + } + } + return uc; /* Past last range */ +} + +/* + * UniStrupr: Upper case a unicode string + */ +static inline wchar_t * +UniStrupr(register wchar_t * upin) +{ + register wchar_t *up; + + up = upin; + while (*up) { /* For all characters */ + *up = UniToupper(*up); + up++; + } + return upin; /* Return input pointer */ +} +#endif /* UNIUPR_NOUPPER */ + +#ifndef UNIUPR_NOLOWER +/* + * UniTolower: Convert a unicode character to lower case + */ +static inline wchar_t +UniTolower(wchar_t uc) +{ + register struct UniCaseRange *rp; + + if (uc < sizeof (UniLowerTable)) { /* Latin characters */ + return uc + UniLowerTable[uc]; /* Use base tables */ + } else { + rp = UniLowerRange; /* Use range tables */ + while (rp->start) { + if (uc < rp->start) /* Before start of range */ + return uc; /* Uppercase = input */ + if (uc <= rp->end) /* In range */ + return uc + rp->table[uc - rp->start]; + rp++; /* Try next range */ + } + } + return uc; /* Past last range */ +} + +/* + * UniStrlwr: Lower case a unicode string + */ +static inline wchar_t * +UniStrlwr(register wchar_t * upin) +{ + register wchar_t *up; + + up = upin; + while (*up) { /* For all characters */ + *up = UniTolower(*up); + up++; + } + return upin; /* Return input pointer */ +} + +#endif diff -urN linux-2.4.27/fs/cifs/cifs_uniupr.h linux-2.4.27-cifs-1.20c/fs/cifs/cifs_uniupr.h --- linux-2.4.27/fs/cifs/cifs_uniupr.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifs_uniupr.h Wed Jul 14 00:25:04 2004 @@ -0,0 +1,253 @@ +/* + * Copyright (c) International Business Machines Corp., 2000,2002 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * uniupr.h - Unicode compressed case ranges + * +*/ + +#ifndef UNIUPR_NOUPPER +/* + * Latin upper case + */ +signed char CifsUniUpperTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */ + 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 060-06f */ + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 0, 0, 0, 0, 0, /* 070-07f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */ + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 0e0-0ef */ + -32, -32, -32, -32, -32, -32, -32, 0, -32, -32, -32, -32, -32, -32, -32, 121, /* 0f0-0ff */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */ + 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */ + -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */ + 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */ + 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */ + 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */ + -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */ + 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */ + -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */ + 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */ +}; + +/* Upper case range - Greek */ +static signed char UniCaseRangeU03a0[47] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37, /* 3a0-3af */ + 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 3b0-3bf */ + -32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64, + -63, -63, +}; + +/* Upper case range - Cyrillic */ +static signed char UniCaseRangeU0430[48] = { + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 430-43f */ + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 440-44f */ + 0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, 0, -80, -80, /* 450-45f */ +}; + +/* Upper case range - Extended cyrillic */ +static signed char UniCaseRangeU0490[61] = { + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */ + 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, +}; + +/* Upper case range - Extended latin and greek */ +static signed char UniCaseRangeU1e00[509] = { + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */ + 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1, /* 1e90-1e9f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */ + 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */ + 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */ + 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */ + 74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, 126, 126, 0, 0, /* 1f70-1f7f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */ + 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */ + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */ + 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */ + 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */ + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* Upper case range - Wide latin */ +static signed char UniCaseRangeUff40[27] = { + 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* ff40-ff4f */ + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, +}; + +/* + * Upper Case Range + */ +const struct UniCaseRange CifsUniUpperRange[] = { + {0x03a0, 0x03ce, UniCaseRangeU03a0}, + {0x0430, 0x045f, UniCaseRangeU0430}, + {0x0490, 0x04cc, UniCaseRangeU0490}, + {0x1e00, 0x1ffc, UniCaseRangeU1e00}, + {0xff40, 0xff5a, UniCaseRangeUff40}, + {0, 0, NULL} +}; +#endif + +#ifndef UNIUPR_NOLOWER +/* + * Latin lower case + */ +static signed char CifsUniLowerTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ + 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 040-04f */ + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, /* 050-05f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 0c0-0cf */ + 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0, /* 0d0-0df */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */ + 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */ + 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 0, /* 170-17f */ + 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 0, /* 180-18f */ + 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */ + 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */ + 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */ + 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */ + 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */ +}; + +/* Lower case range - Greek */ +static signed char UniCaseRangeL0380[44] = { + 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */ + 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 390-39f */ + 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, +}; + +/* Lower case range - Cyrillic */ +static signed char UniCaseRangeL0400[48] = { + 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80, /* 400-40f */ + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 410-41f */ + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 420-42f */ +}; + +/* Lower case range - Extended cyrillic */ +static signed char UniCaseRangeL0490[60] = { + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */ + 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, +}; + +/* Lower case range - Extended latin and greek */ +static signed char UniCaseRangeL1e00[504] = { + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */ + 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */ + 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 0, 0, /* 1fc0-1fcf */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 0, 0, /* 1fe0-1fef */ + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* Lower case range - Wide latin */ +static signed char UniCaseRangeLff20[27] = { + 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* ff20-ff2f */ + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +}; + +/* + * Lower Case Range + */ +const static struct UniCaseRange CifsUniLowerRange[] = { + 0x0380, 0x03ab, UniCaseRangeL0380, + 0x0400, 0x042f, UniCaseRangeL0400, + 0x0490, 0x04cb, UniCaseRangeL0490, + 0x1e00, 0x1ff7, UniCaseRangeL1e00, + 0xff20, 0xff3a, UniCaseRangeLff20, + 0, 0, 0 +}; +#endif diff -urN linux-2.4.27/fs/cifs/cifsencrypt.c linux-2.4.27-cifs-1.20c/fs/cifs/cifsencrypt.c --- linux-2.4.27/fs/cifs/cifsencrypt.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifsencrypt.c Wed Jul 14 00:25:04 2004 @@ -0,0 +1,204 @@ +/* + * fs/cifs/cifsencrypt.c + * + * Copyright (C) International Business Machines Corp., 2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifs_debug.h" +#include "md5.h" +#include "cifs_unicode.h" + +/* Calculate and return the CIFS signature based on the mac key and the smb pdu */ +/* the 16 byte signature must be allocated by the caller */ +/* Note we only use the 1st eight bytes */ +/* Note that the smb header signature field on input contains the + sequence number before this function is called */ + +extern void mdfour(unsigned char *out, unsigned char *in, int n); +extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); + +static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature) +{ + struct MD5Context context; + + if((cifs_pdu == NULL) || (signature == NULL)) + return -EINVAL; + + MD5Init(&context); + MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); + MD5Final(signature,&context); + return 0; +} + +int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, + __u32 * pexpected_response_sequence_number) +{ + int rc = 0; + char smb_signature[20]; + + /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */ + /* BB remember to add code to save expected sequence number in midQ entry BB */ + + if((cifs_pdu == NULL) || (ses == NULL)) + return -EINVAL; + + if((le32_to_cpu(cifs_pdu->Flags2) & SMBFLG2_SECURITY_SIGNATURE) == 0) + return rc; + + spin_lock(&GlobalMid_Lock); + cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number); + cifs_pdu->Signature.Sequence.Reserved = 0; + + *pexpected_response_sequence_number = ses->sequence_number++; + ses->sequence_number++; + spin_unlock(&GlobalMid_Lock); + + rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature); + if(rc) + memset(cifs_pdu->Signature.SecuritySignature, 0, 8); + else + memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); + + return rc; +} + +int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, + __u32 expected_sequence_number) +{ + unsigned int rc; + char server_response_sig[8]; + char what_we_think_sig_should_be[20]; + + if((cifs_pdu == NULL) || (mac_key == NULL)) + return -EINVAL; + + if (cifs_pdu->Command == SMB_COM_NEGOTIATE) + return 0; + + if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { + struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu; + if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) + return 0; + } + + /* BB what if signatures are supposed to be on for session but server does not + send one? BB */ + + /* Do not need to verify session setups with signature "BSRSPYL " */ + if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0) + cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command)); + + expected_sequence_number = cpu_to_le32(expected_sequence_number); + + /* save off the origiginal signature so we can modify the smb and check + its signature against what the server sent */ + memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8); + + cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number; + cifs_pdu->Signature.Sequence.Reserved = 0; + + rc = cifs_calculate_signature(cifs_pdu, mac_key, + what_we_think_sig_should_be); + + if(rc) + return rc; + + +/* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */ + + if(memcmp(server_response_sig, what_we_think_sig_should_be, 8)) + return -EACCES; + else + return 0; + +} + +/* We fill in key by putting in 40 byte array which was allocated by caller */ +int cifs_calculate_mac_key(char * key, const char * rn, const char * password) +{ + char temp_key[16]; + if ((key == NULL) || (rn == NULL)) + return -EINVAL; + + E_md4hash(password, temp_key); + mdfour(key,temp_key,16); + memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE); + return 0; +} + +int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info) +{ + char temp_hash[16]; + struct HMACMD5Context ctx; + char * ucase_buf; + wchar_t * unicode_buf; + unsigned int i,user_name_len,dom_name_len; + + if(ses) + return -EINVAL; + + E_md4hash(ses->password, temp_hash); + + hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); + user_name_len = strlen(ses->userName); + if(user_name_len > MAX_USERNAME_SIZE) + return -EINVAL; + dom_name_len = strlen(ses->domainName); + if(dom_name_len > MAX_USERNAME_SIZE) + return -EINVAL; + + ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); + unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); + + for(i=0;icharset2upper[(int)ses->userName[i]]; + ucase_buf[i] = 0; + user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); + unicode_buf[user_name_len] = 0; + user_name_len++; + + for(i=0;icharset2upper[(int)ses->domainName[i]]; + ucase_buf[i] = 0; + dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); + + unicode_buf[user_name_len + dom_name_len] = 0; + hmac_md5_update((const unsigned char *) unicode_buf, + (user_name_len+dom_name_len)*2,&ctx); + + hmac_md5_final(ses->mac_signing_key,&ctx); + kfree(ucase_buf); + kfree(unicode_buf); + return 0; +} +void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) +{ + struct HMACMD5Context context; + memcpy(v2_session_response + 8, ses->server->cryptKey,8); + /* gen_blob(v2_session_response + 16); */ + hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context); + + hmac_md5_update(ses->server->cryptKey,8,&context); +/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ + + hmac_md5_final(v2_session_response,&context); +} diff -urN linux-2.4.27/fs/cifs/cifserr.c linux-2.4.27-cifs-1.20c/fs/cifs/cifserr.c --- linux-2.4.27/fs/cifs/cifserr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifserr.c Wed Jul 14 00:25:04 2004 @@ -0,0 +1,70 @@ +/* + * fs/cifserr.c + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include "cifsfs.h" + +int map_cifs_error(int error_class, int error_code, + int status_codes_negotiated) +{ + + + if (status_codes_negotiated) { + switch (error_code) { + default: + return EIO; + } + } else + switch (error_class) { + case SUCCESS: + return 0; + + case ERRDOS: + switch (error_code) { + case ERRbadfunc: + return EINVAL; + default: + return EIO; + } + + case ERRSRV: + switch (error_code) { + default: + return EIO; + } + + case ERRHRD: + switch (error_code) { + default: + return EIO; + } + default: + return EIO; + } + return 0; +} + +int map_smb_error(int error_class, int error_code) +{ + return map_cifs_error(error_class, error_code, FALSE); +} diff -urN linux-2.4.27/fs/cifs/cifsfs.c linux-2.4.27-cifs-1.20c/fs/cifs/cifsfs.c --- linux-2.4.27/fs/cifs/cifsfs.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifsfs.c Wed Jul 14 00:25:04 2004 @@ -0,0 +1,769 @@ +/* + * fs/cifs/cifsfs.c + * + * Copyright (C) International Business Machines Corp., 2002,2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * Common Internet FileSystem (CIFS) client + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Note that BB means BUGBUG (ie something to fix eventually) */ + +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) +#include +#endif +#include +#include "cifsfs.h" +#include "cifspdu.h" +#define DECLARE_GLOBALS_HERE +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" +#include +#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ +/* BB when mempool_resize is added back in, we will resize pool on new mount */ +#define CIFS_MIN_RCV_POOL 11 /* enough for progress to five servers */ + +#ifdef CONFIG_CIFS_QUOTA +static struct quotactl_ops cifs_quotactl_ops; +#endif + +extern struct file_system_type cifs_fs_type; + +int cifsFYI = 0; +int cifsERROR = 1; +int traceSMB = 0; +unsigned int oplockEnabled = 1; +unsigned int quotaEnabled = 0; +unsigned int linuxExtEnabled = 1; +unsigned int lookupCacheEnabled = 1; +unsigned int multiuser_mount = 0; +unsigned int extended_security = 0; +unsigned int ntlmv2_support = 0; +unsigned int sign_CIFS_PDUs = 1; +unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE; +struct task_struct * oplockThread = NULL; + +extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, + const char *); +extern int cifs_umount(struct super_block *, struct cifs_sb_info *); +void cifs_proc_init(void); +void cifs_proc_clean(void); + +static DECLARE_COMPLETION(cifs_oplock_exited); + + +struct super_block * +cifs_read_super(struct super_block *sb, void *data, int silent) +{ + struct inode *inode; + struct cifs_sb_info *cifs_sb; + int rc = 0; + + sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */ + cifs_sb = CIFS_SB(sb); + if(cifs_sb == NULL) + return 0; + else + memset(cifs_sb,0,sizeof(struct cifs_sb_info)); + + + rc = cifs_mount(sb, cifs_sb, data, NULL); + + if (rc) { + if (!silent) + cERROR(1, + ("cifs_mount failed w/return code = %d", rc)); + goto out_mount_failed; + } + + sb->s_magic = CIFS_MAGIC_NUMBER; + sb->s_op = &cifs_super_ops; +/* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) + sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ +#ifdef CONFIG_CIFS_QUOTA + sb->s_qcop = &cifs_quotactl_ops; +#endif + sb->s_blocksize = CIFS_MAX_MSGSIZE; + sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ + inode = iget(sb, ROOT_I); + + if (!inode) { + goto out_no_root; + } + + sb->s_root = d_alloc_root(inode); + + if (!sb->s_root) { + goto out_no_root; + } + + return sb; + +out_no_root: + cERROR(1, ("cifs_read_super: get root inode failed")); + if (inode) + iput(inode); + +out_mount_failed: + if(cifs_sb->local_nls) + unload_nls(cifs_sb->local_nls); + sb->s_dev = 0; + return 0; +} + +static void +cifs_put_super(struct super_block *sb) +{ + int rc = 0; + struct cifs_sb_info *cifs_sb; + + cFYI(1, ("In cifs_put_super")); + cifs_sb = CIFS_SB(sb); + if(cifs_sb == NULL) { + cFYI(1,("Empty cifs superblock info passed to unmount")); + return; + } + rc = cifs_umount(sb, cifs_sb); + if (rc) { + cERROR(1, ("cifs_umount failed with return code %d", rc)); + } + unload_nls(cifs_sb->local_nls); + return; +} + +static int +cifs_statfs(struct super_block *sb, struct statfs *buf) +{ + int xid, rc; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + + xid = GetXid(); + + cifs_sb = CIFS_SB(sb); + pTcon = cifs_sb->tcon; + + buf->f_type = CIFS_MAGIC_NUMBER; + + /* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */ + buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would presumably + be length of total path, note that some servers may be + able to support more than this, but best to be safe + since Win2k and others can not handle very long filenames */ + buf->f_files = 0; /* undefined */ + buf->f_ffree = 0; /* unlimited */ + + rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls); + + /* + int f_type; + __fsid_t f_fsid; + int f_namelen; */ + /* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */ + FreeXid(xid); + return 0; /* always return success? what if volume is no longer available? */ +} + +static int cifs_permission(struct inode * inode, int mask) +{ + /* the server does permission checks, we do not need to do it here */ + return 0; +} + +kmem_cache_t *cifs_req_cachep; +kmem_cache_t *cifs_mid_cachep; +kmem_cache_t *cifs_oplock_cachep; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +static struct inode * +cifs_alloc_inode(struct super_block *sb) +{ + struct cifsInodeInfo *cifs_inode; + cifs_inode = + (struct cifsInodeInfo *) kmem_cache_alloc(cifs_inode_cachep, + SLAB_KERNEL); + if (!cifs_inode) + return NULL; + cifs_inode->cifsAttrs = 0x20; /* default */ + atomic_set(&cifs_inode->inUse, 0); + cifs_inode->time = 0; + /* Until the file is open and we have gotten oplock + info back from the server, can not assume caching of + file data or metadata */ + cifs_inode->clientCanCacheRead = FALSE; + cifs_inode->clientCanCacheAll = FALSE; + INIT_LIST_HEAD(&cifs_inode->openFileList); + return &cifs_inode->vfs_inode; +} + +static void +cifs_destroy_inode(struct inode *inode) +{ + kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); +} +#endif + +/* + * cifs_show_options() is for displaying mount options in /proc/mounts. + * Not all settable options are displayed but most of the important + * ones are. + */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) +static int +cifs_show_options(struct seq_file *s, struct vfsmount *m) +{ + struct cifs_sb_info *cifs_sb; + + cifs_sb = CIFS_SB(m->mnt_sb); + + if (cifs_sb) { + if (cifs_sb->tcon) { + seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); + if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->userName)) + seq_printf(s, ",username=%s", + cifs_sb->tcon->ses->userName); + if(cifs_sb->tcon->ses->domainName) + seq_printf(s, ",domain=%s", + cifs_sb->tcon->ses->domainName); + } + seq_printf(s, ",rsize=%d",cifs_sb->rsize); + seq_printf(s, ",wsize=%d",cifs_sb->wsize); + } + return 0; +} +#endif + +#ifdef CONFIG_CIFS_QUOTA +int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid, + struct fs_disk_quota * pdquota) +{ + int xid; + int rc = 0; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifsTconInfo *pTcon; + + if(cifs_sb) + pTcon = cifs_sb->tcon; + else + return -EIO; + + + xid = GetXid(); + if(pTcon) { + cFYI(1,("set type: 0x%x id: %d",quota_type,qid)); + } else { + return -EIO; + } + + FreeXid(xid); + return rc; +} + +int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid, + struct fs_disk_quota * pdquota) +{ + int xid; + int rc = 0; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifsTconInfo *pTcon; + + if(cifs_sb) + pTcon = cifs_sb->tcon; + else + return -EIO; + + xid = GetXid(); + if(pTcon) { + cFYI(1,("set type: 0x%x id: %d",quota_type,qid)); + } else { + rc = -EIO; + } + + FreeXid(xid); + return rc; +} + +int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation) +{ + int xid; + int rc = 0; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifsTconInfo *pTcon; + + if(cifs_sb) + pTcon = cifs_sb->tcon; + else + return -EIO; + + xid = GetXid(); + if(pTcon) { + cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation)); + } else { + rc = -EIO; + } + + FreeXid(xid); + return rc; +} + +int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats) +{ + int xid; + int rc = 0; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifsTconInfo *pTcon; + + if(cifs_sb) { + pTcon = cifs_sb->tcon; + } else { + return -EIO; + } + xid = GetXid(); + if(pTcon) { + cFYI(1,("pqstats %p",qstats)); + } else { + rc = -EIO; + } + + FreeXid(xid); + return rc; +} + +static struct quotactl_ops cifs_quotactl_ops = { + .set_xquota = cifs_xquota_set, + .get_xquota = cifs_xquota_set, + .set_xstate = cifs_xstate_set, + .get_xstate = cifs_xstate_get, +}; +#endif + +static int cifs_remount(struct super_block *sb, int *flags, char *data) +{ + *flags |= MS_NODIRATIME; + return 0; +} + +struct super_operations cifs_super_ops = { + .read_inode = cifs_read_inode, + .put_super = cifs_put_super, + .statfs = cifs_statfs, +/* .alloc_inode = cifs_alloc_inode, + .destroy_inode = cifs_destroy_inode, */ +/* .drop_inode = generic_delete_inode, + .delete_inode = cifs_delete_inode, *//* Do not need the above two functions + unless later we add lazy close of inodes or unless the kernel forgets to call + us with the same number of releases (closes) as opens */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) + .show_options = cifs_show_options, +#endif +/* .umount_begin = cifs_umount_begin, *//* consider adding in the future */ +}; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +static struct super_block * +cifs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + int rc; + struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL); + + cFYI(1, ("Devname: %s flags: %d ", dev_name, flags)); + + if (IS_ERR(sb)) + return sb; + + sb->s_flags = flags; + + rc = cifs_read_super(sb, data, dev_name, flags & MS_VERBOSE ? 1 : 0); + if (rc) { + up_write(&sb->s_umount); + deactivate_super(sb); + return ERR_PTR(rc); + } + sb->s_flags |= MS_ACTIVE; + return sb; +} +#endif + +static ssize_t +cifs_read_wrapper(struct file * file, char *read_data, size_t read_size, + loff_t * poffset) +{ + if(file == NULL) + return -EIO; + else if(file->f_dentry == NULL) + return -EIO; + else if(file->f_dentry->d_inode == NULL) + return -EIO; + + if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) { + return generic_file_read(file,read_data,read_size,poffset); + } else { + /* BB do we need to lock inode from here until after invalidate? */ +/* if(file->f_dentry->d_inode->i_mapping) { + filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); + filemap_fdatawait(file->f_dentry->d_inode->i_mapping); + }*/ +/* cifs_revalidate(file->f_dentry);*/ /* BB fixme */ + + /* BB we should make timer configurable - perhaps + by simply calling cifs_revalidate here */ + /* invalidate_remote_inode(file->f_dentry->d_inode);*/ + return generic_file_read(file,read_data,read_size,poffset); + } +} + +static ssize_t +cifs_write_wrapper(struct file * file, const char *write_data, + size_t write_size, loff_t * poffset) +{ + ssize_t written; + + if(file == NULL) + return -EIO; + else if(file->f_dentry == NULL) + return -EIO; + else if(file->f_dentry->d_inode == NULL) + return -EIO; + + /* check whether we can cache writes locally */ + written = generic_file_write(file,write_data,write_size,poffset); + if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) { + if(file->f_dentry->d_inode->i_mapping) { + filemap_fdatasync(file->f_dentry->d_inode->i_mapping); + } + } + return written; +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +static struct file_system_type cifs_fs_type = { + .owner = THIS_MODULE, + .name = "cifs", + .get_sb = cifs_get_sb, + .kill_sb = kill_anon_super, + /* .fs_flags */ +}; +#endif + +static DECLARE_FSTYPE(cifs_fs_type, "cifs", cifs_read_super,0); + + +struct inode_operations cifs_dir_inode_ops = { + .create = cifs_create, + .lookup = cifs_lookup, + .unlink = cifs_unlink, + .link = cifs_hardlink, + .mkdir = cifs_mkdir, + .rmdir = cifs_rmdir, + .rename = cifs_rename, + .permission = cifs_permission, + .revalidate = cifs_revalidate, + .setattr = cifs_setattr, + .symlink = cifs_symlink, + .mknod = cifs_mknod, +}; + +struct inode_operations cifs_file_inode_ops = { + .revalidate = cifs_revalidate, + .setattr = cifs_setattr, +/* .getattr = cifs_getattr,*/ + .rename = cifs_rename, + .permission = cifs_permission, +#ifdef CONFIG_CIFS_XATTR + .setxattr = cifs_setxattr, + .getxattr = cifs_getxattr, + .listxattr = cifs_listxattr, + .removexattr = cifs_removexattr, +#endif +}; + +struct inode_operations cifs_symlink_inode_ops = { + .readlink = cifs_readlink, + .follow_link = cifs_follow_link, + .permission = cifs_permission, + /* BB add the following two eventually */ + /* revalidate: cifs_revalidate, + setattr: cifs_notify_change, *//* BB do we need notify change */ +#ifdef CONFIG_CIFS_XATTR + .setxattr = cifs_setxattr, + .getxattr = cifs_getxattr, + .listxattr = cifs_listxattr, + .removexattr = cifs_removexattr, +#endif +}; + +struct file_operations cifs_file_ops = { + .read = cifs_read_wrapper, + .write = cifs_write_wrapper, + .open = cifs_open, + .release = cifs_close, + .lock = cifs_lock, + .fsync = cifs_fsync, + .flush = cifs_flush, + .mmap = cifs_file_mmap, +/* .sendfile = generic_file_sendfile,*/ +#ifdef CONFIG_CIFS_FCNTL + .fcntl = cifs_fcntl, +#endif +}; + +struct file_operations cifs_dir_ops = { + .readdir = cifs_readdir, + .release = cifs_closedir, + .read = generic_read_dir, +#ifdef CONFIG_CIFS_FCNTL + .fcntl = cifs_fcntl, +#endif +}; +/* +static void +cifs_init_once(void *inode, kmem_cache_t * cachep, unsigned long flags) +{ + struct cifsInodeInfo *cifsi = (struct cifsInodeInfo *) inode; + + if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) { + inode_init_once(&cifsi->vfs_inode); + INIT_LIST_HEAD(&cifsi->lockList); + } +} + +static int +cifs_init_inodecache(void) +{ + cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", + sizeof (struct cifsInodeInfo), + 0, SLAB_HWCACHE_ALIGN, + cifs_init_once, NULL); + if (cifs_inode_cachep == NULL) + return -ENOMEM; + + + return 0; +} + +static void +cifs_destroy_inodecache(void) +{ + if (kmem_cache_destroy(cifs_inode_cachep)) + printk(KERN_WARNING "cifs_inode_cache: error freeing\n"); +} */ + +static int +cifs_init_request_bufs(void) +{ + cifs_req_cachep = kmem_cache_create("cifs_request", + CIFS_MAX_MSGSIZE + + MAX_CIFS_HDR_SIZE, 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (cifs_req_cachep == NULL) + return -ENOMEM; + + return 0; +} + +static void +cifs_destroy_request_bufs(void) +{ + if (kmem_cache_destroy(cifs_req_cachep)) + printk(KERN_WARNING + "cifs_destroy_request_cache: error not all structures were freed\n"); +} + +static int +cifs_init_mids(void) +{ + cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", + sizeof (struct mid_q_entry), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (cifs_mid_cachep == NULL) + return -ENOMEM; + cifs_oplock_cachep = kmem_cache_create("cifs_oplock_struct", + sizeof (struct oplock_q_entry), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (cifs_oplock_cachep == NULL) { + kmem_cache_destroy(cifs_mid_cachep); + return -ENOMEM; + } + + return 0; +} + +static void +cifs_destroy_mids(void) +{ + if (kmem_cache_destroy(cifs_mid_cachep)) + printk(KERN_WARNING + "cifs_destroy_mids: error not all structures were freed\n"); + if (kmem_cache_destroy(cifs_oplock_cachep)) + printk(KERN_WARNING + "error not all oplock structures were freed\n"); +} + +static int cifs_oplock_thread(void * dummyarg) +{ + struct oplock_q_entry * oplock_item; + struct cifsTconInfo *pTcon; + struct inode * inode; + __u16 netfid; + int rc = 0; + + daemonize(); + sprintf(current->comm,"cifsoplockd"); + + oplockThread = current; + do { + set_current_state(TASK_INTERRUPTIBLE); + + schedule_timeout(1*HZ); + spin_lock(&GlobalMid_Lock); + if(list_empty(&GlobalOplock_Q)) { + spin_unlock(&GlobalMid_Lock); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(39*HZ); + } else { + oplock_item = list_entry(GlobalOplock_Q.next, + struct oplock_q_entry, qhead); + if(oplock_item) { + cFYI(1,("found oplock item to write out")); + pTcon = oplock_item->tcon; + inode = oplock_item->pinode; + netfid = oplock_item->netfid; + spin_unlock(&GlobalMid_Lock); + DeleteOplockQEntry(oplock_item); + /* can not grab inode sem here since it would + deadlock when oplock received on delete + since vfs_unlink holds the i_sem across + the call */ + /* down(&inode->i_sem);*/ + if (S_ISREG(inode->i_mode)) { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) + rc = filemap_fdatasync(inode->i_mapping); + if(rc) + CIFS_I(inode)->write_behind_rc = rc; +#else + filemap_fdatasync(inode->i_mapping); +#endif + if(CIFS_I(inode)->clientCanCacheRead == 0) + invalidate_inode_pages(inode); + } else + rc = 0; + /* releasing a stale oplock after recent reconnection + of smb session using a now incorrect file + handle is not a data integrity issue but do + not bother sending an oplock release if session + to server still is disconnected since oplock + already released by the server in that case */ + if(pTcon->tidStatus != CifsNeedReconnect) { + rc = CIFSSMBLock(0, pTcon, + netfid, + 0 /* len */ , 0 /* offset */, 0, + 0, LOCKING_ANDX_OPLOCK_RELEASE, + 0 /* wait flag */); + cFYI(1,("Oplock release rc = %d ",rc)); + } + } else + spin_unlock(&GlobalMid_Lock); + } + } while(!signal_pending(current)); + complete_and_exit (&cifs_oplock_exited, 0); +} + +static int __init +init_cifs(void) +{ + int rc = 0; +#if CONFIG_PROC_FS + cifs_proc_init(); +#endif + INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */ + INIT_LIST_HEAD(&GlobalSMBSessionList); + INIT_LIST_HEAD(&GlobalTreeConnectionList); + INIT_LIST_HEAD(&GlobalOplock_Q); +/* + * Initialize Global counters + */ + atomic_set(&sesInfoAllocCount, 0); + atomic_set(&tconInfoAllocCount, 0); + atomic_set(&tcpSesReconnectCount, 0); + atomic_set(&tconInfoReconnectCount, 0); + + atomic_set(&bufAllocCount, 0); + atomic_set(&midCount, 0); + GlobalCurrentXid = 0; + GlobalTotalActiveXid = 0; + GlobalMaxActiveXid = 0; + GlobalSMBSeslock = RW_LOCK_UNLOCKED; + GlobalMid_Lock = SPIN_LOCK_UNLOCKED; + +/* rc = cifs_init_inodecache();*/ + if (!rc) { + rc = cifs_init_mids(); + if (!rc) { + rc = cifs_init_request_bufs(); + if (!rc) { + rc = register_filesystem(&cifs_fs_type); + if (!rc) { + kernel_thread(cifs_oplock_thread, NULL, + CLONE_FS | CLONE_FILES | CLONE_VM); + return rc; /* Success */ + } else + cifs_destroy_request_bufs(); + } + cifs_destroy_mids(); + } +/* cifs_destroy_inodecache(); */ + } +#if CONFIG_PROC_FS + cifs_proc_clean(); +#endif + return rc; +} + +static void __exit +exit_cifs(void) +{ + cFYI(0, ("In unregister ie exit_cifs")); +#if CONFIG_PROC_FS + cifs_proc_clean(); +#endif + unregister_filesystem(&cifs_fs_type); +/* cifs_destroy_inodecache();*/ + cifs_destroy_mids(); + cifs_destroy_request_bufs(); + if(oplockThread) { + send_sig(SIGTERM, oplockThread, 1); + wait_for_completion(&cifs_oplock_exited); + } +} + +MODULE_AUTHOR("Steve French "); +MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ +MODULE_DESCRIPTION + ("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows"); +module_init(init_cifs) +module_exit(exit_cifs) diff -urN linux-2.4.27/fs/cifs/cifsfs.h linux-2.4.27-cifs-1.20c/fs/cifs/cifsfs.h --- linux-2.4.27/fs/cifs/cifsfs.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifsfs.h Wed Jul 14 00:25:04 2004 @@ -0,0 +1,97 @@ +/* + * fs/cifs/cifsfs.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CIFSFS_H +#define _CIFSFS_H + +#define ROOT_I 2 + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +extern int map_cifs_error(int error_class, int error_code, + int status_codes_negotiated); + +extern struct address_space_operations cifs_addr_ops; + +/* Functions related to super block operations */ +extern struct super_operations cifs_super_ops; +extern void cifs_put_inode(struct inode *); +extern void cifs_read_inode(struct inode *); +extern void cifs_delete_inode(struct inode *); +/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */ + +/* Functions related to inodes */ +extern struct inode_operations cifs_dir_inode_ops; +extern int cifs_create(struct inode *, struct dentry *, int); +extern struct dentry *cifs_lookup(struct inode *, struct dentry *); +extern int cifs_unlink(struct inode *, struct dentry *); +extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); +extern int cifs_mknod(struct inode *, struct dentry *, int, int); +extern int cifs_mkdir(struct inode *, struct dentry *, int); +extern int cifs_rmdir(struct inode *, struct dentry *); +extern int cifs_rename(struct inode *, struct dentry *, struct inode *, + struct dentry *); +extern int cifs_revalidate(struct dentry *); +extern int cifs_setattr(struct dentry *, struct iattr *); + +extern struct inode_operations cifs_file_inode_ops; +extern void cifs_truncate_file(struct inode *); +extern struct inode_operations cifs_symlink_inode_ops; + +/* Functions related to files and directories */ +extern struct file_operations cifs_file_ops; +extern int cifs_open(struct inode *inode, struct file *file); +extern int cifs_close(struct inode *inode, struct file *file); +extern int cifs_closedir(struct inode *inode, struct file *file); +extern ssize_t cifs_read(struct file *file, char *read_data, + size_t read_size, loff_t * poffset); +extern ssize_t cifs_write(struct file *file, const char *write_data, + size_t write_size, loff_t * poffset); +extern int cifs_lock(struct file *, int, struct file_lock *); +extern int cifs_fsync(struct file *, struct dentry *, int); +extern int cifs_flush(struct file *); +extern int cifs_file_mmap(struct file * , struct vm_area_struct *); +extern struct file_operations cifs_dir_ops; +extern int cifs_dir_open(struct inode *inode, struct file *file); +extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); +extern long cifs_fcntl(int, unsigned int, unsigned long, struct file *); + +/* Functions related to dir entries */ +extern struct dentry_operations cifs_dentry_ops; + +/* Functions related to symlinks */ +extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd); +extern int cifs_readlink(struct dentry *direntry, char *buffer, int buflen); +extern int cifs_symlink(struct inode *inode, struct dentry *direntry, + const char *symname); +extern int cifs_removexattr(struct dentry *, const char *); +extern int cifs_setxattr(struct dentry *, const char *, const void *, + size_t, int); +extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); +extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); +#define CIFS_VERSION "1.20" +#endif /* _CIFSFS_H */ diff -urN linux-2.4.27/fs/cifs/cifsglob.h linux-2.4.27-cifs-1.20c/fs/cifs/cifsglob.h --- linux-2.4.27/fs/cifs/cifsglob.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifsglob.h Wed Jul 14 00:25:05 2004 @@ -0,0 +1,413 @@ +/* + * fs/cifs/cifsglob.h + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + */ +#include +#include +#include "cifs_fs_sb.h" +/* + * The sizes of various internal tables and strings + */ +#define MAX_UID_INFO 16 +#define MAX_SES_INFO 2 +#define MAX_TCON_INFO 4 + +#define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1 +#define MAX_SERVER_SIZE 15 +#define MAX_SHARE_SIZE 64 /* used to be 20 - this should still be enough */ +#define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null + termination then *2 for unicode versions */ +#define MAX_PASSWORD_SIZE 16 + +/* + * MAX_REQ is the maximum number of requests that WE will send + * on one socket concurently. It also matches the most common + * value of max multiplex returned by servers. We may + * eventually want to use the negotiated value (in case + * future servers can handle more) when we are more confident that + * we will not have problems oveloading the socket with pending + * write data. + */ +#define CIFS_MAX_REQ 50 + +#define SERVER_NAME_LENGTH 15 +#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) + +/* used to define string lengths for reversing unicode strings */ +/* (256+1)*2 = 514 */ +/* (max path length + 1 for null) * 2 for unicode */ +#define MAX_NAME 514 + +#include "cifspdu.h" + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef XATTR_DOS_ATTRIB +#define XATTR_DOS_ATTRIB "user.DOSATTRIB" +#endif + +/* + * This information is kept on every Server we know about. + * + * Some things to note: + * + */ +#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) + +/* + * CIFS vfs client Status information (based on what we know.) + */ + + /* associated with each tcp and smb session */ +enum statusEnum { + CifsNew = 0, + CifsGood, + CifsExiting, + CifsNeedReconnect +}; + +enum securityEnum { + NTLM = 0, /* Legacy NTLM012 auth with NTLM hash */ + NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ + RawNTLMSSP, /* NTLMSSP without SPNEGO */ + NTLMSSP, /* NTLMSSP via SPNEGO */ + Kerberos /* Kerberos via SPNEGO */ +}; + +enum protocolEnum { + IPV4 = 0, + IPV6, + SCTP + /* Netbios frames protocol not supported at this time */ +}; + +/* + ***************************************************************** + * Except the CIFS PDUs themselves all the + * globally interesting structs should go here + ***************************************************************** + */ + +struct TCP_Server_Info { + char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */ + char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */ + struct socket *ssocket; + union { + struct sockaddr_in sockAddr; + struct sockaddr_in6 sockAddr6; + } addr; + wait_queue_head_t response_q; + wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ + struct list_head pending_mid_q; + void *Server_NlsInfo; /* BB - placeholder for future NLS info */ + unsigned short server_codepage; /* codepage for the server */ + unsigned long ip_address; /* IP addr for the server if known */ + enum protocolEnum protocolType; + char versionMajor; + char versionMinor; + int svlocal:1; /* local server or remote */ + atomic_t socketUseCount; /* number of open cifs sessions on socket */ + atomic_t inFlight; /* number of requests on the wire to server */ + enum statusEnum tcpStatus; /* what we think the status is */ + struct semaphore tcpSem; + struct task_struct *tsk; + char server_GUID[16]; + char secMode; + enum securityEnum secType; + unsigned int maxReq; /* Clients should submit no more */ + /* than maxReq distinct unanswered SMBs to the server when using */ + /* multiplexed reads or writes */ + unsigned int maxBuf; /* maxBuf specifies the maximum */ + /* message size the server can send or receive for non-raw SMBs */ + unsigned int maxRw; /* maxRw specifies the maximum */ + /* message size the server can send or receive for */ + /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */ + char sessid[4]; /* unique token id for this session */ + /* (returned on Negotiate */ + int capabilities; /* allow selective disabling of caps by smb sess */ + __u16 timeZone; + char cryptKey[CIFS_CRYPTO_KEY_SIZE]; + char workstation_RFC1001_name[16]; /* 16th byte is always zero */ +}; + +/* + * The following is our shortcut to user information. We surface the uid, + * and name. We always get the password on the fly in case it + * has changed. We also hang a list of sessions owned by this user off here. + */ +struct cifsUidInfo { + struct list_head userList; + struct list_head sessionList; /* SMB sessions for this user */ + uid_t linux_uid; + char user[MAX_USERNAME_SIZE + 1]; /* ascii name of user */ + /* BB may need ptr or callback for PAM or WinBind info */ +}; + +/* + * Session structure. One of these for each uid session with a particular host + */ +struct cifsSesInfo { + struct list_head cifsSessionList; + struct semaphore sesSem; + struct cifsUidInfo *uidInfo; /* pointer to user info */ + struct TCP_Server_Info *server; /* pointer to server info */ + atomic_t inUse; /* # of mounts (tree connections) on this ses */ + enum statusEnum status; + __u32 sequence_number; /* needed for CIFS PDU signature */ + __u16 ipc_tid; /* special tid for connection to IPC share */ + char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; + char *serverOS; /* name of operating system underlying the server */ + char *serverNOS; /* name of network operating system that the server is running */ + char *serverDomain; /* security realm of server */ + int Suid; /* remote smb uid */ + uid_t linux_uid; /* local Linux uid */ + int capabilities; + char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ + char userName[MAX_USERNAME_SIZE + 1]; + char domainName[MAX_USERNAME_SIZE + 1]; + char * password; +}; + +/* + * there is one of these for each connection to a resource on a particular + * session + */ +struct cifsTconInfo { + struct list_head cifsConnectionList; + struct list_head openFileList; + struct semaphore tconSem; + struct cifsSesInfo *ses; /* pointer to session associated with */ + char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */ + char *nativeFileSystem; + __u16 tid; /* The 2 byte tree id */ + __u16 Flags; /* optional support bits */ + enum statusEnum tidStatus; + atomic_t useCount; /* how many mounts (explicit or implicit) to this share */ +#ifdef CONFIG_CIFS_STATS + atomic_t num_smbs_sent; + atomic_t num_writes; + atomic_t num_reads; + atomic_t num_oplock_brks; + atomic_t num_opens; + atomic_t num_deletes; + atomic_t num_mkdirs; + atomic_t num_rmdirs; + atomic_t num_renames; + atomic_t num_t2renames; + __u64 bytes_read; + __u64 bytes_written; + spinlock_t stat_lock; +#endif + FILE_SYSTEM_DEVICE_INFO fsDevInfo; + FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ + FILE_SYSTEM_UNIX_INFO fsUnixInfo; + int retry:1; + /* BB add field for back pointer to sb struct? */ +}; + +/* + * This info hangs off the cifsFileInfo structure. This is used to track + * byte stream locks on the file + */ +struct cifsLockInfo { + struct cifsLockInfo *next; + int start; + int length; + int type; +}; + +/* + * One of these for each open instance of a file + */ +struct cifsFileInfo { + struct list_head tlist; /* pointer to next fid owned by tcon */ + struct list_head flist; /* next fid (file instance) for this inode */ + unsigned int uid; /* allows finding which FileInfo structure */ + __u32 pid; /* process id who opened file */ + __u16 netfid; /* file id from remote */ + /* BB add lock scope info here if needed */ ; + /* lock scope id (0 if none) */ + struct file * pfile; /* needed for writepage */ + struct inode * pInode; /* needed for oplock break */ + int endOfSearch:1; /* we have reached end of search */ + int closePend:1; /* file is marked to close */ + int emptyDir:1; + int invalidHandle:1; /* file closed via session abend */ + struct semaphore fh_sem; /* prevents reopen race after dead ses*/ + char * search_resume_name; + unsigned int resume_name_length; + __u32 resume_key; +}; + +/* + * One of these for each file inode + */ + +struct cifsInodeInfo { + struct list_head lockList; + /* BB add in lists for dirty pages - i.e. write caching info for oplock */ + struct list_head openFileList; + int write_behind_rc; + __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ + atomic_t inUse; /* num concurrent users (local openers cifs) of file*/ + unsigned long time; /* jiffies of last update/check of inode */ + int clientCanCacheRead:1; /* read oplock */ + int clientCanCacheAll:1; /* read and writebehind oplock */ + int oplockPending:1; + struct inode vfs_inode; +}; + +static inline struct cifsInodeInfo * CIFS_I(struct inode *inode) +{ + return (struct cifsInodeInfo *)&(inode->u); +} + +static inline struct cifs_sb_info * CIFS_SB(struct super_block *sb) +{ + return (struct cifs_sb_info *) &(sb->u); +} + + +/* one of these for every pending CIFS request to the server */ +struct mid_q_entry { + struct list_head qhead; /* mids waiting on reply from this server */ + __u16 mid; /* multiplex id */ + __u16 pid; /* process id */ + __u32 sequence_number; /* for CIFS signing */ + __u16 command; /* smb command code */ + struct timeval when_sent; /* time when smb sent */ + struct cifsSesInfo *ses; /* smb was sent to this server */ + struct task_struct *tsk; /* task waiting for response */ + struct smb_hdr *resp_buf; /* response buffer */ + int midState; /* wish this were enum but can not pass to wait_event */ +}; + +struct oplock_q_entry { + struct list_head qhead; + struct inode * pinode; + struct cifsTconInfo * tcon; + __u16 netfid; +}; + +#define MID_FREE 0 +#define MID_REQUEST_ALLOCATED 1 +#define MID_REQUEST_SUBMITTED 2 +#define MID_RESPONSE_RECEIVED 4 +#define MID_RETRY_NEEDED 8 /* session closed while this request out */ + +/* + ***************************************************************** + * All constants go here + ***************************************************************** + */ + +#define UID_HASH (16) + +/* + * Note that ONE module should define _DECLARE_GLOBALS_HERE to cause the + * following to be declared. + */ + +/**************************************************************************** + * Locking notes. All updates to global variables and lists should be + * protected by spinlocks or semaphores. + * + * Spinlocks + * --------- + * GlobalMid_Lock protects: + * list operations on pending_mid_q and oplockQ + * updates to XID counters, multiplex id and SMB sequence numbers + * GlobalSMBSesLock protects: + * list operations on tcp and SMB session lists and tCon lists + * f_owner.lock protects certain per file struct operations + * mapping->page_lock protects certain per page operations + * + * Semaphores + * ---------- + * sesSem operations on smb session + * tconSem operations on tree connection + * fh_sem file handle reconnection operations + * + ****************************************************************************/ + +#ifdef DECLARE_GLOBALS_HERE +#define GLOBAL_EXTERN +#else +#define GLOBAL_EXTERN extern +#endif + +/* + * The list of servers that did not respond with NT LM 0.12. + * This list helps improve performance and eliminate the messages indicating + * that we had a communications error talking to the server in this list. + */ +GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */ + +/* + * The following is a hash table of all the users we know about. + */ +GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH]; + +GLOBAL_EXTERN struct list_head GlobalServerList; /* BB not implemented yet */ +GLOBAL_EXTERN struct list_head GlobalSMBSessionList; +GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; +GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ + +GLOBAL_EXTERN struct list_head GlobalOplock_Q; + +/* + * Global transaction id (XID) information + */ +GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ +GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ +GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ +GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */ + /* on midQ entries */ +GLOBAL_EXTERN char Local_System_Name[15]; + +/* + * Global counters, updated atomically + */ +GLOBAL_EXTERN atomic_t sesInfoAllocCount; +GLOBAL_EXTERN atomic_t tconInfoAllocCount; + +GLOBAL_EXTERN atomic_t tcpSesReconnectCount; +GLOBAL_EXTERN atomic_t tconInfoReconnectCount; + +/* Various Debug counters to remove someday (BB) */ +GLOBAL_EXTERN atomic_t bufAllocCount; +GLOBAL_EXTERN atomic_t midCount; + +/* Misc globals */ +GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions + to be established on existing mount if we + have the uid/password or Kerberos credential + or equivalent for current user */ +GLOBAL_EXTERN unsigned int oplockEnabled; +GLOBAL_EXTERN unsigned int quotaEnabled; +GLOBAL_EXTERN unsigned int lookupCacheEnabled; +GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent + with more secure ntlmssp2 challenge/resp */ +GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ +GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ +GLOBAL_EXTERN unsigned int linuxExtEnabled; /* enable Linux/Unix CIFS extensions */ + diff -urN linux-2.4.27/fs/cifs/cifspdu.h linux-2.4.27-cifs-1.20c/fs/cifs/cifspdu.h --- linux-2.4.27/fs/cifs/cifspdu.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifspdu.h Wed Jul 14 00:25:05 2004 @@ -0,0 +1,1793 @@ +/* + * fs/cifs/cifspdu.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CIFSPDU_H +#define _CIFSPDU_H + +#include + +#define CIFS_PROT 0 +#define BAD_PROT CIFS_PROT+1 + +/* SMB command codes */ +#define SMB_COM_CREATE_DIRECTORY 0x00 +#define SMB_COM_DELETE_DIRECTORY 0x01 +#define SMB_COM_CLOSE 0x04 +#define SMB_COM_DELETE 0x06 +#define SMB_COM_RENAME 0x07 +#define SMB_COM_LOCKING_ANDX 0x24 +#define SMB_COM_COPY 0x29 +#define SMB_COM_READ_ANDX 0x2E +#define SMB_COM_WRITE_ANDX 0x2F +#define SMB_COM_TRANSACTION2 0x32 +#define SMB_COM_TRANSACTION2_SECONDARY 0x33 +#define SMB_COM_FIND_CLOSE2 0x34 +#define SMB_COM_TREE_DISCONNECT 0x71 +#define SMB_COM_NEGOTIATE 0x72 +#define SMB_COM_SESSION_SETUP_ANDX 0x73 +#define SMB_COM_LOGOFF_ANDX 0x74 +#define SMB_COM_TREE_CONNECT_ANDX 0x75 +#define SMB_COM_NT_TRANSACT 0xA0 +#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 +#define SMB_COM_NT_CREATE_ANDX 0xA2 +#define SMB_COM_NT_RENAME 0xA5 + +/* Transact2 subcommand codes */ +#define TRANS2_OPEN 0x00 +#define TRANS2_FIND_FIRST 0x01 +#define TRANS2_FIND_NEXT 0x02 +#define TRANS2_QUERY_FS_INFORMATION 0x03 +#define TRANS2_QUERY_PATH_INFORMATION 0x05 +#define TRANS2_SET_PATH_INFORMATION 0x06 +#define TRANS2_QUERY_FILE_INFORMATION 0x07 +#define TRANS2_SET_FILE_INFORMATION 0x08 +#define TRANS2_GET_DFS_REFERRAL 0x10 +#define TRANS2_REPORT_DFS_INCOSISTENCY 0x11 + +/* NT Transact subcommand codes */ +#define NT_TRANSACT_CREATE 0x01 +#define NT_TRANSACT_IOCTL 0x02 +#define NT_TRANSACT_SET_SECURITY_DESC 0x03 +#define NT_TRANSACT_NOTIFY_CHANGE 0x04 +#define NT_TRANSACT_RENAME 0x05 +#define NT_TRANSACT_QUERY_SECURITY_DESC 0x06 +#define NT_TRANSACT_GET_USER_QUOTA 0x07 +#define NT_TRANSACT_SET_USER_QUOTA 0x08 + +#define MAX_CIFS_HDR_SIZE 256 /* chained NTCreateXReadX will probably be biggest */ + +/* internal cifs vfs structures */ +/***************************************************************** + * All constants go here + ***************************************************************** + */ + +/* + * Starting value for maximum SMB size negotiation + */ +#define CIFS_MAX_MSGSIZE (4*4096) + +/* + * Size of encrypted user password in bytes + */ +#define CIFS_ENCPWD_SIZE (16) + +/* + * Size of the crypto key returned on the negotiate SMB in bytes + */ +#define CIFS_CRYPTO_KEY_SIZE (8) + +/* + * Size of the session key (crypto key encrypted with the password + */ +#define CIFS_SESSION_KEY_SIZE (24) + +/* + * Maximum user name length + */ +#define CIFS_UNLEN (20) + +/* + * Flags on SMB open + */ +#define SMBOPEN_WRITE_THROUGH 0x4000 +#define SMBOPEN_DENY_ALL 0x0010 +#define SMBOPEN_DENY_WRITE 0x0020 +#define SMBOPEN_DENY_READ 0x0030 +#define SMBOPEN_DENY_NONE 0x0040 +#define SMBOPEN_READ 0x0000 +#define SMBOPEN_WRITE 0x0001 +#define SMBOPEN_READWRITE 0x0002 +#define SMBOPEN_EXECUTE 0x0003 + +#define SMBOPEN_OCREATE 0x0010 +#define SMBOPEN_OTRUNC 0x0002 +#define SMBOPEN_OAPPEND 0x0001 + +/* + * SMB flag definitions + */ +#define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock primitives */ +#define SMBFLG_RCV_POSTED 0x02 /* obsolete */ +#define SMBFLG_RSVD 0x04 +#define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off implies case sensitive file handling requested) */ +#define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */ +#define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */ +#define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */ +#define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */ + +/* + * SMB flag2 definitions + */ +#define SMBFLG2_KNOWS_LONG_NAMES 0x0001 /* can send long (non-8.3) path names in response */ +#define SMBFLG2_KNOWS_EAS 0x0002 +#define SMBFLG2_SECURITY_SIGNATURE 0x0004 +#define SMBFLG2_IS_LONG_NAME 0x0040 +#define SMBFLG2_EXT_SEC 0x0800 +#define SMBFLG2_DFS 0x1000 +#define SMBFLG2_PAGING_IO 0x2000 +#define SMBFLG2_ERR_STATUS 0x4000 +#define SMBFLG2_UNICODE 0x8000 + +/* + * These are the file access permission bits defined in CIFS for the + * NTCreateAndX as well as the level 0x107 + * TRANS2_QUERY_PATH_INFORMATION API. The level 0x107, SMB_QUERY_FILE_ALL_INFO + * responds with the AccessFlags. + * The AccessFlags specifies the access permissions a caller has to the + * file and can have any suitable combination of the following values: + */ + +#define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ +#define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ +#define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ +#define FILE_READ_EA 0x00000008 /* Extended attributes associated */ + /* with the file can be read */ +#define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ + /* with the file can be written */ +#define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ + /* the file using system paging I/O */ +#define FILE_DELETE_CHILD 0x00000040 +#define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ + /* file can be read */ +#define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ + /* file can be written */ +#define DELETE 0x00010000 /* The file can be deleted */ +#define READ_CONTROL 0x00020000 /* The access control list and */ + /* ownership associated with the */ + /* file can be read */ +#define WRITE_DAC 0x00040000 /* The access control list and */ + /* ownership associated with the */ + /* file can be written. */ +#define WRITE_OWNER 0x00080000 /* Ownership information associated */ + /* with the file can be written */ +#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ + /* synchronize with the completion */ + /* of an input/output request */ +#define GENERIC_ALL 0x10000000 +#define GENERIC_EXECUTE 0x20000000 +#define GENERIC_WRITE 0x40000000 +#define GENERIC_READ 0x80000000 + /* In summary - Relevant file */ + /* access flags from CIFS are */ + /* file_read_data, file_write_data */ + /* file_execute, file_read_attributes */ + /* write_dac, and delete. */ + +/* + * Invalid readdir handle + */ +#define CIFS_NO_HANDLE 0xFFFF + +/* IPC$ in ASCII */ +#define CIFS_IPC_RESOURCE "\x49\x50\x43\x24" + +/* IPC$ in Unicode */ +#define CIFS_IPC_UNICODE_RESOURCE "\x00\x49\x00\x50\x00\x43\x00\x24\x00\x00" + +/* Unicode Null terminate 2 bytes of 0 */ +#define UNICODE_NULL "\x00\x00" +#define ASCII_NULL 0x00 + +/* + * Server type values (returned on EnumServer API + */ +#define CIFS_SV_TYPE_DC 0x00000008 +#define CIFS_SV_TYPE_BACKDC 0x00000010 + +/* + * Alias type flags (From EnumAlias API call + */ +#define CIFS_ALIAS_TYPE_FILE 0x0001 +#define CIFS_SHARE_TYPE_FILE 0x0000 + +/* + * File Attribute flags + */ +#define ATTR_READONLY 0x0001 +#define ATTR_HIDDEN 0x0002 +#define ATTR_SYSTEM 0x0004 +#define ATTR_VOLUME 0x0008 +#define ATTR_DIRECTORY 0x0010 +#define ATTR_ARCHIVE 0x0020 +#define ATTR_DEVICE 0x0040 +#define ATTR_NORMAL 0x0080 +#define ATTR_TEMPORARY 0x0100 +#define ATTR_SPARSE 0x0200 +#define ATTR_REPARSE 0x0400 +#define ATTR_COMPRESSED 0x0800 +#define ATTR_OFFLINE 0x1000 /* ie file not immediately available - offline storage */ +#define ATTR_NOT_CONTENT_INDEXED 0x2000 +#define ATTR_ENCRYPTED 0x4000 +#define ATTR_POSIX_SEMANTICS 0x01000000 +#define ATTR_BACKUP_SEMANTICS 0x02000000 +#define ATTR_DELETE_ON_CLOSE 0x04000000 +#define ATTR_SEQUENTIAL_SCAN 0x08000000 +#define ATTR_RANDOM_ACCESS 0x10000000 +#define ATTR_NO_BUFFERING 0x20000000 +#define ATTR_WRITE_THROUGH 0x80000000 + +/* ShareAccess flags */ +#define FILE_NO_SHARE 0x00000000 +#define FILE_SHARE_READ 0x00000001 +#define FILE_SHARE_WRITE 0x00000002 +#define FILE_SHARE_DELETE 0x00000004 +#define FILE_SHARE_ALL 0x00000007 + +/* CreateDisposition flags */ +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 + +/* CreateOptions */ +#define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ +#define CREATE_WRITE_THROUGH 0x00000002 +#define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ +#define CREATE_RANDOM_ACCESS 0x00000800 +#define CREATE_DELETE_ON_CLOSE 0x00001000 +#define OPEN_REPARSE_POINT 0x00200000 + +/* ImpersonationLevel flags */ +#define SECURITY_ANONYMOUS 0 +#define SECURITY_IDENTIFICATION 1 +#define SECURITY_IMPERSONATION 2 +#define SECURITY_DELEGATION 3 + +/* SecurityFlags */ +#define SECURITY_CONTEXT_TRACKING 0x01 +#define SECURITY_EFFECTIVE_ONLY 0x02 + +/* + * Default PID value, used in all SMBs where the PID is not important + */ +#define CIFS_DFT_PID 0x1234 + +/* + * We use the same routine for Copy and Move SMBs. This flag is used to + * distinguish + */ +#define CIFS_COPY_OP 1 +#define CIFS_RENAME_OP 2 + +#define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ +#define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ + +#pragma pack(1) + +struct smb_hdr { + __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 */ + __u8 Protocol[4]; + __u8 Command; + union { + struct { + __u8 ErrorClass; + __u8 Reserved; + __u16 Error; /* note: treated as little endian (le) on wire */ + } DosError; + __u32 CifsError; /* note: le */ + } Status; + __u8 Flags; + __u16 Flags2; /* note: le */ + __u16 PidHigh; /* note: le */ + union { + struct { + __u32 SequenceNumber; /* le */ + __u32 Reserved; /* zero */ + } Sequence; + __u8 SecuritySignature[8]; /* le */ + } Signature; + __u8 pad[2]; + __u16 Tid; + __u16 Pid; /* note: le */ + __u16 Uid; + __u16 Mid; + __u8 WordCount; +}; +/* given a pointer to an smb_hdr retrieve the value of byte count */ +#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) + +/* given a pointer to an smb_hdr retrieve the pointer to the byte area */ +#define pByteArea(smb_var) ((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) + +/* + * Computer Name Length + */ +#define CNLEN 15 + +/* + * Share Name Length @S8A + * Note: This length is limited by the SMB used to get @S8A + * the Share info. NetShareEnum only returns 13 @S8A + * chars, including the null termination. @S8A + */ +#define SNLEN 12 /*@S8A */ + +/* + * Comment Length + */ +#define MAXCOMMENTLEN 40 + +/* + * The OS/2 maximum path name + */ +#define MAX_PATHCONF 256 + +/* + * SMB frame definitions (following must be packed structs) + * See the SNIA CIFS Specification for details. + * + * The Naming convention is the lower case version of the + * smb command code name for the struct and this is typedef to the + * uppercase version of the same name with the prefix SMB_ removed + * for brevity. Although typedefs are not commonly used for + * structure definitions in the Linux kernel, their use in the + * CIFS standards document, which this code is based on, may + * make this one of the cases where typedefs for structures make + * sense to improve readability for readers of the standards doc. + * Typedefs can always be removed later if they are too distracting + * and they are only used for the CIFSs PDUs themselves, not + * internal cifs vfs structures + * + */ + +typedef struct negotiate_req { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; + unsigned char DialectsArray[1]; +} NEGOTIATE_REQ; + +typedef struct negotiate_rsp { + struct smb_hdr hdr; /* wct = 17 */ + __u16 DialectIndex; + __u8 SecurityMode; + __u16 MaxMpxCount; + __u16 MaxNumberVcs; + __u32 MaxBufferSize; + __u32 MaxRawSize; + __u32 SessionKey; + __u32 Capabilities; /* see below */ + __u32 SystemTimeLow; + __u32 SystemTimeHigh; + __u16 ServerTimeZone; + __u8 EncryptionKeyLength; + __u16 ByteCount; + union { + unsigned char EncryptionKey[1]; /* if cap extended security is off */ + /* followed by Domain name - if extended security is off */ + /* followed by 16 bytes of server GUID */ + /* followed by security blob if cap_extended_security negotiated */ + struct { + unsigned char GUID[16]; + unsigned char SecurityBlob[1]; + } extended_response; + } u; +} NEGOTIATE_RSP; + +/* SecurityMode bits */ +#define SECMODE_USER 0x01 /* off indicates share level security */ +#define SECMODE_PW_ENCRYPT 0x02 +#define SECMODE_SIGN_ENABLED 0x04 /* SMB security signatures enabled */ +#define SECMODE_SIGN_REQUIRED 0x08 /* SMB security signatures required */ + +/* Negotiate response Capabilities */ +#define CAP_RAW_MODE 0x00000001 +#define CAP_MPX_MODE 0x00000002 +#define CAP_UNICODE 0x00000004 +#define CAP_LARGE_FILES 0x00000008 +#define CAP_NT_SMBS 0x00000010 /* implies CAP_NT_FIND */ +#define CAP_RPC_REMOTE_APIS 0x00000020 +#define CAP_STATUS32 0x00000040 +#define CAP_LEVEL_II_OPLOCKS 0x00000080 +#define CAP_LOCK_AND_READ 0x00000100 +#define CAP_NT_FIND 0x00000200 +#define CAP_DFS 0x00001000 +#define CAP_INFOLEVEL_PASSTHRU 0x00002000 +#define CAP_LARGE_READ_X 0x00004000 +#define CAP_LARGE_WRITE_X 0x00008000 +#define CAP_UNIX 0x00800000 +#define CAP_RESERVED 0x02000000 +#define CAP_BULK_TRANSFER 0x20000000 +#define CAP_COMPRESSED_DATA 0x40000000 +#define CAP_EXTENDED_SECURITY 0x80000000 + +typedef union smb_com_session_setup_andx { + struct { /* request format */ + struct smb_hdr hdr; /* wct = 12 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 MaxBufferSize; + __u16 MaxMpxCount; + __u16 VcNumber; + __u32 SessionKey; + __u16 SecurityBlobLength; + __u32 Reserved; + __u32 Capabilities; /* see below */ + __u16 ByteCount; + unsigned char SecurityBlob[1]; /* followed by */ + /* STRING NativeOS */ + /* STRING NativeLanMan */ + } req; /* NTLM request format (with extended security */ + + struct { /* request format */ + struct smb_hdr hdr; /* wct = 13 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 MaxBufferSize; + __u16 MaxMpxCount; + __u16 VcNumber; + __u32 SessionKey; + __u16 CaseInsensitivePasswordLength; /* ASCII password length */ + __u16 CaseSensitivePasswordLength; /* Unicode password length */ + __u32 Reserved; /* see below */ + __u32 Capabilities; + __u16 ByteCount; + unsigned char CaseInsensitivePassword[1]; /* followed by: */ + /* unsigned char * CaseSensitivePassword; */ + /* STRING AccountName */ + /* STRING PrimaryDomain */ + /* STRING NativeOS */ + /* STRING NativeLanMan */ + } req_no_secext; /* NTLM request format (without extended security */ + + struct { /* default (NTLM) response format */ + struct smb_hdr hdr; /* wct = 4 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Action; /* see below */ + __u16 SecurityBlobLength; + __u16 ByteCount; + unsigned char SecurityBlob[1]; /* followed by */ +/* unsigned char * NativeOS; */ +/* unsigned char * NativeLanMan; */ +/* unsigned char * PrimaryDomain; */ + } resp; /* NTLM response format (with or without extended security */ + + struct { /* request format */ + struct smb_hdr hdr; /* wct = 10 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 MaxBufferSize; + __u16 MaxMpxCount; + __u16 VcNumber; + __u32 SessionKey; + __u16 PassswordLength; + __u32 Reserved; + __u16 ByteCount; + unsigned char AccountPassword[1]; /* followed by */ + /* STRING AccountName */ + /* STRING PrimaryDomain */ + /* STRING NativeOS */ + /* STRING NativeLanMan */ + } old_req; /* pre-NTLM (LANMAN2.1) request format */ + + struct { /* default (NTLM) response format */ + struct smb_hdr hdr; /* wct = 3 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Action; /* see below */ + __u16 ByteCount; + unsigned char NativeOS[1]; /* followed by */ +/* unsigned char * NativeLanMan; */ +/* unsigned char * PrimaryDomain; */ + } old_resp; /* pre-NTLM (LANMAN2.1) response format */ +} SESSION_SETUP_ANDX; + +#define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" + +/* Capabilities bits (for NTLM SessSetup request) */ +#define CAP_UNICODE 0x00000004 +#define CAP_LARGE_FILES 0x00000008 +#define CAP_NT_SMBS 0x00000010 +#define CAP_STATUS32 0x00000040 +#define CAP_LEVEL_II_OPLOCKS 0x00000080 +#define CAP_NT_FIND 0x00000200 /* reserved should be zero (presumably because NT_SMBs implies the same thing) */ +#define CAP_BULK_TRANSFER 0x20000000 +#define CAP_EXTENDED_SECURITY 0x80000000 + +/* Action bits */ +#define GUEST_LOGIN 1 + +typedef struct smb_com_tconx_req { + struct smb_hdr hdr; /* wct = 4 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Flags; /* see below */ + __u16 PasswordLength; + __u16 ByteCount; + unsigned char Password[1]; /* followed by */ +/* STRING Path *//* \\server\share name */ + /* STRING Service */ +} TCONX_REQ; + +typedef struct smb_com_tconx_rsp { + struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 OptionalSupport; /* see below */ + __u16 ByteCount; + unsigned char Service[1]; /* always ASCII, not Unicode */ + /* STRING NativeFileSystem */ +} TCONX_RSP; + +/* tree connect Flags */ +#define DISCONNECT_TID 0x0001 +#define TCON_EXTENDED_SECINFO 0x0008 +/* OptionalSupport bits */ +#define SMB_SUPPORT_SEARCH_BITS 0x0001 /* must have bits (exclusive searches suppt. */ +#define SMB_SHARE_IS_IN_DFS 0x0002 + +typedef struct smb_com_logoff_andx_req { + + struct smb_hdr hdr; /* wct = 2 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 ByteCount; +} LOGOFF_ANDX_REQ; + +typedef struct smb_com_logoff_andx_rsp { + struct smb_hdr hdr; /* wct = 2 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 ByteCount; +} LOGOFF_ANDX_RSP; + +typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */ + struct { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bcc = 0 */ + } req; + struct { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bcc = 0 */ + } resp; +} TREE_DISCONNECT; + +typedef struct smb_com_close_req { + struct smb_hdr hdr; /* wct = 3 */ + __u16 FileID; + __u32 LastWriteTime; /* should be zero */ + __u16 ByteCount; /* 0 */ +} CLOSE_REQ; + +typedef struct smb_com_close_rsp { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bct = 0 */ +} CLOSE_RSP; + +typedef struct smb_com_findclose_req { + struct smb_hdr hdr; /* wct = 1 */ + __u16 FileID; + __u16 ByteCount; /* 0 */ +} FINDCLOSE_REQ; + +/* OpenFlags */ +#define REQ_OPLOCK 0x00000002 +#define REQ_BATCHOPLOCK 0x00000004 +#define REQ_OPENDIRONLY 0x00000008 + +typedef struct smb_com_open_req { /* also handles create */ + struct smb_hdr hdr; /* wct = 24 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u8 Reserved; /* Must Be Zero */ + __u16 NameLength; + __u32 OpenFlags; + __u32 RootDirectoryFid; + __u32 DesiredAccess; + __u64 AllocationSize; + __u32 FileAttributes; + __u32 ShareAccess; + __u32 CreateDisposition; + __u32 CreateOptions; + __u32 ImpersonationLevel; + __u8 SecurityFlags; + __u16 ByteCount; + char fileName[1]; +} OPEN_REQ; + +/* open response: oplock levels */ +#define OPLOCK_NONE 0 +#define OPLOCK_EXCLUSIVE 1 +#define OPLOCK_BATCH 2 +#define OPLOCK_READ 3 /* level 2 oplock */ + +/* open response for CreateAction shifted left */ +#define CIFS_CREATE_ACTION 0x20000 /* file created */ + +typedef struct smb_com_open_rsp { + struct smb_hdr hdr; /* wct = 34 BB */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u8 OplockLevel; + __u16 Fid; + __u32 CreateAction; + __u64 CreationTime; + __u64 LastAccessTime; + __u64 LastWriteTime; + __u64 ChangeTime; + __u32 FileAttributes; + __u64 AllocationSize; + __u64 EndOfFile; + __u16 FileType; + __u16 DeviceState; + __u8 DirectoryFlag; + __u16 ByteCount; /* bct = 0 */ +} OPEN_RSP; + +typedef struct smb_com_write_req { + struct smb_hdr hdr; /* wct = 14 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Fid; + __u32 OffsetLow; + __u32 Reserved; + __u16 WriteMode; + __u16 Remaining; + __u16 DataLengthHigh; + __u16 DataLengthLow; + __u16 DataOffset; + __u32 OffsetHigh; + __u16 ByteCount; + __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ + char Data[1]; +} WRITE_REQ; + +typedef struct smb_com_write_rsp { + struct smb_hdr hdr; /* wct = 6 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Count; + __u16 Remaining; + __u32 Reserved; + __u16 ByteCount; +} WRITE_RSP; + +typedef struct smb_com_read_req { + struct smb_hdr hdr; /* wct = 12 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Fid; + __u32 OffsetLow; + __u16 MaxCount; + __u16 MinCount; /* obsolete */ + __u32 MaxCountHigh; + __u16 Remaining; + __u32 OffsetHigh; + __u16 ByteCount; +} READ_REQ; + +typedef struct smb_com_read_rsp { + struct smb_hdr hdr; /* wct = 12 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Remaining; + __u16 DataCompactionMode; + __u16 Reserved; + __u16 DataLength; + __u16 DataOffset; + __u16 DataLengthHigh; + __u64 Reserved2; + __u16 ByteCount; + __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ + char Data[1]; +} READ_RSP; + +typedef struct locking_andx_range { + __u16 Pid; + __u16 Pad; + __u32 OffsetHigh; + __u32 OffsetLow; + __u32 LengthHigh; + __u32 LengthLow; +} LOCKING_ANDX_RANGE; + +#define LOCKING_ANDX_SHARED_LOCK 0x01 +#define LOCKING_ANDX_OPLOCK_RELEASE 0x02 +#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 +#define LOCKING_ANDX_CANCEL_LOCK 0x08 +#define LOCKING_ANDX_LARGE_FILES 0x10 /* always on for us */ + +typedef struct smb_com_lock_req { + struct smb_hdr hdr; /* wct = 8 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Fid; + __u8 LockType; + __u8 OplockLevel; + __u32 Timeout; + __u16 NumberOfUnlocks; + __u16 NumberOfLocks; + __u16 ByteCount; + LOCKING_ANDX_RANGE Locks[1]; +} LOCK_REQ; + +typedef struct smb_com_lock_rsp { + struct smb_hdr hdr; /* wct = 2 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 ByteCount; +} LOCK_RSP; + +typedef struct smb_com_rename_req { + struct smb_hdr hdr; /* wct = 1 */ + __u16 SearchAttributes; /* target file attributes */ + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII or Unicode */ + unsigned char OldFileName[1]; + /* followed by __u8 BufferFormat2 */ + /* followed by NewFileName */ +} RENAME_REQ; + + /* copy request flags */ +#define COPY_MUST_BE_FILE 0x0001 +#define COPY_MUST_BE_DIR 0x0002 +#define COPY_TARGET_MODE_ASCII 0x0004 /* if not set, binary */ +#define COPY_SOURCE_MODE_ASCII 0x0008 /* if not set, binary */ +#define COPY_VERIFY_WRITES 0x0010 +#define COPY_TREE 0x0020 + +typedef struct smb_com_copy_req { + struct smb_hdr hdr; /* wct = 3 */ + __u16 Tid2; + __u16 OpenFunction; + __u16 Flags; + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII or Unicode */ + unsigned char OldFileName[1]; + /* followed by __u8 BufferFormat2 */ + /* followed by NewFileName string */ +} COPY_REQ; + +typedef struct smb_com_copy_rsp { + struct smb_hdr hdr; /* wct = 1 */ + __u16 CopyCount; /* number of files copied */ + __u16 ByteCount; /* may be zero */ + __u8 BufferFormat; /* 0x04 - only present if errored file follows */ + unsigned char ErrorFileName[1]; /* only present if error in copy */ +} COPY_RSP; + +#define CREATE_HARD_LINK 0x103 +#define MOVEFILE_COPY_ALLOWED 0x0002 +#define MOVEFILE_REPLACE_EXISTING 0x0001 + +typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */ + struct smb_hdr hdr; /* wct = 4 */ + __u16 SearchAttributes; /* target file attributes */ + __u16 Flags; /* spec says Information Level */ + __u32 ClusterCount; + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII or Unicode */ + unsigned char OldFileName[1]; + /* followed by __u8 BufferFormat2 */ + /* followed by NewFileName */ +} NT_RENAME_REQ; + +typedef struct smb_com_rename_rsp { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bct = 0 */ +} RENAME_RSP; + +typedef struct smb_com_delete_file_req { + struct smb_hdr hdr; /* wct = 1 */ + __u16 SearchAttributes; + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII */ + unsigned char fileName[1]; +} DELETE_FILE_REQ; + +typedef struct smb_com_delete_file_rsp { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bct = 0 */ +} DELETE_FILE_RSP; + +typedef struct smb_com_delete_directory_req { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII */ + unsigned char DirName[1]; +} DELETE_DIRECTORY_REQ; + +typedef struct smb_com_delete_directory_rsp { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bct = 0 */ +} DELETE_DIRECTORY_RSP; + +typedef struct smb_com_create_directory_req { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII */ + unsigned char DirName[1]; +} CREATE_DIRECTORY_REQ; + +typedef struct smb_com_create_directory_rsp { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bct = 0 */ +} CREATE_DIRECTORY_RSP; + +/***************************************************/ +/* NT Transact structure defintions follow */ +/* Currently only ioctl and notify are implemented */ +/***************************************************/ +typedef struct smb_com_transaction_ioctl_req { + struct smb_hdr hdr; /* wct = 23 */ + __u8 MaxSetupCount; + __u16 Reserved; + __u32 TotalParameterCount; + __u32 TotalDataCount; + __u32 MaxParameterCount; + __u32 MaxDataCount; + __u32 ParameterCount; + __u32 ParameterOffset; + __u32 DataCount; + __u32 DataOffset; + __u8 SetupCount; /* four setup words follow subcommand */ + /* SNIA spec incorrectly included spurious pad here */ + __u16 SubCommand;/* 2 = IOCTL/FSCTL */ + __u32 FunctionCode; + __u16 Fid; + __u8 IsFsctl; /* 1 = File System Control, 0 = device control (IOCTL)*/ + __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/ + __u16 ByteCount; + __u8 Pad[3]; + __u8 Data[1]; +} TRANSACT_IOCTL_REQ; + +typedef struct smb_com_transaction_ioctl_rsp { + struct smb_hdr hdr; /* wct = 19 */ + __u8 Reserved[3]; + __u32 TotalParameterCount; + __u32 TotalDataCount; + __u32 ParameterCount; + __u32 ParameterOffset; + __u32 ParameterDisplacement; + __u32 DataCount; + __u32 DataOffset; + __u32 DataDisplacement; + __u8 SetupCount; /* 1 */ + __u16 ReturnedDataLen; + __u16 ByteCount; + __u8 Pad[3]; +} TRANSACT_IOCTL_RSP; + +typedef struct smb_com_transaction_change_notify_req { + struct smb_hdr hdr; /* wct = 23 */ + __u8 MaxSetupCount; + __u16 Reserved; + __u32 TotalParameterCount; + __u32 TotalDataCount; + __u32 MaxParameterCount; + __u32 MaxDataCount; + __u32 ParameterCount; + __u32 ParameterOffset; + __u32 DataCount; + __u32 DataOffset; + __u8 SetupCount; /* four setup words follow subcommand */ + /* SNIA spec incorrectly included spurious pad here */ + __u16 SubCommand;/* 4 = Change Notify */ + __u32 CompletionFilter; /* operation to monitor */ + __u16 Fid; + __u8 WatchTree; /* 1 = Monitor subdirectories */ + __u8 Reserved2; + __u16 ByteCount; +/* __u8 Pad[3];*/ +/* __u8 Data[1];*/ +} TRANSACT_CHANGE_NOTIFY_REQ; + +typedef struct smb_com_transaction_change_notify_rsp { + struct smb_hdr hdr; /* wct = 18 */ + __u8 Reserved[3]; + __u32 TotalParameterCount; + __u32 TotalDataCount; + __u32 ParameterCount; + __u32 ParameterOffset; + __u32 ParameterDisplacement; + __u32 DataCount; + __u32 DataOffset; + __u32 DataDisplacement; + __u8 SetupCount; /* 0 */ + __u16 ByteCount; + /* __u8 Pad[3]; */ +} TRANSACT_CHANGE_NOTIFY_RSP; +/* Completion Filter flags for Notify */ +#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 +#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 +#define FILE_NOTIFY_CHANGE_NAME 0x00000003 +#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 +#define FILE_NOTIFY_CHANGE_SIZE 0x00000008 +#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 +#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 +#define FILE_NOTIFY_CHANGE_CREATION 0x00000040 +#define FILE_NOTIFY_CHANGE_EA 0x00000080 +#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 +#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200 +#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400 +#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800 + +#define FILE_ACTION_ADDED 0x00000001 +#define FILE_ACTION_REMOVED 0x00000002 +#define FILE_ACTION_MODIFIED 0x00000003 +#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 +#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 +#define FILE_ACTION_ADDED_STREAM 0x00000006 +#define FILE_ACTION_REMOVED_STREAM 0x00000007 +#define FILE_ACTION_MODIFIED_STREAM 0x00000008 + +/* response contains array of the following structures */ +struct file_notify_information { + __u32 NextEntryOffset; + __u32 Action; + __u32 FileNameLength; + __u8 FileName[1]; +}; + +struct reparse_data { + __u32 ReparseTag; + __u16 ReparseDataLength; + __u16 Reserved; + __u16 AltNameOffset; + __u16 AltNameLen; + __u16 TargetNameOffset; + __u16 TargetNameLen; + char LinkNamesBuf[1]; +}; + +struct cifs_quota_data { + __u32 rsrvd1; /* 0 */ + __u32 sid_size; + __u64 rsrvd2; /* 0 */ + __u64 space_used; + __u64 soft_limit; + __u64 hard_limit; + char sid[1]; /* variable size? */ +}; + +/* quota sub commands */ +#define QUOTA_LIST_CONTINUE 0 +#define QUOTA_LIST_START 0x100 +#define QUOTA_FOR_SID 0x101 + +typedef union smb_com_transaction2 { + struct { + struct smb_hdr hdr; /* wct = 14+ */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* 1st setup word - can be followed by SetupCount words */ + __u16 ByteCount; /* careful - setupcount is not always one */ + } req; + struct { + struct smb_hdr hdr; /* wct = 0 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParamterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; + __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ + /* data area follows */ + } resp; +} TRANSACTION2; + +/* PathInfo/FileInfo infolevels */ +#define SMB_INFO_STANDARD 1 +#define SMB_INFO_QUERY_EAS_FROM_LIST 3 +#define SMB_INFO_QUERY_ALL_EAS 4 +#define SMB_INFO_IS_NAME_VALID 6 +#define SMB_QUERY_FILE_BASIC_INFO 0x101 +#define SMB_QUERY_FILE_STANDARD_INFO 0x102 +#define SMB_QUERY_FILE_EA_INFO 0x103 +#define SMB_QUERY_FILE_NAME_INFO 0x104 +#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105 +#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106 +#define SMB_QUERY_FILE_ALL_INFO 0x107 +#define SMB_QUERY_ALT_NAME_INFO 0x108 +#define SMB_QUERY_FILE_STREAM_INFO 0x109 +#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B +#define SMB_QUERY_FILE_UNIX_BASIC 0x200 +#define SMB_QUERY_FILE_UNIX_LINK 0x201 + +#define SMB_SET_FILE_BASIC_INFO 0x101 +#define SMB_SET_FILE_DISPOSITION_INFO 0x102 +#define SMB_SET_FILE_ALLOCATION_INFO 0x103 +#define SMB_SET_FILE_END_OF_FILE_INFO 0x104 +#define SMB_SET_FILE_UNIX_BASIC 0x200 +#define SMB_SET_FILE_UNIX_LINK 0x201 +#define SMB_SET_FILE_UNIX_HLINK 0x203 +#define SMB_SET_FILE_BASIC_INFO2 0x3ec +#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 +#define SMB_FILE_ALL_INFO2 0x3fa +#define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb +#define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc +#define SMB_FILE_MOVE_CLUSTER_INFO 0x407 +#define SMB_FILE_QUOTA_INFO 0x408 +#define SMB_FILE_REPARSEPOINT_INFO 0x409 +#define SMB_FILE_MAXIMUM_INFO 0x40d + +/* Find File infolevels */ +#define SMB_FIND_FILE_DIRECTORY_INFO 0x101 +#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 +#define SMB_FIND_FILE_NAMES_INFO 0x103 +#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104 +#define SMB_FIND_FILE_UNIX 0x202 + +typedef struct smb_com_transaction2_qpi_req { + struct smb_hdr hdr; /* wct = 14+ */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* one setup word */ + __u16 ByteCount; + __u8 Pad; + __u16 InformationLevel; + __u32 Reserved4; + char FileName[1]; +} TRANSACTION2_QPI_REQ; + +typedef struct smb_com_transaction2_qpi_rsp { + struct smb_hdr hdr; /* wct = 10 + SetupCount */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; + __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ +} TRANSACTION2_QPI_RSP; + +typedef struct smb_com_transaction2_spi_req { + struct smb_hdr hdr; /* wct = 15 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* one setup word */ + __u16 ByteCount; + __u8 Pad; + __u16 Pad1; + __u16 InformationLevel; + __u32 Reserved4; + char FileName[1]; +} TRANSACTION2_SPI_REQ; + +typedef struct smb_com_transaction2_spi_rsp { + struct smb_hdr hdr; /* wct = 10 + SetupCount */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; + __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ +} TRANSACTION2_SPI_RSP; + +struct set_file_rename { + __u32 overwrite; /* 1 = overwrite dest */ + __u32 root_fid; /* zero */ + __u32 target_name_len; + char target_name[0]; /* Must be unicode */ +}; + +struct smb_com_transaction2_sfi_req { + struct smb_hdr hdr; /* wct = 15 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* one setup word */ + __u16 ByteCount; + __u8 Pad; + __u16 Pad1; + __u16 Fid; + __u16 InformationLevel; + __u16 Reserved4; +}; + +struct smb_com_transaction2_sfi_rsp { + struct smb_hdr hdr; /* wct = 10 + SetupCount */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; + __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ +}; + + +/* + * Flags on T2 FINDFIRST and FINDNEXT + */ +#define CIFS_SEARCH_CLOSE_ALWAYS 0x0001 +#define CIFS_SEARCH_CLOSE_AT_END 0x0002 +#define CIFS_SEARCH_RETURN_RESUME 0x0004 +#define CIFS_SEARCH_CONTINUE_FROM_LAST 0x0008 +#define CIFS_SEARCH_BACKUP_SEARCH 0x0010 + +/* + * Size of the resume key on FINDFIRST and FINDNEXT calls + */ +#define CIFS_SMB_RESUME_KEY_SIZE 4 + +typedef struct smb_com_transaction2_ffirst_req { + struct smb_hdr hdr; /* wct = 15 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; /* one */ + __u8 Reserved3; + __u16 SubCommand; /* TRANS2_FIND_FIRST */ + __u16 ByteCount; + __u8 Pad; + __u16 SearchAttributes; + __u16 SearchCount; + __u16 SearchFlags; + __u16 InformationLevel; + __u32 SearchStorageType; + char FileName[1]; +} TRANSACTION2_FFIRST_REQ; + +typedef struct smb_com_transaction2_ffirst_rsp { + struct smb_hdr hdr; /* wct = 10 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; +} TRANSACTION2_FFIRST_RSP; + +typedef struct smb_com_transaction2_ffirst_rsp_parms { + __u16 SearchHandle; + __u16 SearchCount; + __u16 EndofSearch; + __u16 EAErrorOffset; + __u16 LastNameOffset; +} T2_FFIRST_RSP_PARMS; + +typedef struct smb_com_transaction2_fnext_req { + struct smb_hdr hdr; /* wct = 15 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; /* one */ + __u8 Reserved3; + __u16 SubCommand; /* TRANS2_FIND_NEXT */ + __u16 ByteCount; + __u8 Pad; + __u16 SearchHandle; + __u16 SearchCount; + __u16 InformationLevel; + __u32 ResumeKey; + __u16 SearchFlags; + char ResumeFileName[1]; +} TRANSACTION2_FNEXT_REQ; + +typedef struct smb_com_transaction2_fnext_rsp { + struct smb_hdr hdr; /* wct = 10 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; +} TRANSACTION2_FNEXT_RSP; + +typedef struct smb_com_transaction2_fnext_rsp_parms { + __u16 SearchCount; + __u16 EndofSearch; + __u16 EAErrorOffset; + __u16 LastNameOffset; +} T2_FNEXT_RSP_PARMS; + +/* QFSInfo Levels */ +#define SMB_INFO_ALLOCATION 1 +#define SMB_INFO_VOLUME 2 +#define SMB_QUERY_FS_VOLUME_INFO 0x102 +#define SMB_QUERY_FS_SIZE_INFO 0x103 +#define SMB_QUERY_FS_DEVICE_INFO 0x104 +#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105 +#define SMB_QUERY_CIFS_UNIX_INFO 0x200 +#define SMB_QUERY_LABEL_INFO 0x3ea +#define SMB_QUERY_FS_QUOTA_INFO 0x3ee + +typedef struct smb_com_transaction2_qfsi_req { + struct smb_hdr hdr; /* wct = 14+ */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* one setup word */ + __u16 ByteCount; + __u8 Pad; + __u16 InformationLevel; +} TRANSACTION2_QFSI_REQ; + +typedef struct smb_com_transaction_qfsi_rsp { + struct smb_hdr hdr; /* wct = 10 + SetupCount */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; + __u8 Pad; /* may be three bytes *//* followed by data area */ +} TRANSACTION2_QFSI_RSP; + +typedef struct smb_com_transaction2_get_dfs_refer_req { + struct smb_hdr hdr; /* wct = 15 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* one setup word */ + __u16 ByteCount; + __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */ + __u16 MaxReferralLevel; + char RequestFileName[1]; +} TRANSACTION2_GET_DFS_REFER_REQ; + +typedef struct dfs_referral_level_3 { + __u16 VersionNumber; + __u16 ReferralSize; + __u16 ServerType; /* 0x0001 = CIFS server */ + __u16 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 */ + __u16 TimeToLive; + __u16 Proximity; + __u16 DfsPathOffset; + __u16 DfsAlternatePathOffset; + __u16 NetworkAddressOffset; +} REFERRAL3; + +typedef struct smb_com_transaction_get_dfs_refer_rsp { + struct smb_hdr hdr; /* wct = 10 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* zero setup words following */ + __u16 ByteCount; + __u8 Pad; + __u16 PathConsumed; + __u16 NumberOfReferrals; + __u16 DFSFlags; + __u16 Pad2; + REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ + /* followed by the strings pointed to by the referral structures */ +} TRANSACTION2_GET_DFS_REFER_RSP; + +/* DFS Flags */ +#define DFSREF_REFERRAL_SERVER 0x0001 +#define DFSREF_STORAGE_SERVER 0x0002 + +/* IOCTL information */ +/* List of ioctl function codes that look to be of interest to remote clients like this. */ +/* Need to do some experimentation to make sure they all work remotely. */ +/* Some of the following such as the encryption/compression ones would be */ +/* invoked from tools via a specialized hook into the VFS rather than via the */ +/* standard vfs entry points */ +#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000 +#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004 +#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008 +#define FSCTL_LOCK_VOLUME 0x00090018 +#define FSCTL_UNLOCK_VOLUME 0x0009001C +#define FSCTL_GET_COMPRESSION 0x0009003C +#define FSCTL_SET_COMPRESSION 0x0009C040 +#define FSCTL_REQUEST_FILTER_OPLOCK 0x0009008C +#define FSCTL_FILESYS_GET_STATISTICS 0x00090090 +#define FSCTL_SET_REPARSE_POINT 0x000900A4 +#define FSCTL_GET_REPARSE_POINT 0x000900A8 +#define FSCTL_DELETE_REPARSE_POINT 0x000900AC +#define FSCTL_SET_SPARSE 0x000900C4 +#define FSCTL_SET_ZERO_DATA 0x000900C8 +#define FSCTL_SET_ENCRYPTION 0x000900D7 +#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB +#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF +#define FSCTL_READ_RAW_ENCRYPTED 0x000900E3 +#define FSCTL_SIS_COPYFILE 0x00090100 +#define FSCTL_SIS_LINK_FILES 0x0009C104 + +#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 +#define IO_REPARSE_TAG_HSM 0xC0000004 +#define IO_REPARSE_TAG_SIS 0x80000007 + +/* + ************************************************************************ + * All structs for everything above the SMB PDUs themselves + * (such as the T2 level specific data) go here + ************************************************************************ + */ + +/* + * Information on a server + */ + +struct serverInfo { + char name[16]; + unsigned char versionMajor; + unsigned char versionMinor; + unsigned long type; + unsigned int commentOffset; +}; + +/* + * The following structure is the format of the data returned on a NetShareEnum + * with level "90" (x5A) + */ + +struct shareInfo { + char shareName[13]; + char pad; + unsigned short type; + unsigned int commentOffset; +}; + +struct aliasInfo { + char aliasName[9]; + char pad; + unsigned int commentOffset; + unsigned char type[2]; +}; + +struct aliasInfo92 { + int aliasNameOffset; + int serverNameOffset; + int shareNameOffset; +}; + +typedef struct { + __u64 TotalAllocationUnits; + __u64 FreeAllocationUnits; + __u32 SectorsPerAllocationUnit; + __u32 BytesPerSector; +} FILE_SYSTEM_INFO; /* size info, level 0x103 */ + +typedef struct { + __u16 MajorVersionNumber; + __u16 MinorVersionNumber; + __u64 Capability; +} FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ +/* Linux/Unix extensions capability flags */ +#define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ +#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 + +/* DeviceType Flags */ +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SERIAL_PORT 0x0000001b +#define FILE_DEVICE_STREAMS 0x0000001e +#define FILE_DEVICE_TAPE 0x0000001f +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 + +typedef struct { + __u32 DeviceType; + __u32 DeviceCharacteristics; +} FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ + +typedef struct { + __u32 Attributes; + __u32 MaxPathNameComponentLength; + __u32 FileSystemNameLen; + char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ +} FILE_SYSTEM_ATTRIBUTE_INFO; + +typedef struct { /* data block encoding of response to level 263 QPathInfo */ + __u64 CreationTime; + __u64 LastAccessTime; + __u64 LastWriteTime; + __u64 ChangeTime; + __u32 Attributes; + __u32 Pad1; + __u64 AllocationSize; + __u64 EndOfFile; /* size ie offset to first free byte in file */ + __u32 NumberOfLinks; /* hard links */ + __u8 DeletePending; + __u8 Directory; + __u16 Pad2; + __u64 IndexNumber; + __u32 EASize; + __u32 AccessFlags; + __u64 IndexNumber1; + __u64 CurrentByteOffset; + __u32 Mode; + __u32 AlignmentRequirement; + __u32 FileNameLength; + char FileName[1]; +} FILE_ALL_INFO; /* level 263 QPathInfo */ + +typedef struct { + __u64 EndOfFile; + __u64 NumOfBytes; + __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */ + __u64 LastAccessTime; + __u64 LastModificationTime; + __u64 Uid; + __u64 Gid; + __u32 Type; + __u64 DevMajor; + __u64 DevMinor; + __u64 UniqueId; + __u64 Permissions; + __u64 Nlinks; +} FILE_UNIX_BASIC_INFO; /* level 512 QPathInfo */ + +typedef struct { + char LinkDest[1]; +} FILE_UNIX_LINK_INFO; /* level 513 QPathInfo */ + +/* defines for enumerating possible values of the Unix type field below */ +#define UNIX_FILE 0 +#define UNIX_DIR 1 +#define UNIX_SYMLINK 2 +#define UNIX_CHARDEV 3 +#define UNIX_BLOCKDEV 4 +#define UNIX_FIFO 5 +#define UNIX_SOCKET 6 + +typedef struct { + __u32 NextEntryOffset; + __u32 ResumeKey; + __u64 EndOfFile; + __u64 NumOfBytes; + __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */ + __u64 LastAccessTime; + __u64 LastModificationTime; + __u64 Uid; + __u64 Gid; + __u32 Type; + __u64 DevMajor; + __u64 DevMinor; + __u64 UniqueId; + __u64 Permissions; + __u64 Nlinks; + char FileName[1]; +} FILE_UNIX_INFO; + +typedef struct { + __u64 CreationTime; + __u64 LastAccessTime; + __u64 LastWriteTime; + __u64 ChangeTime; + __u32 Attributes; + __u32 Pad; +} FILE_BASIC_INFO; /* size info, level 0x101 */ + +struct file_allocation_info { + __u64 AllocationSize; +}; /* size info, level 0x103 */ + +struct file_end_of_file_info { + __u64 FileSize; /* offset to end of file */ +}; /* size info, level 0x104 */ + +typedef struct { + __u32 NextEntryOffset; + __u32 FileIndex; + __u64 CreationTime; + __u64 LastAccessTime; + __u64 LastWriteTime; + __u64 ChangeTime; + __u64 EndOfFile; + __u64 AllocationSize; + __u32 ExtFileAttributes; + __u32 FileNameLength; + char FileName[1]; +} FILE_DIRECTORY_INFO; /* level 257 FF response data area */ + +struct gea { + unsigned char cbName; + char szName[1]; +}; + +struct gealist { + unsigned long cbList; + struct gea list[1]; +}; + +struct fea { + unsigned char EA_flags; + __u8 name_len; + __u16 value_len; + char szName[1]; + /* optionally followed by value */ +}; +/* flags for _FEA.fEA */ +#define FEA_NEEDEA 0x80 /* need EA bit */ + +struct fealist { + __u32 list_len; + struct fea list[1]; +}; + +/* used to hold an arbitrary blob of data */ +struct data_blob { + __u8 *data; + size_t length; + void (*free) (struct data_blob * data_blob); +}; + +#ifdef CONFIG_CIFS_POSIX +/* + For better POSIX semantics from Linux client, (even better + than the existing CIFS Unix Extensions) we need updated PDUs for: + + 1) PosixCreateX - to set and return the mode, inode#, device info and + perhaps add a CreateDevice - to create Pipes and other special .inodes + Also note POSIX open flags + 2) Close - to return the last write time to do cache across close more safely + 3) PosixQFSInfo - to return statfs info + 4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes) + 5) Mkdir - set mode + + And under consideration: + 6) FindClose2 (return nanosecond timestamp ??) + 7) Use nanosecond timestamps throughout all time fields if + corresponding attribute flag is set + 8) sendfile - handle based copy + 9) Direct i/o + 10) "POSIX ACL" support + 11) Misc fcntls? + + what about fixing 64 bit alignment + + There are also various legacy SMB/CIFS requests used as is + + From existing Lanman and NTLM dialects: + -------------------------------------- + NEGOTIATE + SESSION_SETUP_ANDX (BB which?) + TREE_CONNECT_ANDX (BB which wct?) + TREE_DISCONNECT (BB add volume timestamp on response) + LOGOFF_ANDX + DELETE (note delete open file behavior) + DELETE_DIRECTORY + READ_AND_X + WRITE_AND_X + LOCKING_AND_X (note posix lock semantics) + RENAME (note rename across dirs and open file rename posix behaviors) + NT_RENAME (for hardlinks) Is this good enough for all features? + FIND_CLOSE2 + TRANSACTION2 (18 cases) + SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2 + (BB verify that never need to set allocation size) + SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?) + + COPY (note support for copy across directories) - FUTURE, OPTIONAL + setting/getting OS/2 EAs - FUTURE (BB can this handle + setting Linux xattrs perfectly) - OPTIONAL + dnotify - FUTURE, OPTIONAL + quota - FUTURE, OPTIONAL + + Note that various requests implemented for NT interop such as + NT_TRANSACT (IOCTL) QueryReparseInfo + are unneeded to servers compliant with the CIFS POSIX extensions + + From CIFS Unix Extensions: + ------------------------- + T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks + T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2) + T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK) + T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields + Actually need QUERY_FILE_UNIX_INFO since has inode num + BB what about a) blksize/blkbits/blocks + b) i_version + c) i_rdev + d) notify mask? + e) generation + f) size_seqcount + T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX + TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended + T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL + + + */ +#endif + +#pragma pack() /* resume default structure packing */ + +#endif /* _CIFSPDU_H */ diff -urN linux-2.4.27/fs/cifs/cifsproto.h linux-2.4.27-cifs-1.20c/fs/cifs/cifsproto.h --- linux-2.4.27/fs/cifs/cifsproto.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifsproto.h Wed Jul 14 00:25:05 2004 @@ -0,0 +1,254 @@ +/* + * fs/cifs/cifsproto.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _CIFSPROTO_H +#define _CIFSPROTO_H +#include + +struct statfs; + +/* + ***************************************************************** + * All Prototypes + ***************************************************************** + */ + +extern struct smb_hdr *cifs_buf_get(void); +extern void cifs_buf_release(void *); +extern int smb_send(struct socket *, struct smb_hdr *, + unsigned int /* length */ , struct sockaddr *); +extern unsigned int _GetXid(void); +extern void _FreeXid(unsigned int); +#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid)); +#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,rc));} +extern char *build_path_from_dentry(struct dentry *); +extern char *build_wildcard_path_from_dentry(struct dentry *direntry); +extern void renew_parental_timestamps(struct dentry *direntry); +extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, + struct smb_hdr * /* input */ , + struct smb_hdr * /* out */ , + int * /* bytes returned */ , const int long_op); +extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); +extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); +extern int is_valid_oplock_break(struct smb_hdr *smb); +extern unsigned int smbCalcSize(struct smb_hdr *ptr); +extern int decode_negTokenInit(unsigned char *security_blob, int length, + enum securityEnum *secType); +extern int map_smb_to_linux_error(struct smb_hdr *smb); +extern void header_assemble(struct smb_hdr *, char /* command */ , + const struct cifsTconInfo *, int + /* length of fixed section (word count) in two byte units */ + ); +struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *); +void DeleteOplockQEntry(struct oplock_q_entry *); +extern time_t cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); +extern u64 cifs_UnixTimeToNT(time_t); +extern int cifs_get_inode_info(struct inode **pinode, + const unsigned char *search_path, + FILE_ALL_INFO * pfile_info, + struct super_block *sb, int xid); +extern int cifs_get_inode_info_unix(struct inode **pinode, + const unsigned char *search_path, + struct super_block *sb,int xid); + +extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, + struct nls_table * nls_info); +extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); + +extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, + const char *tree, struct cifsTconInfo *tcon, + const struct nls_table *); + +extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, + const char *searchName, + FILE_DIRECTORY_INFO * findData, + T2_FFIRST_RSP_PARMS * findParms, + const struct nls_table *nls_codepage, + int *pUnicodeFlag, + int *pUnixFlag /* if Unix extensions used */ ); +extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, + FILE_DIRECTORY_INFO * findData, + T2_FNEXT_RSP_PARMS * findParms, + const __u16 searchHandle, char * resume_name, + int name_length, __u32 resume_key, + int *UnicodeFlag, int *pUnixFlag); + +extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, + const __u16 search_handle); + +extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + FILE_ALL_INFO * findData, + const struct nls_table *nls_codepage); + +extern int CIFSSMBUnixQPathInfo(const int xid, + struct cifsTconInfo *tcon, + const unsigned char *searchName, + FILE_UNIX_BASIC_INFO * pFindData, + const struct nls_table *nls_codepage); + +extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, + const unsigned char *searchName, + unsigned char **targetUNCs, + unsigned int *number_of_UNC_in_array, + const struct nls_table *nls_codepage); + +extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, + const char *old_path, + const struct nls_table *nls_codepage); +extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, + const char *old_path, const struct nls_table *nls_codepage, + unsigned int *pnum_referrals, unsigned char ** preferrals); +extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, + struct statfs *FSData, + const struct nls_table *nls_codepage); +extern int CIFSSMBQFSAttributeInfo(const int xid, + struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage); +extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage); +extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage); + +extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, + char *fileName, FILE_BASIC_INFO * data, + const struct nls_table *nls_codepage); +extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, + char *fileName, __u64 size,int setAllocationSizeFlag, + const struct nls_table *nls_codepage); +extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, + __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag); +extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon, + char *full_path, __u64 mode, __u64 uid, + __u64 gid, dev_t dev, const struct nls_table *nls_codepage); + +extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, + const char *newName, + const struct nls_table *nls_codepage); +extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, + const char *name, const struct nls_table *nls_codepage); + +extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, + const char *name, + const struct nls_table *nls_codepage); +extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); +extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, + int netfid, char * target_name, const struct nls_table *nls_codepage); +extern int CIFSCreateHardLink(const int xid, + struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); +extern int CIFSUnixCreateHardLink(const int xid, + struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); +extern int CIFSUnixCreateSymLink(const int xid, + struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); +extern int CIFSSMBUnixQuerySymLink(const int xid, + struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *syminfo, const int buflen, + const struct nls_table *nls_codepage); +extern int CIFSSMBQueryReparseLinkInfo(const int xid, + struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *symlinkinfo, const int buflen, __u16 fid, + const struct nls_table *nls_codepage); + +extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, + const char *fileName, const int disposition, + const int access_flags, const int omode, + __u16 * netfid, int *pOplock, FILE_ALL_INFO *, + const struct nls_table *nls_codepage); +extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, + const int smb_file_id); + +extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, + const int netfid, unsigned int count, + const __u64 lseek, unsigned int *nbytes, char **buf); +extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, + const int netfid, const unsigned int count, + const __u64 lseek, unsigned int *nbytes, + const char *buf, const int long_op); +extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, + const __u16 netfid, const __u64 len, + const __u64 offset, const __u32 numUnlock, + const __u32 numLock, const __u8 lockType, + const int waitFlag); + +extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); +extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); + +extern struct cifsSesInfo *sesInfoAlloc(void); +extern void sesInfoFree(struct cifsSesInfo *); +extern struct cifsTconInfo *tconInfoAlloc(void); +extern void tconInfoFree(struct cifsTconInfo *); + +extern int cifs_reconnect(struct TCP_Server_Info *server); + +extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *); +extern int cifs_verify_signature(const struct smb_hdr *, const char * mac_key, + __u32 expected_sequence_number); +extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); +extern void CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); +extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); + +extern int CIFSBuildServerList(int xid, char *serverBufferList, + int recordlength, int *entries, + int *totalEntries, int *topoChangedFlag); +extern int CIFSSMBQueryShares(int xid, struct cifsTconInfo *tcon, + struct shareInfo *shareList, int bufferLen, + int *entries, int *totalEntries); +extern int CIFSSMBQueryAlias(int xid, struct cifsTconInfo *tcon, + struct aliasInfo *aliasList, int bufferLen, + int *entries, int *totalEntries); +extern int CIFSSMBAliasInfo(int xid, struct cifsTconInfo *tcon, + char *aliasName, char *serverName, + char *shareName, char *comment); +extern int CIFSSMBGetShareInfo(int xid, struct cifsTconInfo *tcon, + char *share, char *comment); +extern int CIFSSMBGetUserPerms(int xid, struct cifsTconInfo *tcon, + char *userName, char *searchName, int *perms); +extern int CIFSSMBSync(int xid, struct cifsTconInfo *tcon, int netfid, int pid); + +extern int CIFSSMBSeek(int xid, + struct cifsTconInfo *tcon, + int netfid, + int pid, + int whence, unsigned long offset, long long *newoffset); + +extern int CIFSSMBCopy(int xid, + struct cifsTconInfo *source_tcon, + const char *fromName, + const __u16 target_tid, + const char *toName, const int flags, + const struct nls_table *nls_codepage); +extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, + const int notify_subdirs,const __u16 netfid,__u32 filter, + const struct nls_table *nls_codepage); +extern int CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + char * EAData, size_t size, + const struct nls_table *nls_codepage); +#endif /* _CIFSPROTO_H */ diff -urN linux-2.4.27/fs/cifs/cifssmb.c linux-2.4.27-cifs-1.20c/fs/cifs/cifssmb.c --- linux-2.4.27/fs/cifs/cifssmb.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/cifssmb.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,3016 @@ +/* + * fs/cifs/cifssmb.c + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * Contains the routines for constructing the SMB PDUs themselves + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */ + /* These are mostly routines that operate on a pathname, or on a tree id */ + /* (mounted volume), but there are eight handle based routines which must be */ + /* treated slightly different for reconnection purposes since we never want */ + /* to reuse a stale file handle and the caller knows the file handle */ + +#include +#include +#include +#include +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_unicode.h" +#include "cifs_debug.h" + +#ifdef CONFIG_CIFS_POSIX +static struct { + int index; + char *name; +} protocols[] = { + {CIFS_PROT, "\2NT LM 0.12"}, + {CIFS_PROT, "\2POSIX 2"}, + {BAD_PROT, "\2"} +}; +#else +static struct { + int index; + char *name; +} protocols[] = { + {CIFS_PROT, "\2NT LM 0.12"}, + {BAD_PROT, "\2"} +}; +#endif + + +/* Mark as invalid, all open files on tree connections since they + were closed when session to server was lost */ +static void mark_open_files_invalid(struct cifsTconInfo * pTcon) +{ + struct cifsFileInfo *open_file = NULL; + struct list_head * tmp; + struct list_head * tmp1; + +/* list all files open on tree connection and mark them invalid */ + write_lock(&GlobalSMBSeslock); + list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, tlist); + if(open_file) { + open_file->invalidHandle = TRUE; + } + } + write_unlock(&GlobalSMBSeslock); + /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */ +} + +static int +smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, + void **request_buf /* returned */ , + void **response_buf /* returned */ ) +{ + int rc = 0; + int timeout = 10 * HZ; + + /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so + check for tcp and smb session status done differently + for those three - in the calling routine */ + if(tcon) { + if((tcon->ses) && (tcon->ses->server)){ + struct nls_table *nls_codepage; + /* Give Demultiplex thread up to 10 seconds to + reconnect, should be greater than cifs socket + timeout which is 7 seconds */ + while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + while ((tcon->ses->server->tcpStatus != CifsGood) && (timeout > 0)){ + timeout = interruptible_sleep_on_timeout(&tcon->ses->server->response_q,timeout); + } + if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + /* on "soft" mounts we wait once */ + if((tcon->retry == FALSE) || + (tcon->ses->status == CifsExiting)) { + cFYI(1,("gave up waiting on reconnect in smb_init")); + return -EHOSTDOWN; + } /* else "hard" mount - keep retrying until + process is killed or server comes back up */ + } else /* TCP session is reestablished now */ + break; + + } + + nls_codepage = load_nls_default(); + /* need to prevent multiple threads trying to + simultaneously reconnect the same SMB session */ + down(&tcon->ses->sesSem); + if(tcon->ses->status == CifsNeedReconnect) + rc = cifs_setup_session(0, tcon->ses, nls_codepage); + if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { + mark_open_files_invalid(tcon); + rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, + nls_codepage); + up(&tcon->ses->sesSem); + if(rc == 0) + atomic_inc(&tconInfoReconnectCount); + + cFYI(1, ("reconnect tcon rc = %d", rc)); + /* Removed call to reopen open files here - + it is safer (and faster) to reopen files + one at a time as needed in read and write */ + + /* Check if handle based operation so we + know whether we can continue or not without + returning to caller to reset file handle */ + switch(smb_command) { + case SMB_COM_READ_ANDX: + case SMB_COM_WRITE_ANDX: + case SMB_COM_CLOSE: + case SMB_COM_FIND_CLOSE2: + case SMB_COM_LOCKING_ANDX: { + unload_nls(nls_codepage); + return -EAGAIN; + } + } + } else { + up(&tcon->ses->sesSem); + } + unload_nls(nls_codepage); + + } else { + return -EIO; + } + } + if(rc) + return rc; + + *request_buf = cifs_buf_get(); + if (*request_buf == 0) { + /* BB should we add a retry in here if not a writepage? */ + return -ENOMEM; + } + /* Although the original thought was we needed the response buf for */ + /* potential retries of smb operations it turns out we can determine */ + /* from the mid flags when the request buffer can be resent without */ + /* having to use a second distinct buffer for the response */ + *response_buf = *request_buf; + + header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, + wct /*wct */ ); + +#ifdef CONFIG_CIFS_STATS + if(tcon != NULL) { + atomic_inc(&tcon->num_smbs_sent); + } +#endif + return rc; +} + +int +CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) +{ + NEGOTIATE_REQ *pSMB; + NEGOTIATE_RSP *pSMBr; + int rc = 0; + int bytes_returned; + struct TCP_Server_Info * server; + + if(ses->server) + server = ses->server; + else { + rc = -EIO; + return rc; + } + rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , + (void **) &pSMB, (void **) &pSMBr); + if (rc) + return rc; + + pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; + if (extended_security) + pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; + + pSMB->ByteCount = strlen(protocols[0].name) + 1; + strncpy(pSMB->DialectsArray, protocols[0].name, 30); + /* null guaranteed to be at end of source and target buffers anyway */ + + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc == 0) { + server->secMode = pSMBr->SecurityMode; + server->secType = NTLM; /* BB override default for NTLMv2 or krb*/ + /* one byte - no need to convert this or EncryptionKeyLen from le,*/ + server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); + /* probably no need to store and check maxvcs */ + server->maxBuf = + min(le32_to_cpu(pSMBr->MaxBufferSize), + (__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE); + server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); + cFYI(0, ("Max buf = %d ", ses->server->maxBuf)); + GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); + server->capabilities = le32_to_cpu(pSMBr->Capabilities); + server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); + /* BB with UTC do we ever need to be using srvr timezone? */ + if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { + memcpy(server->cryptKey, pSMBr->u.EncryptionKey, + CIFS_CRYPTO_KEY_SIZE); + } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) + && (pSMBr->EncryptionKeyLength == 0)) { + /* decode security blob */ + } else + rc = -EIO; + + /* BB might be helpful to save off the domain of server here */ + + if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) { + if (pSMBr->ByteCount < 16) + rc = -EIO; + else if (pSMBr->ByteCount == 16) { + server->secType = RawNTLMSSP; + if (server->socketUseCount.counter > 1) { + if (memcmp + (server->server_GUID, + pSMBr->u.extended_response. + GUID, 16) != 0) { + cFYI(1, + ("UID of server does not match previous connection to same ip address")); + memcpy(server-> + server_GUID, + pSMBr->u. + extended_response. + GUID, 16); + } + } else + memcpy(server->server_GUID, + pSMBr->u.extended_response. + GUID, 16); + } else { + rc = decode_negTokenInit(pSMBr->u. + extended_response. + SecurityBlob, + pSMBr->ByteCount - + 16, &server->secType); + } + } else + server->capabilities &= ~CAP_EXTENDED_SECURITY; + if(sign_CIFS_PDUs == FALSE) { + if(server->secMode & SECMODE_SIGN_REQUIRED) + cERROR(1, + ("Server requires /proc/fs/cifs/PacketSigningEnabled")); + server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); + } else if(sign_CIFS_PDUs == 1) { + if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) + server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); + } + + } + if (pSMB) + cifs_buf_release(pSMB); + return rc; +} + +int +CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + int rc = 0; + int length; + + cFYI(1, ("In tree disconnect")); + /* + * If last user of the connection and + * connection alive - disconnect it + * If this is the last connection on the server session disconnect it + * (and inside session disconnect we should check if tcp socket needs + * to be freed and kernel thread woken up). + */ + if (tcon) + down(&tcon->tconSem); + else + return -EIO; + + atomic_dec(&tcon->useCount); + if (atomic_read(&tcon->useCount) > 0) { + up(&tcon->tconSem); + return -EBUSY; + } + + /* No need to return error on this operation if tid invalidated and + closed on server already e.g. due to tcp session crashing */ + if(tcon->tidStatus == CifsNeedReconnect) { + up(&tcon->tconSem); + return 0; + } + + if((tcon->ses == 0) || (tcon->ses->server == 0)) { + up(&tcon->tconSem); + return -EIO; + } + + rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, + (void **) &smb_buffer, (void **) &smb_buffer_response); + if (rc) { + up(&tcon->tconSem); + return rc; + } + rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, + &length, 0); + if (rc) + cFYI(1, (" Tree disconnect failed %d", rc)); + + if (smb_buffer) + cifs_buf_release(smb_buffer); + up(&tcon->tconSem); + + /* No need to return error on this operation if tid invalidated and + closed on server already e.g. due to tcp session crashing */ + if (rc == -EAGAIN) + rc = 0; + + return rc; +} + +int +CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) +{ + struct smb_hdr *smb_buffer_response; + LOGOFF_ANDX_REQ *pSMB; + int rc = 0; + int length; + + cFYI(1, ("In SMBLogoff for session disconnect")); + if (ses) + down(&ses->sesSem); + else + return -EIO; + + atomic_dec(&ses->inUse); + if (atomic_read(&ses->inUse) > 0) { + up(&ses->sesSem); + return -EBUSY; + } + + rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL /* no tcon anymore */, + (void **) &pSMB, (void **) &smb_buffer_response); + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + if (rc) { + up(&ses->sesSem); + return rc; + } + + pSMB->hdr.Uid = ses->Suid; + + pSMB->AndXCommand = 0xFF; + rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, + smb_buffer_response, &length, 0); + if (ses->server) { + atomic_dec(&ses->server->socketUseCount); + if (atomic_read(&ses->server->socketUseCount) == 0) { + spin_lock(&GlobalMid_Lock); + ses->server->tcpStatus = CifsExiting; + spin_unlock(&GlobalMid_Lock); + rc = -ESHUTDOWN; + } + } + if (pSMB) + cifs_buf_release(pSMB); + up(&ses->sesSem); + + /* if session dead then we do not need to do ulogoff, + since server closed smb session, no sense reporting + error */ + if (rc == -EAGAIN) + rc = 0; + return rc; +} + +int +CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, + const char *fileName, const struct nls_table *nls_codepage) +{ + DELETE_FILE_REQ *pSMB = NULL; + DELETE_FILE_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + +DelFileRetry: + rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->fileName, fileName, name_len); + } + pSMB->SearchAttributes = + cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); + pSMB->ByteCount = name_len + 1; + pSMB->BufferFormat = 0x04; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Error in RMFile = %d", rc)); + } +#ifdef CONFIG_CIFS_STATS + else { + atomic_inc(&tcon->num_deletes); + } +#endif + + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto DelFileRetry; + + return rc; +} + +int +CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, + const char *dirName, const struct nls_table *nls_codepage) +{ + DELETE_DIRECTORY_REQ *pSMB = NULL; + DELETE_DIRECTORY_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In CIFSSMBRmDir")); +RmDirRetry: + rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(dirName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->DirName, dirName, name_len); + } + + pSMB->ByteCount = name_len + 1; + pSMB->BufferFormat = 0x04; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Error in RMDir = %d", rc)); + } +#ifdef CONFIG_CIFS_STATS + else { + atomic_inc(&tcon->num_rmdirs); + } +#endif + + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto RmDirRetry; + return rc; +} + +int +CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, + const char *name, const struct nls_table *nls_codepage) +{ + int rc = 0; + CREATE_DIRECTORY_REQ *pSMB = NULL; + CREATE_DIRECTORY_RSP *pSMBr = NULL; + int bytes_returned; + int name_len; + + cFYI(1, ("In CIFSSMBMkDir")); +MkDirRetry: + rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(name, 530); + name_len++; /* trailing null */ + strncpy(pSMB->DirName, name, name_len); + } + + pSMB->ByteCount = name_len + 1 /* for buf format */ ; + pSMB->BufferFormat = 0x04; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Error in Mkdir = %d", rc)); + } +#ifdef CONFIG_CIFS_STATS + else { + atomic_inc(&tcon->num_mkdirs); + } +#endif + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto MkDirRetry; + return rc; +} + +int +CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, + const char *fileName, const int openDisposition, + const int access_flags, const int create_options, __u16 * netfid, + int *pOplock, FILE_ALL_INFO * pfile_info, + const struct nls_table *nls_codepage) +{ + int rc = -EACCES; + OPEN_REQ *pSMB = NULL; + OPEN_RSP *pSMBr = NULL; + int bytes_returned; + int name_len; + +openRetry: + rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->AndXCommand = 0xFF; /* none */ + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + pSMB->ByteCount = 1; /* account for one byte pad to word boundary */ + name_len = + cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1), + fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + pSMB->NameLength = cpu_to_le16(name_len); + } else { /* BB improve the check for buffer overruns BB */ + pSMB->ByteCount = 0; /* no pad */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + pSMB->NameLength = cpu_to_le16(name_len); + strncpy(pSMB->fileName, fileName, name_len); + } + if (*pOplock & REQ_OPLOCK) + pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK); + else if (*pOplock & REQ_BATCHOPLOCK) { + pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); + } + pSMB->DesiredAccess = cpu_to_le32(access_flags); + pSMB->AllocationSize = 0; + pSMB->FileAttributes = ATTR_NORMAL; + /* XP does not handle ATTR_POSIX_SEMANTICS */ + /* but it helps speed up case sensitive checks for other + servers such as Samba */ + if (tcon->ses->capabilities & CAP_UNIX) + pSMB->FileAttributes |= ATTR_POSIX_SEMANTICS; + + /* if ((omode & S_IWUGO) == 0) + pSMB->FileAttributes |= ATTR_READONLY;*/ + /* Above line causes problems due to vfs splitting create into two + pieces - need to set mode after file created not while it is + being created */ + pSMB->FileAttributes = cpu_to_le32(pSMB->FileAttributes); + pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); + pSMB->CreateDisposition = cpu_to_le32(openDisposition); + pSMB->CreateOptions = cpu_to_le32(create_options); + pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/ + pSMB->SecurityFlags = + cpu_to_le32(SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY); + + pSMB->ByteCount += name_len; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + /* long_op set to 1 to allow for oplock break timeouts */ + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 1); + if (rc) { + cFYI(1, ("Error in Open = %d", rc)); + } else { + *pOplock = pSMBr->OplockLevel; /* one byte no need to le_to_cpu */ + *netfid = pSMBr->Fid; /* cifs fid stays in le */ + /* Let caller know file was created so we can set the mode. */ + /* Do we care about the CreateAction in any other cases? */ + if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) + *pOplock |= CIFS_CREATE_ACTION; + if(pfile_info) { + memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime, + 36 /* CreationTime to Attributes */); + /* the file_info buf is endian converted by caller */ + pfile_info->AllocationSize = pSMBr->AllocationSize; + pfile_info->EndOfFile = pSMBr->EndOfFile; + pfile_info->NumberOfLinks = cpu_to_le32(1); + } + +#ifdef CONFIG_CIFS_STATS + atomic_inc(&tcon->num_opens); +#endif + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto openRetry; + return rc; +} + +/* If no buffer passed in, then caller wants to do the copy + as in the case of readpages so the SMB buffer must be + freed by the caller */ + +int +CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, + const int netfid, const unsigned int count, + const __u64 lseek, unsigned int *nbytes, char **buf) +{ + int rc = -EACCES; + READ_REQ *pSMB = NULL; + READ_RSP *pSMBr = NULL; + char *pReadData = NULL; + int bytes_returned; + + *nbytes = 0; + rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + /* tcon and ses pointer are checked in smb_init */ + if (tcon->ses->server == NULL) + return -ECONNABORTED; + + pSMB->AndXCommand = 0xFF; /* none */ + pSMB->Fid = netfid; + pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); + pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); + pSMB->Remaining = 0; + pSMB->MaxCount = cpu_to_le16(count); + pSMB->MaxCountHigh = 0; + pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cERROR(1, ("Send error in read = %d", rc)); + } else { + pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength); + *nbytes = pSMBr->DataLength; + /*check that DataLength would not go beyond end of SMB */ + if ((pSMBr->DataLength > CIFS_MAX_MSGSIZE) + || (pSMBr->DataLength > count)) { + cFYI(1,("bad length %d for count %d",pSMBr->DataLength,count)); + rc = -EIO; + *nbytes = 0; + } else { + pReadData = + (char *) (&pSMBr->hdr.Protocol) + + le16_to_cpu(pSMBr->DataOffset); +/* if(rc = copy_to_user(buf, pReadData, pSMBr->DataLength)) { + cERROR(1,("Faulting on read rc = %d",rc)); + rc = -EFAULT; + }*/ /* can not use copy_to_user when using page cache*/ + if(*buf) + memcpy(*buf,pReadData,pSMBr->DataLength); + } + } + if (pSMB) { + if(*buf) + cifs_buf_release(pSMB); + else + *buf = (char *)pSMB; + } + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; +} + +int +CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, + const int netfid, const unsigned int count, + const __u64 offset, unsigned int *nbytes, const char *buf, + const int long_op) +{ + int rc = -EACCES; + WRITE_REQ *pSMB = NULL; + WRITE_RSP *pSMBr = NULL; + int bytes_returned; + + rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + /* tcon and ses pointer are checked in smb_init */ + if (tcon->ses->server == NULL) + return -ECONNABORTED; + + pSMB->AndXCommand = 0xFF; /* none */ + pSMB->Fid = netfid; + pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); + pSMB->OffsetHigh = cpu_to_le32(offset >> 32); + pSMB->Remaining = 0; + if (count > ((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00)) + pSMB->DataLengthLow = + (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00; + else + pSMB->DataLengthLow = count; + pSMB->DataLengthHigh = 0; + pSMB->DataOffset = + cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); + + memcpy(pSMB->Data,buf,pSMB->DataLengthLow); + + pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ; + pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, long_op); + if (rc) { + cFYI(1, ("Send error in write = %d", rc)); + *nbytes = 0; + } else + *nbytes = le16_to_cpu(pSMBr->Count); + + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +int +CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, + const __u16 smb_file_id, const __u64 len, + const __u64 offset, const __u32 numUnlock, + const __u32 numLock, const __u8 lockType, const int waitFlag) +{ + int rc = 0; + LOCK_REQ *pSMB = NULL; + LOCK_RSP *pSMBr = NULL; + int bytes_returned; + int timeout = 0; + __u64 temp; + + cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock)); + rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) { + timeout = -1; /* no response expected */ + pSMB->Timeout = 0; + } else if (waitFlag == TRUE) { + timeout = 3; /* blocking operation, no timeout */ + pSMB->Timeout = -1; /* blocking - do not time out */ + } else { + pSMB->Timeout = 0; + } + + pSMB->NumberOfLocks = cpu_to_le32(numLock); + pSMB->NumberOfUnlocks = cpu_to_le32(numUnlock); + pSMB->LockType = lockType; + pSMB->AndXCommand = 0xFF; /* none */ + pSMB->Fid = smb_file_id; /* netfid stays le */ + + if(numLock != 0) { + pSMB->Locks[0].Pid = cpu_to_le16(current->tgid); + /* BB where to store pid high? */ + temp = cpu_to_le64(len); + pSMB->Locks[0].LengthLow = (__u32)(temp & 0xFFFFFFFF); + pSMB->Locks[0].LengthHigh = (__u32)(temp>>32); + temp = cpu_to_le64(offset); + pSMB->Locks[0].OffsetLow = (__u32)(temp & 0xFFFFFFFF); + pSMB->Locks[0].OffsetHigh = (__u32)(temp>>32); + pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE); + } else { + /* oplock break */ + pSMB->ByteCount = 0; + } + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, timeout); + + if (rc) { + cFYI(1, ("Send error in Lock = %d", rc)); + } + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; +} + +int +CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) +{ + int rc = 0; + CLOSE_REQ *pSMB = NULL; + CLOSE_RSP *pSMBr = NULL; + int bytes_returned; + cFYI(1, ("In CIFSSMBClose")); + +/* do not retry on dead session on close */ + rc = smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB, + (void **) &pSMBr); + if(rc == -EAGAIN) + return 0; + if (rc) + return rc; + + pSMB->FileID = (__u16) smb_file_id; + pSMB->LastWriteTime = 0; + pSMB->ByteCount = 0; + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + if(rc!=-EINTR) { + /* EINTR is expected when user ctl-c to kill app */ + cERROR(1, ("Send error in Close = %d", rc)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + /* Since session is dead, file will be closed on server already */ + if(rc == -EAGAIN) + rc = 0; + + return rc; +} + +int +CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage) +{ + int rc = 0; + RENAME_REQ *pSMB = NULL; + RENAME_RSP *pSMBr = NULL; + int bytes_returned; + int name_len, name_len2; + + cFYI(1, ("In CIFSSMBRename")); +renameRetry: + rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->BufferFormat = 0x04; + pSMB->SearchAttributes = + cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | + ATTR_DIRECTORY); + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + pSMB->OldFileName[name_len] = 0x04; /* pad */ + /* protocol requires ASCII signature byte on Unicode string */ + pSMB->OldFileName[name_len + 1] = 0x00; + name_len2 = + cifs_strtoUCS((wchar_t *) & pSMB-> + OldFileName[name_len + 2], toName, 530, + nls_codepage); + name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; + name_len2 *= 2; /* convert to bytes */ + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fromName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->OldFileName, fromName, name_len); + name_len2 = strnlen(toName, 530); + name_len2++; /* trailing null */ + pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ + strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); + name_len2++; /* trailing null */ + name_len2++; /* signature byte */ + } + + pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in rename = %d", rc)); + } + +#ifdef CONFIG_CIFS_STATS + else { + atomic_inc(&tcon->num_renames); + } +#endif + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto renameRetry; + + return rc; +} + +int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, + int netfid, char * target_name, const struct nls_table * nls_codepage) +{ + struct smb_com_transaction2_sfi_req *pSMB = NULL; + struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; + struct set_file_rename * rename_info; + char *data_offset; + char dummy_string[30]; + int rc = 0; + int bytes_returned = 0; + int len_of_str; + + cFYI(1, ("Rename to File by handle")); + rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->ParameterCount = 6; + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, + Fid) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + rename_info = (struct set_file_rename *) data_offset; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + /* construct random name ".cifs_tmp" */ + rename_info->overwrite = cpu_to_le32(1); + rename_info->root_fid = 0; + /* unicode only call */ + if(target_name == NULL) { + sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid); + len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage); + } else { + len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, 530, nls_codepage); + } + rename_info->target_name_len = cpu_to_le32(2 * len_of_str); + pSMB->DataCount = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2; + pSMB->ByteCount += pSMB->DataCount; + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->Fid = netfid; + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1,("Send error in Rename (by file handle) = %d", rc)); + } +#ifdef CONFIG_CIFS_STATS + else { + atomic_inc(&pTcon->num_t2renames); + } +#endif + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +int +CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, + const __u16 target_tid, const char *toName, const int flags, + const struct nls_table *nls_codepage) +{ + int rc = 0; + COPY_REQ *pSMB = NULL; + COPY_RSP *pSMBr = NULL; + int bytes_returned; + int name_len, name_len2; + + cFYI(1, ("In CIFSSMBCopy")); +copyRetry: + rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->BufferFormat = 0x04; + pSMB->Tid2 = target_tid; + + if(flags & COPY_TREE) + pSMB->Flags |= COPY_TREE; + pSMB->Flags = cpu_to_le16(pSMB->Flags); + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, + fromName, + 530 /* find define for this maxpathcomponent */, + nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + pSMB->OldFileName[name_len] = 0x04; /* pad */ + /* protocol requires ASCII signature byte on Unicode string */ + pSMB->OldFileName[name_len + 1] = 0x00; + name_len2 = cifs_strtoUCS((wchar_t *) & pSMB-> + OldFileName[name_len + 2], toName, 530, + nls_codepage); + name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; + name_len2 *= 2; /* convert to bytes */ + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fromName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->OldFileName, fromName, name_len); + name_len2 = strnlen(toName, 530); + name_len2++; /* trailing null */ + pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ + strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); + name_len2++; /* trailing null */ + name_len2++; /* signature byte */ + } + + pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in copy = %d with %d files copied", + rc, pSMBr->CopyCount)); + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto copyRetry; + + return rc; +} + +int +CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage) +{ + TRANSACTION2_SPI_REQ *pSMB = NULL; + TRANSACTION2_SPI_RSP *pSMBr = NULL; + char *data_offset; + int name_len; + int name_len_target; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In Symlink Unix style")); +createSymLinkRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fromName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fromName, name_len); + } + pSMB->ParameterCount = 6 + name_len; + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len_target = + cifs_strtoUCS((wchar_t *) data_offset, toName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len_target++; /* trailing null */ + name_len_target *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len_target = strnlen(toName, 530); + name_len_target++; /* trailing null */ + strncpy(data_offset, toName, name_len_target); + } + + pSMB->DataCount = name_len_target; + pSMB->MaxParameterCount = cpu_to_le16(2); + /* BB find exact max on data count below from sess */ + pSMB->MaxDataCount = cpu_to_le16(1000); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, + ("Send error in SetPathInfo (create symlink) = %d", + rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto createSymLinkRetry; + + return rc; +} + +int +CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage) +{ + TRANSACTION2_SPI_REQ *pSMB = NULL; + TRANSACTION2_SPI_RSP *pSMBr = NULL; + char *data_offset; + int name_len; + int name_len_target; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In Create Hard link Unix style")); +createHardLinkRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(toName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, toName, name_len); + } + pSMB->ParameterCount = 6 + name_len; + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len_target = + cifs_strtoUCS((wchar_t *) data_offset, fromName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len_target++; /* trailing null */ + name_len_target *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len_target = strnlen(fromName, 530); + name_len_target++; /* trailing null */ + strncpy(data_offset, fromName, name_len_target); + } + + pSMB->DataCount = name_len_target; + pSMB->MaxParameterCount = cpu_to_le16(2); + /* BB find exact max on data count below from sess*/ + pSMB->MaxDataCount = cpu_to_le16(1000); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto createHardLinkRetry; + + return rc; +} + +int +CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage) +{ + int rc = 0; + NT_RENAME_REQ *pSMB = NULL; + RENAME_RSP *pSMBr = NULL; + int bytes_returned; + int name_len, name_len2; + + cFYI(1, ("In CIFSCreateHardLink")); +winCreateHardLinkRetry: + + rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->SearchAttributes = + cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | + ATTR_DIRECTORY); + pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK); + pSMB->ClusterCount = 0; + + pSMB->BufferFormat = 0x04; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + pSMB->OldFileName[name_len] = 0; /* pad */ + pSMB->OldFileName[name_len + 1] = 0x04; + name_len2 = + cifs_strtoUCS((wchar_t *) & pSMB-> + OldFileName[name_len + 2], toName, 530, + nls_codepage); + name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; + name_len2 *= 2; /* convert to bytes */ + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fromName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->OldFileName, fromName, name_len); + name_len2 = strnlen(toName, 530); + name_len2++; /* trailing null */ + pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ + strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); + name_len2++; /* trailing null */ + name_len2++; /* signature byte */ + } + + pSMB->ByteCount = 1 /* string type byte */ + name_len + name_len2; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto winCreateHardLinkRetry; + + return rc; +} + +int +CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *symlinkinfo, const int buflen, + const struct nls_table *nls_codepage) +{ +/* SMB_QUERY_FILE_UNIX_LINK */ + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName)); + +querySymLinkRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = + 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + /* BB find exact max data count below from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(4000); + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); + if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512)) + /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ + else { + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = UniStrnlen((wchar_t *) ((char *) + &pSMBr->hdr.Protocol +pSMBr->DataOffset), + min_t(const int, buflen,pSMBr->DataCount) / 2); + cifs_strfromUCS_le(symlinkinfo, + (wchar_t *) ((char *)&pSMBr->hdr.Protocol + + pSMBr->DataOffset), + name_len, nls_codepage); + } else { + strncpy(symlinkinfo, + (char *) &pSMBr->hdr.Protocol + + pSMBr->DataOffset, + min_t(const int, buflen, pSMBr->DataCount)); + } + symlinkinfo[buflen] = 0; + /* just in case so calling code does not go off the end of buffer */ + } + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto querySymLinkRetry; + return rc; +} + + + +int +CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *symlinkinfo, const int buflen,__u16 fid, + const struct nls_table *nls_codepage) +{ + int rc = 0; + int bytes_returned; + int name_len; + struct smb_com_transaction_ioctl_req * pSMB; + struct smb_com_transaction_ioctl_rsp * pSMBr; + + cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName)); + rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 0 ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le32(2); + /* BB find exact data count max from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le32(4000); + pSMB->MaxSetupCount = 4; + pSMB->Reserved = 0; + pSMB->ParameterOffset = 0; + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 4; + pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT); + pSMB->IsFsctl = 1; /* FSCTL */ + pSMB->IsRootFlag = 0; + pSMB->Fid = fid; /* file handle always le */ + pSMB->ByteCount = 0; + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); + if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512)) + /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ + else { + if(pSMBr->DataCount && (pSMBr->DataCount < 2048)) { + /* could also validate reparse tag && better check name length */ + struct reparse_data * reparse_buf = (struct reparse_data *) + ((char *)&pSMBr->hdr.Protocol + pSMBr->DataOffset); + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = UniStrnlen((wchar_t *) + (reparse_buf->LinkNamesBuf + + reparse_buf->TargetNameOffset), + min(buflen/2, reparse_buf->TargetNameLen / 2)); + cifs_strfromUCS_le(symlinkinfo, + (wchar_t *) (reparse_buf->LinkNamesBuf + + reparse_buf->TargetNameOffset), + name_len, nls_codepage); + } else { /* ASCII names */ + strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + + reparse_buf->TargetNameOffset, + min_t(const int, buflen, reparse_buf->TargetNameLen)); + } + } else { + rc = -EIO; + cFYI(1,("Invalid return data count on get reparse info ioctl")); + } + symlinkinfo[buflen] = 0; /* just in case so the caller + does not go off the end of the buffer */ + cFYI(1,("readlink result - %s ",symlinkinfo)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +int +CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + FILE_ALL_INFO * pFindData, + const struct nls_table *nls_codepage) +{ +/* level 263 SMB_QUERY_FILE_ALL_INFO */ + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In QPathInfo path %s", searchName)); +QPathInfoRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QPathInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + /* BB also check enough total bytes returned */ + /* BB we need to improve the validity checking + of these trans2 responses */ + if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512)) + rc = -EIO; /* bad smb */ + else if (pFindData){ + memcpy((char *) pFindData, + (char *) &pSMBr->hdr.Protocol + + pSMBr->DataOffset, sizeof (FILE_ALL_INFO)); + } else + rc = -ENOMEM; + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto QPathInfoRetry; + + return rc; +} + +int +CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + FILE_UNIX_BASIC_INFO * pFindData, + const struct nls_table *nls_codepage) +{ +/* SMB_QUERY_FILE_UNIX_BASIC */ + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned = 0; + int name_len; + + cFYI(1, ("In QPathInfo (Unix) the path %s", searchName)); +UnixQPathInfoRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(4000); + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QPathInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + /* BB also check if enough total bytes returned */ + if ((pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO)) || + (pSMBr->DataOffset > 512) || + (pSMBr->DataOffset < sizeof(struct smb_hdr))) { + cFYI(1,("UnixQPathinfo invalid data offset %d bytes returned %d", + (int)pSMBr->DataOffset,bytes_returned)); + rc = -EIO; /* bad smb */ + } else { + memcpy((char *) pFindData, + (char *) &pSMBr->hdr.Protocol + + pSMBr->DataOffset, + sizeof (FILE_UNIX_BASIC_INFO)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto UnixQPathInfoRetry; + + return rc; +} + +int +CIFSFindSingle(const int xid, struct cifsTconInfo *tcon, + const char *searchName, FILE_ALL_INFO * findData, + const struct nls_table *nls_codepage) +{ +/* level 257 SMB_ */ + TRANSACTION2_FFIRST_REQ *pSMB = NULL; + TRANSACTION2_FFIRST_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In FindUnique")); +findUniqueRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 12 + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; /* no EAs */ + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16( + offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; /* one byte, no need to le convert */ + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalDataCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->SearchAttributes = + cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | + ATTR_DIRECTORY); + pSMB->SearchCount = cpu_to_le16(16); /* BB increase */ + pSMB->SearchFlags = cpu_to_le16(1); + pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); + pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */ + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + + if (rc) { + cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); + } else { /* decode response */ + + /* BB fill in */ + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto findUniqueRetry; + + return rc; +} + +int +CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, + const char *searchName, FILE_DIRECTORY_INFO * findData, + T2_FFIRST_RSP_PARMS * findParms, + const struct nls_table *nls_codepage, int *pUnicodeFlag, + int *pUnixFlag) +{ +/* level 257 SMB_ */ + TRANSACTION2_FFIRST_REQ *pSMB = NULL; + TRANSACTION2_FFIRST_RSP *pSMBr = NULL; + char *response_data; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In FindFirst")); +findFirstRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 12 + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; /* no EAs */ + pSMB->MaxParameterCount = cpu_to_le16(10); + pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf - + MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof(struct + smb_com_transaction2_ffirst_req, SearchAttributes) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; /* one byte no need to make endian neutral */ + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); + pSMB->SearchAttributes = + cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | + ATTR_DIRECTORY); + pSMB->SearchCount = cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); /* should this be shrunk even more ? */ + pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); + + /* test for Unix extensions */ + if (tcon->ses->capabilities & CAP_UNIX) { + pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX); + *pUnixFlag = TRUE; + } else { + pSMB->InformationLevel = + cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); + *pUnixFlag = FALSE; + } + pSMB->SearchStorageType = 0; /* BB what should we set this to? It is not clear if it matters BB */ + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + + if (rc) { /* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ + cFYI(1, ("Error in FindFirst = %d", rc)); + } else { /* decode response */ + /* BB add safety checks for these memcpys */ + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) + *pUnicodeFlag = TRUE; + else + *pUnicodeFlag = FALSE; + memcpy(findParms, + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->ParameterOffset), + sizeof (T2_FFIRST_RSP_PARMS)); + /* search handle can stay LE and EAoffset not needed so not converted */ + findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch); + findParms->LastNameOffset = + le16_to_cpu(findParms->LastNameOffset); + findParms->SearchCount = le16_to_cpu(findParms->SearchCount); + response_data = + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->DataOffset); + memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto findFirstRetry; + + return rc; +} + +int +CIFSFindNext(const int xid, struct cifsTconInfo *tcon, + FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms, + const __u16 searchHandle, char * resume_file_name, int name_len, + __u32 resume_key, int *pUnicodeFlag, int *pUnixFlag) +{ +/* level 257 SMB_ */ + TRANSACTION2_FNEXT_REQ *pSMB = NULL; + TRANSACTION2_FNEXT_RSP *pSMBr = NULL; + char *response_data; + int rc = 0; + int bytes_returned; + + cFYI(1, ("In FindNext")); + + if(resume_file_name == NULL) { + return -EIO; + } + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 14; /* includes 2 bytes of null string, converted to LE below */ + pSMB->TotalDataCount = 0; /* no EAs */ + pSMB->MaxParameterCount = cpu_to_le16(8); + pSMB->MaxDataCount = + cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_fnext_req,SearchHandle) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT); + pSMB->SearchHandle = searchHandle; /* always kept as le */ + findParms->SearchCount = 0; /* set to zero in case of error */ + pSMB->SearchCount = + cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); + /* test for Unix extensions */ + if (tcon->ses->capabilities & CAP_UNIX) { + pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX); + *pUnixFlag = TRUE; + } else { + pSMB->InformationLevel = + cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); + *pUnixFlag = FALSE; + } + pSMB->ResumeKey = resume_key; + pSMB->SearchFlags = + cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); + /* BB add check to make sure we do not cross end of smb */ + if(name_len < CIFS_MAX_MSGSIZE) { + memcpy(pSMB->ResumeFileName, resume_file_name, name_len); + pSMB->ByteCount += name_len; + } + pSMB->TotalParameterCount += name_len; + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + /* BB improve error handling here */ + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + + if (rc) { + if (rc == -EBADF) + rc = 0; /* search probably was closed at end of search above */ + else + cFYI(1, ("FindNext returned = %d", rc)); + } else { /* decode response */ + /* BB add safety checks for these memcpys */ + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) + *pUnicodeFlag = TRUE; + else + *pUnicodeFlag = FALSE; + memcpy(findParms, + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->ParameterOffset), + sizeof (T2_FNEXT_RSP_PARMS)); + findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch); + findParms->LastNameOffset = + le16_to_cpu(findParms->LastNameOffset); + findParms->SearchCount = le16_to_cpu(findParms->SearchCount); + response_data = + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->DataOffset); + memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); + } + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +int +CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle) +{ + int rc = 0; + FINDCLOSE_REQ *pSMB = NULL; + CLOSE_RSP *pSMBr = NULL; + int bytes_returned; + + cFYI(1, ("In CIFSSMBFindClose")); + rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB, + (void **) &pSMBr); + /* no sense returning error if session restarted + file handle has been closed */ + if(rc == -EAGAIN) + return 0; + if (rc) + return rc; + + pSMB->FileID = searchHandle; + pSMB->ByteCount = 0; + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cERROR(1, ("Send error in FindClose = %d", rc)); + } + if (pSMB) + cifs_buf_release(pSMB); + + /* Since session is dead, search handle closed on server already */ + if (rc == -EAGAIN) + rc = 0; + + return rc; +} + +int +CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, + const unsigned char *searchName, + unsigned char **targetUNCs, + unsigned int *number_of_UNC_in_array, + const struct nls_table *nls_codepage) +{ +/* TRANS2_GET_DFS_REFERRAL */ + TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; + TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; + struct dfs_referral_level_3 * referrals = NULL; + int rc = 0; + int bytes_returned; + int name_len; + unsigned int i; + char * temp; + *number_of_UNC_in_array = 0; + *targetUNCs = NULL; + + cFYI(1, ("In GetDFSRefer the path %s", searchName)); + if (ses == NULL) + return -ENODEV; +getDFSRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->hdr.Tid = ses->ipc_tid; + pSMB->hdr.Uid = ses->Suid; + if (ses->capabilities & CAP_STATUS32) { + pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS; + } + if (ses->capabilities & CAP_DFS) { + pSMB->hdr.Flags2 |= SMBFLG2_DFS; + } + + if (ses->capabilities & CAP_UNICODE) { + pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; + name_len = + cifs_strtoUCS((wchar_t *) pSMB->RequestFileName, + searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->RequestFileName, searchName, name_len); + } + + pSMB->ParameterCount = 2 /* level */ + name_len /*includes null */ ; + pSMB->TotalDataCount = 0; + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->MaxParameterCount = 0; + pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL); + pSMB->ByteCount = pSMB->ParameterCount + 3 /* pad */ ; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->MaxReferralLevel = cpu_to_le16(3); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in GetDFSRefer = %d", rc)); + } else { /* decode response */ +/* BB Add logic to parse referrals here */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); + cFYI(1, + ("Decoding GetDFSRefer response. BCC: %d Offset %d", + pSMBr->ByteCount, pSMBr->DataOffset)); + if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ + else { + referrals = + (struct dfs_referral_level_3 *) + (8 /* sizeof start of data block */ + + pSMBr->DataOffset + + (char *) &pSMBr->hdr.Protocol); + 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",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive)); + /* BB This field is actually two bytes in from start of + data block so we could do safety check that DataBlock + begins at address of pSMBr->NumberOfReferrals */ + *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals); + + /* BB Fix below so can return more than one referral */ + if(*number_of_UNC_in_array > 1) + *number_of_UNC_in_array = 1; + + /* get the length of the strings describing refs */ + name_len = 0; + for(i=0;i<*number_of_UNC_in_array;i++) { + /* make sure that DfsPathOffset not past end */ + referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset); + if(referrals->DfsPathOffset > pSMBr->DataCount) { + /* if invalid referral, stop here and do + not try to copy any more */ + *number_of_UNC_in_array = i; + break; + } + temp = ((char *)referrals) + referrals->DfsPathOffset; + + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount); + } else { + name_len += strnlen(temp,pSMBr->DataCount); + } + referrals++; + /* BB add check that referral pointer does not fall off end PDU */ + + } + /* BB add check for name_len bigger than bcc */ + *targetUNCs = + kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL); + /* copy the ref strings */ + referrals = + (struct dfs_referral_level_3 *) + (8 /* sizeof data hdr */ + + pSMBr->DataOffset + + (char *) &pSMBr->hdr.Protocol); + + for(i=0;i<*number_of_UNC_in_array;i++) { + temp = ((char *)referrals) + referrals->DfsPathOffset; + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { + cifs_strfromUCS_le(*targetUNCs, + (wchar_t *) temp, name_len, nls_codepage); + } else { + strncpy(*targetUNCs,temp,name_len); + } + /* BB update target_uncs pointers */ + referrals++; + } + temp = *targetUNCs; + temp[name_len] = 0; + } + + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto getDFSRetry; + + return rc; +} + +int +CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, + struct statfs *FSData, const struct nls_table *nls_codepage) +{ +/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ + TRANSACTION2_QFSI_REQ *pSMB = NULL; + TRANSACTION2_QFSI_RSP *pSMBr = NULL; + FILE_SYSTEM_INFO *response_data; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In QFSInfo")); +QFSInfoRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 2; /* level */ + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cERROR(1, ("Send error in QFSInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + cFYI(1, + ("Decoding qfsinfo response. BCC: %d Offset %d", + pSMBr->ByteCount, pSMBr->DataOffset)); + if ((pSMBr->ByteCount < 24) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ + else { + response_data = + (FILE_SYSTEM_INFO + *) (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + FSData->f_bsize = + le32_to_cpu(response_data->BytesPerSector) * + le32_to_cpu(response_data-> + SectorsPerAllocationUnit); + FSData->f_blocks = + le64_to_cpu(response_data->TotalAllocationUnits); + FSData->f_bfree = FSData->f_bavail = + le64_to_cpu(response_data->FreeAllocationUnits); + cFYI(1, + ("Blocks: %lld Free: %lld Block size %ld", + (unsigned long long)FSData->f_blocks, + (unsigned long long)FSData->f_bfree, + FSData->f_bsize)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSInfoRetry; + + return rc; +} + +int +CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage) +{ +/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */ + TRANSACTION2_QFSI_REQ *pSMB = NULL; + TRANSACTION2_QFSI_RSP *pSMBr = NULL; + FILE_SYSTEM_ATTRIBUTE_INFO *response_data; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In QFSAttributeInfo")); +QFSAttributeRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 2; /* level */ + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cERROR(1, ("Send error in QFSAttributeInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) { /* BB also check enough bytes returned */ + rc = -EIO; /* bad smb */ + } else { + response_data = + (FILE_SYSTEM_ATTRIBUTE_INFO + *) (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + response_data->Attributes = le32_to_cpu(response_data->Attributes); + response_data->MaxPathNameComponentLength = + le32_to_cpu(response_data->MaxPathNameComponentLength); + response_data->FileSystemNameLen = + le32_to_cpu(response_data->FileSystemNameLen); + memcpy(&tcon->fsAttrInfo, response_data, + sizeof (FILE_SYSTEM_ATTRIBUTE_INFO)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSAttributeRetry; + + return rc; +} + +int +CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage) +{ +/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ + TRANSACTION2_QFSI_REQ *pSMB = NULL; + TRANSACTION2_QFSI_RSP *pSMBr = NULL; + FILE_SYSTEM_DEVICE_INFO *response_data; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In QFSDeviceInfo")); +QFSDeviceRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 2; /* level */ + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QFSDeviceInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)) + || (pSMBr->DataOffset > 512)) + rc = -EIO; /* bad smb */ + else { + response_data = + (FILE_SYSTEM_DEVICE_INFO + *) (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + response_data->DeviceType = + le32_to_cpu(response_data->DeviceType); + response_data->DeviceCharacteristics = + le32_to_cpu(response_data->DeviceCharacteristics); + memcpy(&tcon->fsDevInfo, response_data, + sizeof (FILE_SYSTEM_DEVICE_INFO)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSDeviceRetry; + + return rc; +} + +int +CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage) +{ +/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */ + TRANSACTION2_QFSI_REQ *pSMB = NULL; + TRANSACTION2_QFSI_RSP *pSMBr = NULL; + FILE_SYSTEM_UNIX_INFO *response_data; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In QFSUnixInfo")); +QFSUnixRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->ParameterCount = 2; /* level */ + pSMB->TotalDataCount = 0; + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ByteCount = pSMB->ParameterCount + 1 /* pad */ ; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof(struct + smb_com_transaction2_qfsi_req, InformationLevel) - 4); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cERROR(1, ("Send error in QFSUnixInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = cpu_to_le16(pSMBr->DataOffset); + if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) { + rc = -EIO; /* bad smb */ + } else { + response_data = + (FILE_SYSTEM_UNIX_INFO + *) (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + response_data->MajorVersionNumber = + le16_to_cpu(response_data->MajorVersionNumber); + response_data->MinorVersionNumber = + le16_to_cpu(response_data->MinorVersionNumber); + response_data->Capability = + le64_to_cpu(response_data->Capability); + memcpy(&tcon->fsUnixInfo, response_data, + sizeof (FILE_SYSTEM_UNIX_INFO)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSUnixRetry; + + + return rc; +} + +/* We can not use write of zero bytes trick to + set file size due to need for large file support. Also note that + this SetPathInfo is preferred to SetFileInfo based method in next + routine which is only needed to work around a sharing violation bug + in Samba which this routine can run into */ + +int +CIFSSMBSetEOF(int xid, struct cifsTconInfo *tcon, char *fileName, + __u64 size, int SetAllocation, const struct nls_table *nls_codepage) +{ + struct smb_com_transaction2_spi_req *pSMB = NULL; + struct smb_com_transaction2_spi_rsp *pSMBr = NULL; + struct file_end_of_file_info *parm_data; + int name_len; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In SetEOF")); +SetEOFRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fileName, name_len); + } + pSMB->ParameterCount = 6 + name_len; + pSMB->DataCount = sizeof (struct file_end_of_file_info); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + if(SetAllocation) { + if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); + else + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); + } else /* Set File Size */ { + if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); + else + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); + } + + parm_data = + (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + + pSMB->DataOffset); + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + parm_data->FileSize = cpu_to_le64(size); + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("SetPathInfo (file size) returned %d", rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetEOFRetry; + + return rc; +} + +int +CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, + __u16 fid, __u32 pid_of_opener, int SetAllocation) +{ + struct smb_com_transaction2_sfi_req *pSMB = NULL; + struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; + char *data_offset; + struct file_end_of_file_info *parm_data; + int rc = 0; + int bytes_returned = 0; + __u32 tmp; + + cFYI(1, ("SetFileSize (via SetFileInfo) %lld", + (long long)size)); + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + tmp = cpu_to_le32(pid_of_opener); /* override pid of current process + so network fid will be valid */ + pSMB->hdr.Pid = tmp & 0xFFFF; + tmp >>= 16; + pSMB->hdr.PidHigh = tmp & 0xFFFF; + + pSMB->ParameterCount = 6; + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, + Fid) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + + pSMB->DataCount = sizeof(struct file_end_of_file_info); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + parm_data = + (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + + pSMB->DataOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */ + parm_data->FileSize = cpu_to_le64(size); + pSMB->Fid = fid; + if(SetAllocation) { + if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); + else + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); + } else /* Set File Size */ { + if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); + else + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); + } + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, + ("Send error in SetFileInfo (SetFileSize) = %d", + rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +int +CIFSSMBSetTimes(int xid, struct cifsTconInfo *tcon, char *fileName, + FILE_BASIC_INFO * data, const struct nls_table *nls_codepage) +{ + TRANSACTION2_SPI_REQ *pSMB = NULL; + TRANSACTION2_SPI_RSP *pSMBr = NULL; + int name_len; + int rc = 0; + int bytes_returned = 0; + char *data_offset; + + cFYI(1, ("In SetTimes")); + +SetTimesRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fileName, name_len); + } + + pSMB->ParameterCount = 6 + name_len; + pSMB->DataCount = sizeof (FILE_BASIC_INFO); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->TotalParameterCount = pSMB->ParameterCount; + if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2); + else + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + memcpy(data_offset, data, sizeof (FILE_BASIC_INFO)); + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("SetPathInfo (times) returned %d", rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetTimesRetry; + + return rc; +} + +int +CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, + char *fileName, __u64 mode, __u64 uid, __u64 gid, + dev_t device, const struct nls_table *nls_codepage) +{ + TRANSACTION2_SPI_REQ *pSMB = NULL; + TRANSACTION2_SPI_RSP *pSMBr = NULL; + int name_len; + int rc = 0; + int bytes_returned = 0; + FILE_UNIX_BASIC_INFO *data_offset; + + cFYI(1, ("In SetUID/GID/Mode")); +setPermsRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fileName, name_len); + } + + pSMB->ParameterCount = 6 + name_len; + pSMB->DataCount = sizeof (FILE_UNIX_BASIC_INFO); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + data_offset = + (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol + + pSMB->DataOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + data_offset->Uid = cpu_to_le64(uid); + data_offset->Gid = cpu_to_le64(gid); + /* better to leave device as zero when it is */ + data_offset->DevMajor = cpu_to_le64(MAJOR(device)); + data_offset->DevMinor = cpu_to_le64(MINOR(device)); + data_offset->Permissions = cpu_to_le64(mode); + + if(S_ISREG(mode)) + data_offset->Type = cpu_to_le32(UNIX_FILE); + else if(S_ISDIR(mode)) + data_offset->Type = cpu_to_le32(UNIX_DIR); + else if(S_ISLNK(mode)) + data_offset->Type = cpu_to_le32(UNIX_SYMLINK); + else if(S_ISCHR(mode)) + data_offset->Type = cpu_to_le32(UNIX_CHARDEV); + else if(S_ISBLK(mode)) + data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV); + else if(S_ISFIFO(mode)) + data_offset->Type = cpu_to_le32(UNIX_FIFO); + else if(S_ISSOCK(mode)) + data_offset->Type = cpu_to_le32(UNIX_SOCKET); + + + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("SetPathInfo (perms) returned %d", rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto setPermsRetry; + return rc; +} + +int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, + const int notify_subdirs, const __u16 netfid, + __u32 filter, const struct nls_table *nls_codepage) +{ + int rc = 0; + struct smb_com_transaction_change_notify_req * pSMB = NULL; + struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; + int bytes_returned; + + cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); + rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 0 ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le32(2); + /* BB find exact data count max from sess structure BB */ + pSMB->MaxDataCount = 0; /* same in little endian or be */ + pSMB->MaxSetupCount = 4; + pSMB->Reserved = 0; + pSMB->ParameterOffset = 0; + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 4; /* single byte does not need le conversion */ + pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); + pSMB->ParameterCount = pSMB->TotalParameterCount; + if(notify_subdirs) + pSMB->WatchTree = 1; /* one byte - no le conversion needed */ + pSMB->Reserved2 = 0; + pSMB->CompletionFilter = cpu_to_le32(filter); + pSMB->Fid = netfid; /* file handle always le */ + pSMB->ByteCount = 0; + + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Error in Notify = %d", rc)); + } + if (pSMB) + cifs_buf_release(pSMB); +/* if (rc == -EAGAIN) + goto NotifyRetry; */ + return rc; +} +#ifdef CONFIG_CIFS_XATTR +int +CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + char * EAData, size_t size, + const struct nls_table *nls_codepage) +{ + /* BB assumes one setup word */ + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In Query All EAs path %s", searchName)); +QAllEAsRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QueryAllEAs = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + /* BB also check enough total bytes returned */ + /* BB we need to improve the validity checking + of these trans2 responses */ + if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512)) + rc = -EIO; /* bad smb */ + /* else if (pFindData){ + memcpy((char *) pFindData, + (char *) &pSMBr->hdr.Protocol + + pSMBr->DataOffset, kl); + }*/ else { + /* check that length of list is not more than bcc */ + /* check that each entry does not go beyond length + of list */ + /* check that each element of each entry does not + go beyond end of list */ + struct fealist * ea_response_data; + rc = 0; + /* validate_trans2_offsets() */ + /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/ + ea_response_data = (struct fealist *) + (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + cFYI(1,("ea length %d",ea_response_data->list_len)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto QAllEAsRetry; + + return rc; +} +#endif diff -urN linux-2.4.27/fs/cifs/connect.c linux-2.4.27-cifs-1.20c/fs/cifs/connect.c --- linux-2.4.27/fs/cifs/connect.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/connect.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,2924 @@ +/* + * fs/cifs/connect.c + * + * Copyright (C) International Business Machines Corp., 2002,2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_unicode.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" +#include "ntlmssp.h" +#include "nterr.h" +#include "rfc1002pdu.h" + +#define CIFS_PORT 445 +#define RFC1001_PORT 139 + +extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, + unsigned char *p24); +extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, + unsigned char *p24); +extern int cifs_inet_pton(int, const char *, void *dst); + +struct smb_vol { + char *username; + char *password; + char *domainname; + char *UNC; + char *UNCip; + char *iocharset; /* local code page for mapping to and from Unicode */ + char source_rfc1001_name[16]; /* netbios name of client */ + uid_t linux_uid; + gid_t linux_gid; + mode_t file_mode; + mode_t dir_mode; + int rw:1; + int retry:1; + int intr:1; + unsigned int rsize; + unsigned int wsize; + unsigned int sockopt; + unsigned short int port; +}; + +static int ipv4_connect(struct sockaddr_in *psin_server, + struct socket **csocket, + char * netb_name); +static int ipv6_connect(struct sockaddr_in6 *psin_server, + struct socket **csocket); + + + /* + * cifs tcp session reconnection + * + * mark tcp session as reconnecting so temporarily locked + * mark all smb sessions as reconnecting for tcp session + * reconnect tcp session + * wake up waiters on reconnection? - (not needed currently) + */ + +int +cifs_reconnect(struct TCP_Server_Info *server) +{ + int rc = 0; + struct list_head *tmp; + struct cifsSesInfo *ses; + struct cifsTconInfo *tcon; + struct mid_q_entry * mid_entry; + + spin_lock(&GlobalMid_Lock); + if(server->tcpStatus == CifsExiting) { + /* the demux thread will exit normally + next time through the loop */ + spin_unlock(&GlobalMid_Lock); + return rc; + } else + server->tcpStatus = CifsNeedReconnect; + spin_unlock(&GlobalMid_Lock); + server->maxBuf = 0; + + cFYI(1, ("Reconnecting tcp session ")); + + /* before reconnecting the tcp session, mark the smb session (uid) + and the tid bad so they are not used until reconnected */ + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalSMBSessionList) { + ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); + if (ses->server) { + if (ses->server == server) { + ses->status = CifsNeedReconnect; + ses->ipc_tid = 0; + } + } + /* else tcp and smb sessions need reconnection */ + } + list_for_each(tmp, &GlobalTreeConnectionList) { + tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + if((tcon) && (tcon->ses) && (tcon->ses->server == server)) { + tcon->tidStatus = CifsNeedReconnect; + } + } + read_unlock(&GlobalSMBSeslock); + /* do not want to be sending data on a socket we are freeing */ + down(&server->tcpSem); + if(server->ssocket) { + cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state, + server->ssocket->flags)); + server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN); + cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state, + server->ssocket->flags)); + sock_release(server->ssocket); + server->ssocket = NULL; + } + + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct + mid_q_entry, + qhead); + if(mid_entry) { + if(mid_entry->midState == MID_REQUEST_SUBMITTED) { + /* Mark other intransit requests as needing retry so + we do not immediately mark the session bad again + (ie after we reconnect below) as they timeout too */ + mid_entry->midState = MID_RETRY_NEEDED; + } + } + } + spin_unlock(&GlobalMid_Lock); + up(&server->tcpSem); + + while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) + { + if(server->protocolType == IPV6) { + rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket); + } else { + rc = ipv4_connect(&server->addr.sockAddr, + &server->ssocket, + server->workstation_RFC1001_name); + } + if(rc) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(3 * HZ); + } else { + atomic_inc(&tcpSesReconnectCount); + spin_lock(&GlobalMid_Lock); + if(server->tcpStatus != CifsExiting) + server->tcpStatus = CifsGood; + spin_unlock(&GlobalMid_Lock); + /* atomic_set(&server->inFlight,0);*/ + wake_up(&server->response_q); + } + } + return rc; +} + +static int +cifs_demultiplex_thread(struct TCP_Server_Info *server) +{ + int length; + unsigned int pdu_length, total_read; + struct smb_hdr *smb_buffer = NULL; + struct msghdr smb_msg; + mm_segment_t temp_fs; + struct iovec iov; + struct socket *csocket = server->ssocket; + struct list_head *tmp; + struct cifsSesInfo *ses; + struct task_struct *task_to_wake = NULL; + struct mid_q_entry *mid_entry; + char *temp; + + daemonize(); + sprintf(current->comm,"cifsd"); + /* allow_signal(SIGKILL);*/ + current->flags |= PF_MEMALLOC; + server->tsk = current; /* save process info to wake at shutdown */ + cFYI(1, ("Demultiplex PID: %d", current->pid)); + + temp_fs = get_fs(); /* we must turn off socket api parm checking */ + set_fs(get_ds()); + + while (server->tcpStatus != CifsExiting) { + if (smb_buffer == NULL) + smb_buffer = cifs_buf_get(); + else + memset(smb_buffer, 0, sizeof (struct smb_hdr)); + + if (smb_buffer == NULL) { + cERROR(1,("Can not get memory for SMB response")); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ * 3); /* give system time to free memory */ + continue; + } + iov.iov_base = smb_buffer; + iov.iov_len = sizeof (struct smb_hdr) - 1; + /* 1 byte less above since wct is not always returned in error cases */ + smb_msg.msg_iov = &iov; + smb_msg.msg_iovlen = 1; + smb_msg.msg_control = NULL; + smb_msg.msg_controllen = 0; + + length = + sock_recvmsg(csocket, &smb_msg, + sizeof (struct smb_hdr) - + 1 /* RFC1001 header and SMB header */ , + MSG_PEEK /* flags see socket.h */ ); + + if(server->tcpStatus == CifsExiting) { + break; + } else if (server->tcpStatus == CifsNeedReconnect) { + cFYI(1,("Reconnecting after server stopped responding")); + cifs_reconnect(server); + cFYI(1,("call to reconnect done")); + csocket = server->ssocket; + continue; + } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); /* minimum sleep to prevent looping + allowing socket to clear and app threads to set + tcpStatus CifsNeedReconnect if server hung */ + continue; + } else if (length <= 0) { + if(server->tcpStatus == CifsNew) { + cFYI(1,("tcp session abended prematurely (after SMBnegprot)")); + /* some servers kill tcp session rather than returning + smb negprot error in which case reconnecting here is + not going to help - return error to mount */ + break; + } + if(length == -EINTR) { + cFYI(1,("cifsd thread killed")); + break; + } + cFYI(1,("Reconnecting after unexpected peek error %d",length)); + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; + } + + pdu_length = 4 + ntohl(smb_buffer->smb_buf_length); + /* Ony read pdu_length after below checks for too short (due + to e.g. int overflow) and too long ie beyond end of buf */ + cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length)); + + temp = (char *) smb_buffer; + if (length > 3) { + if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { + iov.iov_base = smb_buffer; + iov.iov_len = 4; + length = sock_recvmsg(csocket, &smb_msg, 4, 0); + cFYI(0,("Received 4 byte keep alive packet")); + } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) { + iov.iov_base = smb_buffer; + iov.iov_len = 4; + length = sock_recvmsg(csocket, &smb_msg, 4, 0); + cFYI(1,("Good RFC 1002 session rsp")); + } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) + && (length == 5)) { + /* we get this from Windows 98 instead of error on SMB negprot response */ + cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); + if(server->tcpStatus == CifsNew) { + /* if nack on negprot (rather than + ret of smb negprot error) reconnecting + not going to help, ret error to mount */ + break; + } else { + /* give server a second to + clean up before reconnect attempt */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + /* always try 445 first on reconnect + since we get NACK on some if we ever + connected to port 139 (the NACK is + since we do not begin with RFC1001 + session initialize frame) */ + server->addr.sockAddr.sin_port = CIFS_PORT; + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; + } + } else if (temp[0] != (char) 0) { + cERROR(1,("Unknown RFC 1002 frame")); + cifs_dump_mem(" Received Data: ", temp, length); + cifs_reconnect(server); + csocket = server->ssocket; + continue; + } else { + if ((length != sizeof (struct smb_hdr) - 1) + || (pdu_length > + CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) + || (pdu_length < + sizeof (struct smb_hdr) - 1) + || + (checkSMBhdr + (smb_buffer, smb_buffer->Mid))) { + cERROR(1, + ("Invalid size or format for SMB found with length %d and pdu_lenght %d", + length, pdu_length)); + cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + /* could we fix this network corruption by finding next + smb header (instead of killing the session) and + restart reading from next valid SMB found? */ + cifs_reconnect(server); + csocket = server->ssocket; + continue; + } else { /* length ok */ + + length = 0; + iov.iov_base = smb_buffer; + iov.iov_len = pdu_length; + for (total_read = 0; + total_read < pdu_length; + total_read += length) { + length = sock_recvmsg(csocket, &smb_msg, + pdu_length - total_read, 0); + if (length == 0) { + cERROR(1, + ("Zero length receive when expecting %d ", + pdu_length - total_read)); + cifs_reconnect(server); + csocket = server->ssocket; + continue; + } + } + } + + dump_smb(smb_buffer, length); + if (checkSMB + (smb_buffer, smb_buffer->Mid, total_read)) { + cERROR(1, ("Bad SMB Received ")); + continue; + } + + task_to_wake = NULL; + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct + mid_q_entry, + qhead); + + if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) { + cFYI(1, + (" Mid 0x%x matched - waking up ",mid_entry->mid)); + task_to_wake = mid_entry->tsk; + mid_entry->resp_buf = + smb_buffer; + mid_entry->midState = + MID_RESPONSE_RECEIVED; + } + } + spin_unlock(&GlobalMid_Lock); + if (task_to_wake) { + smb_buffer = NULL; /* will be freed by users thread after he is done */ + wake_up_process(task_to_wake); + } else if (is_valid_oplock_break(smb_buffer) == FALSE) { + cERROR(1, ("No task to wake, unknown frame rcvd!")); + cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + } + } + } else { + cFYI(0, + ("Frame less than four bytes received %d bytes long.", + length)); + if (length > 0) { + length = sock_recvmsg(csocket, &smb_msg, length, 0); /* throw away junk frame */ + cFYI(1, + (" with junk 0x%x in it ", + *(__u32 *) smb_buffer)); + } + } + } + spin_lock(&GlobalMid_Lock); + server->tcpStatus = CifsExiting; + server->tsk = NULL; + atomic_set(&server->inFlight, 0); + spin_unlock(&GlobalMid_Lock); + /* Although there should not be any requests blocked on + this queue it can not hurt to be paranoid and try to wake up requests + that may haven been blocked when more than 50 at time were on the wire + to the same server - they now will see the session is in exit state + and get out of SendReceive. */ + wake_up_all(&server->request_q); + /* give those requests time to exit */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/8); + + if(server->ssocket) { + sock_release(csocket); + server->ssocket = NULL; + } + set_fs(temp_fs); + if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ + cifs_buf_release(smb_buffer); + + read_lock(&GlobalSMBSeslock); + if (list_empty(&server->pending_mid_q)) { + /* loop through server session structures attached to this and mark them dead */ + list_for_each(tmp, &GlobalSMBSessionList) { + ses = + list_entry(tmp, struct cifsSesInfo, + cifsSessionList); + if (ses->server == server) { + ses->status = CifsExiting; + ses->server = NULL; + } + } + read_unlock(&GlobalSMBSeslock); + } else { + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct mid_q_entry, qhead); + if (mid_entry->midState == MID_REQUEST_SUBMITTED) { + cFYI(1, + (" Clearing Mid 0x%x - waking up ",mid_entry->mid)); + task_to_wake = mid_entry->tsk; + if(task_to_wake) { + wake_up_process(task_to_wake); + } + } + } + spin_unlock(&GlobalMid_Lock); + read_unlock(&GlobalSMBSeslock); + set_current_state(TASK_INTERRUPTIBLE); + /* 1/8th of sec is more than enough time for them to exit */ + schedule_timeout(HZ/8); + } + + if (list_empty(&server->pending_mid_q)) { + /* mpx threads have not exited yet give them + at least the smb send timeout time for long ops */ + cFYI(1, ("Wait for exit from demultiplex thread")); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(46 * HZ); + /* if threads still have not exited they are probably never + coming home not much else we can do but free the memory */ + } + kfree(server); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/4); + return 0; +} + +static void * +cifs_kcalloc(size_t size, int type) +{ + void *addr; + addr = kmalloc(size, type); + if (addr) + memset(addr, 0, size); + return addr; +} + +static int +cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol) +{ + char *value; + char *data; + unsigned int temp_len, i, j; + char separator[2]; + + separator[0] = ','; + separator[1] = 0; + + memset(vol->source_rfc1001_name,0x20,15); + for(i=0;i < strnlen(system_utsname.nodename,15);i++) { + /* does not have to be a perfect mapping since the field is + informational, only used for servers that do not support + port 445 and it can be overridden at mount time */ + vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]); + } + vol->source_rfc1001_name[15] = 0; + + vol->linux_uid = current->uid; /* current->euid instead? */ + vol->linux_gid = current->gid; + vol->dir_mode = S_IRWXUGO; + /* 2767 perms indicate mandatory locking support */ + vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); + + /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ + vol->rw = TRUE; + + if (!options) + return 1; + + if(strncmp(options,"sep=",4) == 0) { + if(options[4] != 0) { + separator[0] = options[4]; + options += 5; + } else { + cFYI(1,("Null separator not allowed")); + } + } + + while ((data = strsep(&options, separator)) != NULL) { + if (!*data) + continue; + if ((value = strchr(data, '=')) != NULL) + *value++ = '\0'; + if (strnicmp(data, "user", 4) == 0) { + if (!value || !*value) { + printk(KERN_WARNING + "CIFS: invalid or missing username\n"); + return 1; /* needs_arg; */ + } + if (strnlen(value, 200) < 200) { + vol->username = value; + } else { + printk(KERN_WARNING "CIFS: username too long\n"); + return 1; + } + } else if (strnicmp(data, "pass", 4) == 0) { + if (!value || !*value) { + vol->password = NULL; + continue; + } + temp_len = strlen(value); + /* removed password length check, NTLM passwords + can be arbitrarily long */ + + /* if comma in password, the string will be + prematurely null terminated. Commas in password are + specified across the cifs mount interface by a double + comma ie ,, and a comma used as in other cases ie ',' + as a parameter delimiter/separator is single and due + to the strsep above is temporarily zeroed. */ + + /* NB: password legally can have multiple commas and + the only illegal character in a password is null */ + + if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) { + /* reinsert comma */ + value[temp_len] = separator[0]; + temp_len+=2; /* move after the second comma */ + while(value[temp_len] != 0) { + if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) { + /* single comma indicating start of next parm */ + break; + } + temp_len++; + } + if(value[temp_len] == 0) { + options = NULL; + } else { + value[temp_len] = 0; + /* move options to point to start of next parm */ + options = value + temp_len + 1; + } + /* go from value to (value + temp_len) condensing double commas to singles */ + vol->password = cifs_kcalloc(temp_len, GFP_KERNEL); + for(i=0,j=0;ipassword[j] = value[i]; + if(value[i] == separator[0] && value[i+1] == separator[0]) { + /* skip second comma */ + i++; + } + } + /* value[temp_len] is zeroed above so + vol->password[temp_len] guaranteed to be null */ + } else { + vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL); + strcpy(vol->password, value); + } + } else if (strnicmp(data, "ip", 2) == 0) { + if (!value || !*value) { + vol->UNCip = NULL; + } else if (strnlen(value, 35) < 35) { + vol->UNCip = value; + } else { + printk(KERN_WARNING "CIFS: ip address too long\n"); + return 1; + } + } else if ((strnicmp(data, "unc", 3) == 0) + || (strnicmp(data, "target", 6) == 0) + || (strnicmp(data, "path", 4) == 0)) { + if (!value || !*value) { + printk(KERN_WARNING + "CIFS: invalid path to network resource\n"); + return 1; /* needs_arg; */ + } + if ((temp_len = strnlen(value, 300)) < 300) { + vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); + if(vol->UNC == NULL) + return 1; + strcpy(vol->UNC,value); + if (strncmp(vol->UNC, "//", 2) == 0) { + vol->UNC[0] = '\\'; + vol->UNC[1] = '\\'; + } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { + printk(KERN_WARNING + "CIFS: UNC Path does not begin with // or \\\\ \n"); + return 1; + } + } else { + printk(KERN_WARNING "CIFS: UNC name too long\n"); + return 1; + } + } else if ((strnicmp(data, "domain", 3) == 0) + || (strnicmp(data, "workgroup", 5) == 0)) { + if (!value || !*value) { + printk(KERN_WARNING "CIFS: invalid domain name\n"); + return 1; /* needs_arg; */ + } + /* BB are there cases in which a comma can be valid in + a domain name and need special handling? */ + if (strnlen(value, 65) < 65) { + vol->domainname = value; + cFYI(1, ("Domain name set")); + } else { + printk(KERN_WARNING "CIFS: domain name too long\n"); + return 1; + } + } else if (strnicmp(data, "iocharset", 9) == 0) { + if (!value || !*value) { + printk(KERN_WARNING "CIFS: invalid iocharset specified\n"); + return 1; /* needs_arg; */ + } + if (strnlen(value, 65) < 65) { + if(strnicmp(value,"default",7)) + vol->iocharset = value; + /* if iocharset not set load_nls_default used by caller */ + cFYI(1, ("iocharset set to %s",value)); + } else { + printk(KERN_WARNING "CIFS: iocharset name too long.\n"); + return 1; + } + } else if (strnicmp(data, "uid", 3) == 0) { + if (value && *value) { + vol->linux_uid = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "gid", 3) == 0) { + if (value && *value) { + vol->linux_gid = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "file_mode", 4) == 0) { + if (value && *value) { + vol->file_mode = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "dir_mode", 3) == 0) { + if (value && *value) { + vol->dir_mode = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "port", 4) == 0) { + if (value && *value) { + vol->port = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "rsize", 5) == 0) { + if (value && *value) { + vol->rsize = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "wsize", 5) == 0) { + if (value && *value) { + vol->wsize = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "sockopt", 5) == 0) { + if (value && *value) { + vol->sockopt = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "netbiosname", 4) == 0) { + if (!value || !*value || (*value == ' ')) { + cFYI(1,("invalid (empty) netbiosname specified")); + } else { + memset(vol->source_rfc1001_name,0x20,15); + for(i=0;i<15;i++) { + /* BB are there cases in which a comma can be + valid in this workstation netbios name (and need + special handling)? */ + + /* We do not uppercase netbiosname for user */ + if (value[i]==0) + break; + else + vol->source_rfc1001_name[i] = value[i]; + } + /* The string has 16th byte zero still from + set at top of the function */ + if((i==15) && (value[i] != 0)) + printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n"); + } + } else if (strnicmp(data, "credentials", 4) == 0) { + /* ignore */ + } else if (strnicmp(data, "version", 3) == 0) { + /* ignore */ + } else if (strnicmp(data, "rw", 2) == 0) { + vol->rw = TRUE; + } else if ((strnicmp(data, "suid", 4) == 0) || + (strnicmp(data, "nosuid", 6) == 0) || + (strnicmp(data, "exec", 4) == 0) || + (strnicmp(data, "noexec", 6) == 0) || + (strnicmp(data, "nodev", 5) == 0) || + (strnicmp(data, "noauto", 6) == 0) || + (strnicmp(data, "dev", 3) == 0)) { + /* The mount tool or mount.cifs helper (if present) + uses these opts to set flags, and the flags are read + by the kernel vfs layer before we get here (ie + before read super) so there is no point trying to + parse these options again and set anything and it + is ok to just ignore them */ + continue; + } else if (strnicmp(data, "ro", 2) == 0) { + vol->rw = FALSE; + } else if (strnicmp(data, "hard", 4) == 0) { + vol->retry = 1; + } else if (strnicmp(data, "soft", 4) == 0) { + vol->retry = 0; + } else if (strnicmp(data, "nohard", 6) == 0) { + vol->retry = 0; + } else if (strnicmp(data, "nosoft", 6) == 0) { + vol->retry = 1; + } else if (strnicmp(data, "nointr", 6) == 0) { + vol->intr = 0; + } else if (strnicmp(data, "intr", 4) == 0) { + vol->intr = 1; + } else if (strnicmp(data, "noac", 4) == 0) { + printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); + } else + printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); + } + if (vol->UNC == NULL) { + if(devname == NULL) { + printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n"); + return 1; + } + if ((temp_len = strnlen(devname, 300)) < 300) { + vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); + if(vol->UNC == NULL) + return 1; + strcpy(vol->UNC,devname); + if (strncmp(vol->UNC, "//", 2) == 0) { + vol->UNC[0] = '\\'; + vol->UNC[1] = '\\'; + } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { + printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n"); + return 1; + } + } else { + printk(KERN_WARNING "CIFS: UNC name too long\n"); + return 1; + } + } + if(vol->UNCip == 0) + vol->UNCip = &vol->UNC[2]; + + return 0; +} + +static struct cifsSesInfo * +cifs_find_tcp_session(__u32 new_target_ip_addr, + char *userName, struct TCP_Server_Info **psrvTcp) +{ + struct list_head *tmp; + struct cifsSesInfo *ses; + + *psrvTcp = NULL; + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalSMBSessionList) { + ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); + if (ses->server) { + if (ses->server->addr.sockAddr.sin_addr.s_addr == + new_target_ip_addr) { + /* BB lock server and tcp session and increment use count here?? */ + *psrvTcp = ses->server; /* found a match on the TCP session */ + /* BB check if reconnection needed */ + if (strncmp + (ses->userName, userName, + MAX_USERNAME_SIZE) == 0){ + read_unlock(&GlobalSMBSeslock); + return ses; /* found exact match on both tcp and SMB sessions */ + } + } + } + /* else tcp and smb sessions need reconnection */ + } + read_unlock(&GlobalSMBSeslock); + return NULL; +} + +static struct cifsTconInfo * +find_unc(__u32 new_target_ip_addr, char *uncName, char *userName) +{ + struct list_head *tmp; + struct cifsTconInfo *tcon; + + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalTreeConnectionList) { + cFYI(1, ("Next tcon - ")); + tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + if (tcon->ses) { + if (tcon->ses->server) { + cFYI(1, + (" old ip addr: %x == new ip %x ?", + tcon->ses->server->addr.sockAddr.sin_addr. + s_addr, new_target_ip_addr)); + if (tcon->ses->server->addr.sockAddr.sin_addr. + s_addr == new_target_ip_addr) { + /* BB lock tcon and server and tcp session and increment use count here? */ + /* found a match on the TCP session */ + /* BB check if reconnection needed */ + cFYI(1,("Matched ip, old UNC: %s == new: %s ?", + tcon->treeName, uncName)); + if (strncmp + (tcon->treeName, uncName, + MAX_TREE_SIZE) == 0) { + cFYI(1, + ("Matched UNC, old user: %s == new: %s ?", + tcon->treeName, uncName)); + if (strncmp + (tcon->ses->userName, + userName, + MAX_USERNAME_SIZE) == 0) { + read_unlock(&GlobalSMBSeslock); + return tcon;/* also matched user (smb session)*/ + } + } + } + } + } + } + read_unlock(&GlobalSMBSeslock); + return NULL; +} + +int +connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, + const char *old_path, const struct nls_table *nls_codepage) +{ + unsigned char *referrals = NULL; + unsigned int num_referrals; + int rc = 0; + + rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, + &num_referrals, &referrals); + + /* BB Add in code to: if valid refrl, if not ip address contact + the helper that resolves tcp names, mount to it, try to + tcon to it unmount it if fail */ + + if(referrals) + kfree(referrals); + + return rc; +} + +int +get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, + const char *old_path, const struct nls_table *nls_codepage, + unsigned int *pnum_referrals, unsigned char ** preferrals) +{ + char *temp_unc; + int rc = 0; + + *pnum_referrals = 0; + + if (pSesInfo->ipc_tid == 0) { + temp_unc = kmalloc(2 /* for slashes */ + + strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2) + + 1 + 4 /* slash IPC$ */ + 2, + GFP_KERNEL); + if (temp_unc == NULL) + return -ENOMEM; + temp_unc[0] = '\\'; + temp_unc[1] = '\\'; + strcpy(temp_unc + 2, pSesInfo->serverName); + strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$"); + rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage); + cFYI(1, + ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid)); + kfree(temp_unc); + } + if (rc == 0) + rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, + pnum_referrals, nls_codepage); + + return rc; +} + +/* See RFC1001 section 14 on representation of Netbios names */ +static void rfc1002mangle(char * target,char * source, unsigned int length) +{ + unsigned int i,j; + + for(i=0,j=0;i<(length);i++) { + /* mask a nibble at a time and encode */ + target[j] = 'A' + (0x0F & (source[i] >> 4)); + target[j+1] = 'A' + (0x0F & source[i]); + j+=2; + } + +} + + +static int +ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, + char * netbios_name) +{ + int rc = 0; + int connected = 0; + unsigned short int orig_port = 0; + + if(*csocket == NULL) { + rc = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket); + if (rc < 0) { + cERROR(1, ("Error %d creating socket",rc)); + *csocket = NULL; + return rc; + } else { + /* BB other socket options to set KEEPALIVE, NODELAY? */ + cFYI(1,("Socket created")); + (*csocket)->sk->allocation = GFP_NOFS; + } + } + + psin_server->sin_family = AF_INET; + if(psin_server->sin_port) { /* user overrode default port */ + rc = (*csocket)->ops->connect(*csocket, + (struct sockaddr *) psin_server, + sizeof (struct sockaddr_in),0); + if (rc >= 0) + connected = 1; + } + + if(!connected) { + /* save original port so we can retry user specified port + later if fall back ports fail this time */ + orig_port = psin_server->sin_port; + + /* do not retry on the same port we just failed on */ + if(psin_server->sin_port != htons(CIFS_PORT)) { + psin_server->sin_port = htons(CIFS_PORT); + + rc = (*csocket)->ops->connect(*csocket, + (struct sockaddr *) psin_server, + sizeof (struct sockaddr_in),0); + if (rc >= 0) + connected = 1; + } + } + if (!connected) { + psin_server->sin_port = htons(RFC1001_PORT); + rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) + psin_server, sizeof (struct sockaddr_in),0); + if (rc >= 0) + connected = 1; + } + + /* give up here - unless we want to retry on different + protocol families some day */ + if (!connected) { + if(orig_port) + psin_server->sin_port = orig_port; + cFYI(1,("Error %d connecting to server via ipv4",rc)); + sock_release(*csocket); + *csocket = NULL; + return rc; + } + /* Eventually check for other socket options to change from + the default. sock_setsockopt not used because it expects + user space buffer */ + (*csocket)->sk->rcvtimeo = 7 * HZ; + + /* send RFC1001 sessinit */ + + if(psin_server->sin_port == htons(139)) { + /* some servers require RFC1001 sessinit before sending + negprot - BB check reconnection in case where second + sessinit is sent but no second negprot */ + struct rfc1002_session_packet * ses_init_buf; + struct smb_hdr * smb_buf; + ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); + if(ses_init_buf) { + ses_init_buf->trailer.session_req.called_len = 32; + rfc1002mangle(ses_init_buf->trailer.session_req.called_name, + DEFAULT_CIFS_CALLED_NAME,16); + ses_init_buf->trailer.session_req.calling_len = 32; + /* calling name ends in null (byte 16) from old smb + convention. */ + if(netbios_name && (netbios_name[0] !=0)) { + rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, + netbios_name,16); + } else { + rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, + "LINUX_CIFS_CLNT",16); + } + ses_init_buf->trailer.session_req.scope1 = 0; + ses_init_buf->trailer.session_req.scope2 = 0; + smb_buf = (struct smb_hdr *)ses_init_buf; + /* sizeof RFC1002_SESSION_REQUEST with no scope */ + smb_buf->smb_buf_length = 0x81000044; + rc = smb_send(*csocket, smb_buf, 0x44, + (struct sockaddr *)psin_server); + kfree(ses_init_buf); + } + /* else the negprot may still work without this + even though malloc failed */ + + } + + return rc; +} + +static int +ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) +{ + int rc = 0; + int connected = 0; + + if(*csocket == NULL) { + rc = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket); + if (rc < 0) { + cERROR(1, ("Error %d creating ipv6 socket",rc)); + *csocket = NULL; + return rc; + } else { + /* BB other socket options to set KEEPALIVE, NODELAY? */ + cFYI(1,("ipv6 Socket created")); + (*csocket)->sk->allocation = GFP_NOFS; + } + } + + psin_server->sin6_family = AF_INET6; + + if(psin_server->sin6_port) { /* user overrode default port */ + rc = (*csocket)->ops->connect(*csocket, + (struct sockaddr *) psin_server, + sizeof (struct sockaddr_in6),0); + if (rc >= 0) + connected = 1; + } + + if(!connected) { + /* do not retry on the same port we just failed on */ + if(psin_server->sin6_port != htons(CIFS_PORT)) { + psin_server->sin6_port = htons(CIFS_PORT); + + rc = (*csocket)->ops->connect(*csocket, + (struct sockaddr *) psin_server, + sizeof (struct sockaddr_in6),0); + if (rc >= 0) + connected = 1; + } + } + if (!connected) { + psin_server->sin6_port = htons(RFC1001_PORT); + rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) + psin_server, sizeof (struct sockaddr_in6),0); + if (rc >= 0) + connected = 1; + } + + /* give up here - unless we want to retry on different + protocol families some day */ + if (!connected) { + cFYI(1,("Error %d connecting to server via ipv6",rc)); + sock_release(*csocket); + *csocket = NULL; + return rc; + } + /* Eventually check for other socket options to change from + the default. sock_setsockopt not used because it expects + user space buffer */ + (*csocket)->sk->rcvtimeo = 7 * HZ; + + return rc; +} + +int +cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, + char *mount_data, const char *devname) +{ + int rc = 0; + int xid; + struct socket *csocket = NULL; + struct sockaddr_in sin_server; + struct sockaddr_in6 sin_server6; + struct smb_vol volume_info; + struct cifsSesInfo *pSesInfo = NULL; + struct cifsSesInfo *existingCifsSes = NULL; + struct cifsTconInfo *tcon = NULL; + struct TCP_Server_Info *srvTcp = NULL; + + xid = GetXid(); + + cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); /* BB removeme BB fixme */ + + memset(&volume_info,0,sizeof(struct smb_vol)); + if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } + + if (volume_info.username) { + cFYI(1, ("Username: %s ", volume_info.username)); + + } else { + cifserror("No username specified "); + /* In userspace mount helper we can get user name from alternate + locations such as env variables and files on disk */ + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } + + if (volume_info.UNCip && volume_info.UNC) { + rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr); + + if(rc == 0) { + /* not ipv4 address, try ipv6 */ + rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); + } + + if(rc != 1) { + /* we failed translating address */ + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } + + cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); + /* success */ + rc = 0; + } else if (volume_info.UNCip){ + /* BB using ip addr as server name connect to the DFS root below */ + cERROR(1,("Connecting to DFS root not implemented yet")); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } else /* which servers DFS root would we conect to */ { + cERROR(1, + ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } + + /* this is needed for ASCII cp to Unicode converts */ + if(volume_info.iocharset == NULL) { + cifs_sb->local_nls = load_nls_default(); + /* load_nls_default can not return null */ + } else { + cifs_sb->local_nls = load_nls(volume_info.iocharset); + if(cifs_sb->local_nls == NULL) { + cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -ELIBACC; + } + } + + existingCifsSes = + cifs_find_tcp_session(sin_server.sin_addr.s_addr, + volume_info.username, &srvTcp); + if (srvTcp) { + cFYI(1, ("Existing tcp session with server found ")); + } else { /* create socket */ + if(volume_info.port) + sin_server.sin_port = htons(volume_info.port); + else + sin_server.sin_port = 0; + rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name); + if (rc < 0) { + cERROR(1, + ("Error connecting to IPv4 socket. Aborting operation")); + if(csocket != NULL) + sock_release(csocket); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return rc; + } + + srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL); + if (srvTcp == NULL) { + rc = -ENOMEM; + sock_release(csocket); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return rc; + } else { + memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); + memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in)); + atomic_set(&srvTcp->inFlight,0); + /* BB Add code for ipv6 case too */ + srvTcp->ssocket = csocket; + srvTcp->protocolType = IPV4; + init_waitqueue_head(&srvTcp->response_q); + init_waitqueue_head(&srvTcp->request_q); + INIT_LIST_HEAD(&srvTcp->pending_mid_q); + /* at this point we are the only ones with the pointer + to the struct since the kernel thread not created yet + so no need to spinlock this init of tcpStatus */ + srvTcp->tcpStatus = CifsNew; + init_MUTEX(&srvTcp->tcpSem); + kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp, + CLONE_FS | CLONE_FILES | CLONE_VM); + memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); + } + } + + if (existingCifsSes) { + pSesInfo = existingCifsSes; + cFYI(1, ("Existing smb sess found ")); + if(volume_info.password) + kfree(volume_info.password); + /* volume_info.UNC freed at end of function */ + } else if (!rc) { + cFYI(1, ("Existing smb sess not found ")); + pSesInfo = sesInfoAlloc(); + if (pSesInfo == NULL) + rc = -ENOMEM; + else { + pSesInfo->server = srvTcp; + sprintf(pSesInfo->serverName, "%u.%u.%u.%u", + NIPQUAD(sin_server.sin_addr.s_addr)); + } + + if (!rc){ + /* volume_info.password freed at unmount */ + if (volume_info.password) + pSesInfo->password = volume_info.password; + if (volume_info.username) + strncpy(pSesInfo->userName, + volume_info.username,MAX_USERNAME_SIZE); + if (volume_info.domainname) + strncpy(pSesInfo->domainName, + volume_info.domainname,MAX_USERNAME_SIZE); + pSesInfo->linux_uid = volume_info.linux_uid; + down(&pSesInfo->sesSem); + rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); + up(&pSesInfo->sesSem); + if(!rc) + atomic_inc(&srvTcp->socketUseCount); + } else + if(volume_info.password) + kfree(volume_info.password); + } + + /* search for existing tcon to this server share */ + if (!rc) { + if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf)) + cifs_sb->rsize = volume_info.rsize; + else + cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ + if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf)) + cifs_sb->wsize = volume_info.wsize; + else + cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ + if(cifs_sb->rsize < PAGE_CACHE_SIZE) { + cifs_sb->rsize = PAGE_CACHE_SIZE; + cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); + } + cifs_sb->mnt_uid = volume_info.linux_uid; + cifs_sb->mnt_gid = volume_info.linux_gid; + cifs_sb->mnt_file_mode = volume_info.file_mode; + cifs_sb->mnt_dir_mode = volume_info.dir_mode; + cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); + tcon = + find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, + volume_info.username); + if (tcon) { + cFYI(1, ("Found match on UNC path ")); + /* we can have only one retry value for a connection + to a share so for resources mounted more than once + to the same server share the last value passed in + for the retry flag is used */ + tcon->retry = volume_info.retry; + } else { + tcon = tconInfoAlloc(); + if (tcon == NULL) + rc = -ENOMEM; + else { + /* check for null share name ie connect to dfs root */ + + /* BB check if this works for exactly length three strings */ + if ((strchr(volume_info.UNC + 3, '\\') == NULL) + && (strchr(volume_info.UNC + 3, '/') == + NULL)) { + rc = connect_to_dfs_path(xid, + pSesInfo, + "", + cifs_sb-> + local_nls); + if(volume_info.UNC) + kfree(volume_info.UNC); + FreeXid(xid); + return -ENODEV; + } else { + rc = CIFSTCon(xid, pSesInfo, + volume_info.UNC, + tcon, cifs_sb->local_nls); + cFYI(1, ("CIFS Tcon rc = %d", rc)); + } + if (!rc) { + atomic_inc(&pSesInfo->inUse); + tcon->retry = volume_info.retry; + } + } + } + } + if(pSesInfo) { + if (pSesInfo->capabilities & CAP_LARGE_FILES) { + sb->s_maxbytes = (u64) 1 << 63; + } else + sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */ + } + +/* on error free sesinfo and tcon struct if needed */ + if (rc) { + /* if session setup failed, use count is zero but + we still need to free cifsd thread */ + if(atomic_read(&srvTcp->socketUseCount) == 0) { + spin_lock(&GlobalMid_Lock); + srvTcp->tcpStatus = CifsExiting; + spin_unlock(&GlobalMid_Lock); + if(srvTcp->tsk) + send_sig(SIGKILL,srvTcp->tsk,1); + } + /* If find_unc succeeded then rc == 0 so we can not end */ + if (tcon) /* up accidently freeing someone elses tcon struct */ + tconInfoFree(tcon); + if (existingCifsSes == 0) { + if (pSesInfo) { + if ((pSesInfo->server) && + (pSesInfo->status == CifsGood)) { + int temp_rc; + temp_rc = CIFSSMBLogoff(xid, pSesInfo); + /* if the socketUseCount is now zero */ + if((temp_rc == -ESHUTDOWN) && + (pSesInfo->server->tsk)) + send_sig(SIGKILL,pSesInfo->server->tsk,1); + } else + cFYI(1, ("No session or bad tcon")); + sesInfoFree(pSesInfo); + /* pSesInfo = NULL; */ + } + } + } else { + atomic_inc(&tcon->useCount); + cifs_sb->tcon = tcon; + tcon->ses = pSesInfo; + + /* do not care if following two calls succeed - informational only */ + CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls); + CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls); + if (tcon->ses->capabilities & CAP_UNIX) + CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls); + } + + /* volume_info.password is freed above when existing session found + (in which case it is not needed anymore) but when new sesion is created + the password ptr is put in the new session structure (in which case the + password will be freed at unmount time) */ + if(volume_info.UNC) + kfree(volume_info.UNC); + FreeXid(xid); + return rc; +} + +static int +CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, + char session_key[CIFS_SESSION_KEY_SIZE], + const struct nls_table *nls_codepage) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + SESSION_SETUP_ANDX *pSMB; + SESSION_SETUP_ANDX *pSMBr; + char *bcc_ptr; + char *user = ses->userName; + char *domain = ses->domainName; + int rc = 0; + int remaining_words = 0; + int bytes_returned = 0; + int len; + + cFYI(1, ("In sesssetup ")); + + smb_buffer = cifs_buf_get(); + if (smb_buffer == 0) { + return -ENOMEM; + } + smb_buffer_response = smb_buffer; + pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; + + /* send SMBsessionSetup here */ + header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, + NULL /* no tCon exists yet */ , 13 /* wct */ ); + + pSMB->req_no_secext.AndXCommand = 0xFF; + pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); + pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + pSMB->req_no_secext.Capabilities = + CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS; + if (ses->capabilities & CAP_UNICODE) { + smb_buffer->Flags2 |= SMBFLG2_UNICODE; + pSMB->req_no_secext.Capabilities |= CAP_UNICODE; + } + if (ses->capabilities & CAP_STATUS32) { + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; + pSMB->req_no_secext.Capabilities |= CAP_STATUS32; + } + if (ses->capabilities & CAP_DFS) { + smb_buffer->Flags2 |= SMBFLG2_DFS; + pSMB->req_no_secext.Capabilities |= CAP_DFS; + } + pSMB->req_no_secext.Capabilities = + cpu_to_le32(pSMB->req_no_secext.Capabilities); + /* pSMB->req_no_secext.CaseInsensitivePasswordLength = + CIFS_SESSION_KEY_SIZE; */ + pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; + pSMB->req_no_secext.CaseSensitivePasswordLength = + cpu_to_le16(CIFS_SESSION_KEY_SIZE); + bcc_ptr = pByteArea(smb_buffer); + /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE); + bcc_ptr += CIFS_SESSION_KEY_SIZE; */ + memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); + bcc_ptr += CIFS_SESSION_KEY_SIZE; + + if (ses->capabilities & CAP_UNICODE) { + if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ + *bcc_ptr = 0; + bcc_ptr++; + } + if(user == NULL) + bytes_returned = 0; /* skill null user */ + else + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, + nls_codepage); + bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */ + bcc_ptr += 2; /* trailing null */ + if (domain == NULL) + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, + "CIFS_LINUX_DOM", 32, nls_codepage); + else + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + 32, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + 64, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + } else { + if(user != NULL) { + strncpy(bcc_ptr, user, 200); + bcc_ptr += strnlen(user, 200); + } + *bcc_ptr = 0; + bcc_ptr++; + if (domain == NULL) { + strcpy(bcc_ptr, "CIFS_LINUX_DOM"); + bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; + } else { + strncpy(bcc_ptr, domain, 64); + bcc_ptr += strnlen(domain, 64); + *bcc_ptr = 0; + bcc_ptr++; + } + strcpy(bcc_ptr, "Linux version "); + bcc_ptr += strlen("Linux version "); + strcpy(bcc_ptr, UTS_RELEASE); + bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); + bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; + } + BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += BCC(smb_buffer); + BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, + &bytes_returned, 1); + if (rc) { +/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ + } else if ((smb_buffer_response->WordCount == 3) + || (smb_buffer_response->WordCount == 4)) { + pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); + if (pSMBr->resp.Action & GUEST_LOGIN) + cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */ + if (ses) { + ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ + cFYI(1, ("UID = %d ", ses->Suid)); + /* response can have either 3 or 4 word count - Samba sends 3 */ + bcc_ptr = pByteArea(smb_buffer_response); + if ((pSMBr->resp.hdr.WordCount == 3) + || ((pSMBr->resp.hdr.WordCount == 4) + && (pSMBr->resp.SecurityBlobLength < + pSMBr->resp.ByteCount))) { + if (pSMBr->resp.hdr.WordCount == 4) + bcc_ptr += + pSMBr->resp.SecurityBlobLength; + + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if ((long) (bcc_ptr) % 2) { + remaining_words = + (BCC(smb_buffer_response) + - 1) / 2; + bcc_ptr++; /* Unicode strings must be word aligned */ + } else { + remaining_words = + BCC + (smb_buffer_response) / 2; + } + len = + UniStrnlen((wchar_t *) bcc_ptr, + remaining_words - 1); +/* We look for obvious messed up bcc or strings in response so we do not go off + the end since (at least) WIN2K and Windows XP have a major bug in not null + terminating last Unicode string in response */ + ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_strfromUCS_le(ses->serverOS, + (wchar_t *)bcc_ptr, len,nls_codepage); + bcc_ptr += 2 * (len + 1); + remaining_words -= len + 1; + ses->serverOS[2 * len] = 0; + ses->serverOS[1 + (2 * len)] = 0; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *)bcc_ptr, + remaining_words + - 1); + ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL); + cifs_strfromUCS_le(ses->serverNOS, + (wchar_t *)bcc_ptr,len,nls_codepage); + bcc_ptr += 2 * (len + 1); + ses->serverNOS[2 * len] = 0; + ses->serverNOS[1 + (2 * len)] = 0; + remaining_words -= len + 1; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); + /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ + ses->serverDomain = + cifs_kcalloc(2*(len+1),GFP_KERNEL); + cifs_strfromUCS_le(ses->serverDomain, + (wchar_t *)bcc_ptr,len,nls_codepage); + bcc_ptr += 2 * (len + 1); + ses->serverDomain[2*len] = 0; + ses->serverDomain[1+(2*len)] = 0; + } /* else no more room so create dummy domain string */ + else + ses->serverDomain = + cifs_kcalloc(2, + GFP_KERNEL); + } else { /* no room so create dummy domain and NOS string */ + ses->serverDomain = + cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = + cifs_kcalloc(2, GFP_KERNEL); + } + } else { /* ASCII */ + len = strnlen(bcc_ptr, 1024); + if (((long) bcc_ptr + len) - (long) + pByteArea(smb_buffer_response) + <= BCC(smb_buffer_response)) { + ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); + strncpy(ses->serverOS,bcc_ptr, len); + + bcc_ptr += len; + bcc_ptr[0] = 0; /* null terminate the string */ + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); + strncpy(ses->serverNOS, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL); + strncpy(ses->serverDomain, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + } else + cFYI(1, + ("Variable field of length %d extends beyond end of smb ", + len)); + } + } else { + cERROR(1, + (" Security Blob Length extends beyond end of SMB")); + } + } else { + cERROR(1, ("No session structure passed in.")); + } + } else { + cERROR(1, + (" Invalid Word count %d: ", + smb_buffer_response->WordCount)); + rc = -EIO; + } + + if (smb_buffer) + cifs_buf_release(smb_buffer); + + return rc; +} + +static int +CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, + char *SecurityBlob,int SecurityBlobLength, + const struct nls_table *nls_codepage) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + SESSION_SETUP_ANDX *pSMB; + SESSION_SETUP_ANDX *pSMBr; + char *bcc_ptr; + char *user = ses->userName; + char *domain = ses->domainName; + int rc = 0; + int remaining_words = 0; + int bytes_returned = 0; + int len; + + cFYI(1, ("In spnego sesssetup ")); + + smb_buffer = cifs_buf_get(); + if (smb_buffer == 0) { + return -ENOMEM; + } + smb_buffer_response = smb_buffer; + pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; + + /* send SMBsessionSetup here */ + header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, + NULL /* no tCon exists yet */ , 12 /* wct */ ); + pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; + pSMB->req.AndXCommand = 0xFF; + pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); + pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + pSMB->req.Capabilities = + CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | + CAP_EXTENDED_SECURITY; + if (ses->capabilities & CAP_UNICODE) { + smb_buffer->Flags2 |= SMBFLG2_UNICODE; + pSMB->req.Capabilities |= CAP_UNICODE; + } + if (ses->capabilities & CAP_STATUS32) { + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; + pSMB->req.Capabilities |= CAP_STATUS32; + } + if (ses->capabilities & CAP_DFS) { + smb_buffer->Flags2 |= SMBFLG2_DFS; + pSMB->req.Capabilities |= CAP_DFS; + } + pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); + + pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); + bcc_ptr = pByteArea(smb_buffer); + memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength); + bcc_ptr += SecurityBlobLength; + + if (ses->capabilities & CAP_UNICODE) { + if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */ + *bcc_ptr = 0; + bcc_ptr++; + } + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); + bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */ + bcc_ptr += 2; /* trailing null */ + if (domain == NULL) + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, + "CIFS_LINUX_DOM", 32, nls_codepage); + else + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + 32, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + 64, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + } else { + strncpy(bcc_ptr, user, 200); + bcc_ptr += strnlen(user, 200); + *bcc_ptr = 0; + bcc_ptr++; + if (domain == NULL) { + strcpy(bcc_ptr, "CIFS_LINUX_DOM"); + bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; + } else { + strncpy(bcc_ptr, domain, 64); + bcc_ptr += strnlen(domain, 64); + *bcc_ptr = 0; + bcc_ptr++; + } + strcpy(bcc_ptr, "Linux version "); + bcc_ptr += strlen("Linux version "); + strcpy(bcc_ptr, UTS_RELEASE); + bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); + bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; + } + BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += BCC(smb_buffer); + BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, + &bytes_returned, 1); + if (rc) { +/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ + } else if ((smb_buffer_response->WordCount == 3) + || (smb_buffer_response->WordCount == 4)) { + pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); + pSMBr->resp.SecurityBlobLength = + le16_to_cpu(pSMBr->resp.SecurityBlobLength); + if (pSMBr->resp.Action & GUEST_LOGIN) + cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ + if (ses) { + ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ + cFYI(1, ("UID = %d ", ses->Suid)); + bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */ + + /* BB Fix below to make endian neutral !! */ + + if ((pSMBr->resp.hdr.WordCount == 3) + || ((pSMBr->resp.hdr.WordCount == 4) + && (pSMBr->resp.SecurityBlobLength < + pSMBr->resp.ByteCount))) { + if (pSMBr->resp.hdr.WordCount == 4) { + bcc_ptr += + pSMBr->resp.SecurityBlobLength; + cFYI(1, + ("Security Blob Length %d ", + pSMBr->resp.SecurityBlobLength)); + } + + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if ((long) (bcc_ptr) % 2) { + remaining_words = + (BCC(smb_buffer_response) + - 1) / 2; + bcc_ptr++; /* Unicode strings must be word aligned */ + } else { + remaining_words = + BCC + (smb_buffer_response) / 2; + } + len = + UniStrnlen((wchar_t *) bcc_ptr, + remaining_words - 1); +/* We look for obvious messed up bcc or strings in response so we do not go off + the end since (at least) WIN2K and Windows XP have a major bug in not null + terminating last Unicode string in response */ + ses->serverOS = + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_strfromUCS_le(ses->serverOS, + (wchar_t *) + bcc_ptr, len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + remaining_words -= len + 1; + ses->serverOS[2 * len] = 0; + ses->serverOS[1 + (2 * len)] = 0; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *)bcc_ptr, + remaining_words + - 1); + ses->serverNOS = + cifs_kcalloc(2 * (len + 1), + GFP_KERNEL); + cifs_strfromUCS_le(ses->serverNOS, + (wchar_t *)bcc_ptr, + len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + ses->serverNOS[2 * len] = 0; + ses->serverNOS[1 + (2 * len)] = 0; + remaining_words -= len + 1; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); + /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ + ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL); + cifs_strfromUCS_le(ses->serverDomain, + (wchar_t *)bcc_ptr, + len, + nls_codepage); + bcc_ptr += 2*(len+1); + ses->serverDomain[2*len] = 0; + ses->serverDomain[1+(2*len)] = 0; + } /* else no more room so create dummy domain string */ + else + ses->serverDomain = + cifs_kcalloc(2,GFP_KERNEL); + } else { /* no room so create dummy domain and NOS string */ + ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); + } + } else { /* ASCII */ + + len = strnlen(bcc_ptr, 1024); + if (((long) bcc_ptr + len) - (long) + pByteArea(smb_buffer_response) + <= BCC(smb_buffer_response)) { + ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL); + strncpy(ses->serverOS, bcc_ptr, len); + + bcc_ptr += len; + bcc_ptr[0] = 0; /* null terminate the string */ + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); + strncpy(ses->serverNOS, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL); + strncpy(ses->serverDomain, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + } else + cFYI(1, + ("Variable field of length %d extends beyond end of smb ", + len)); + } + } else { + cERROR(1, + (" Security Blob Length extends beyond end of SMB")); + } + } else { + cERROR(1, ("No session structure passed in.")); + } + } else { + cERROR(1, + (" Invalid Word count %d: ", + smb_buffer_response->WordCount)); + rc = -EIO; + } + + if (smb_buffer) + cifs_buf_release(smb_buffer); + + return rc; +} + +static int +CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, + struct cifsSesInfo *ses, int * pNTLMv2_flag, + const struct nls_table *nls_codepage) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + SESSION_SETUP_ANDX *pSMB; + SESSION_SETUP_ANDX *pSMBr; + char *bcc_ptr; + char *domain = ses->domainName; + int rc = 0; + int remaining_words = 0; + int bytes_returned = 0; + int len; + int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE); + PNEGOTIATE_MESSAGE SecurityBlob; + PCHALLENGE_MESSAGE SecurityBlob2; + + cFYI(1, ("In NTLMSSP sesssetup (negotiate) ")); + *pNTLMv2_flag = FALSE; + smb_buffer = cifs_buf_get(); + if (smb_buffer == 0) { + return -ENOMEM; + } + smb_buffer_response = smb_buffer; + pSMB = (SESSION_SETUP_ANDX *) smb_buffer; + pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; + + /* send SMBsessionSetup here */ + header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, + NULL /* no tCon exists yet */ , 12 /* wct */ ); + pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; + pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); + + pSMB->req.AndXCommand = 0xFF; + pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); + pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + pSMB->req.Capabilities = + CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | + CAP_EXTENDED_SECURITY; + if (ses->capabilities & CAP_UNICODE) { + smb_buffer->Flags2 |= SMBFLG2_UNICODE; + pSMB->req.Capabilities |= CAP_UNICODE; + } + if (ses->capabilities & CAP_STATUS32) { + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; + pSMB->req.Capabilities |= CAP_STATUS32; + } + if (ses->capabilities & CAP_DFS) { + smb_buffer->Flags2 |= SMBFLG2_DFS; + pSMB->req.Capabilities |= CAP_DFS; + } + pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); + + bcc_ptr = (char *) &pSMB->req.SecurityBlob; + SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr; + strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); + SecurityBlob->MessageType = NtLmNegotiate; + SecurityBlob->NegotiateFlags = + NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | + NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 | + /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; + if(sign_CIFS_PDUs) + SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN; + if(ntlmv2_support) + SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; + /* setup pointers to domain name and workstation name */ + bcc_ptr += SecurityBlobLength; + + SecurityBlob->WorkstationName.Buffer = 0; + SecurityBlob->WorkstationName.Length = 0; + SecurityBlob->WorkstationName.MaximumLength = 0; + + if (domain == NULL) { + SecurityBlob->DomainName.Buffer = 0; + SecurityBlob->DomainName.Length = 0; + SecurityBlob->DomainName.MaximumLength = 0; + } else { + SecurityBlob->NegotiateFlags |= + NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; + strncpy(bcc_ptr, domain, 63); + SecurityBlob->DomainName.Length = strnlen(domain, 64); + SecurityBlob->DomainName.MaximumLength = + cpu_to_le16(SecurityBlob->DomainName.Length); + SecurityBlob->DomainName.Buffer = + cpu_to_le32((long) &SecurityBlob-> + DomainString - + (long) &SecurityBlob->Signature); + bcc_ptr += SecurityBlob->DomainName.Length; + SecurityBlobLength += SecurityBlob->DomainName.Length; + SecurityBlob->DomainName.Length = + cpu_to_le16(SecurityBlob->DomainName.Length); + } + if (ses->capabilities & CAP_UNICODE) { + if ((long) bcc_ptr % 2) { + *bcc_ptr = 0; + bcc_ptr++; + } + + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + 32, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; /* null terminate Linux version */ + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + 64, nls_codepage); + bcc_ptr += 2 * bytes_returned; + *(bcc_ptr + 1) = 0; + *(bcc_ptr + 2) = 0; + bcc_ptr += 2; /* null terminate network opsys string */ + *(bcc_ptr + 1) = 0; + *(bcc_ptr + 2) = 0; + bcc_ptr += 2; /* null domain */ + } else { /* ASCII */ + strcpy(bcc_ptr, "Linux version "); + bcc_ptr += strlen("Linux version "); + strcpy(bcc_ptr, UTS_RELEASE); + bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); + bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; + bcc_ptr++; /* empty domain field */ + *bcc_ptr = 0; + } + SecurityBlob->NegotiateFlags = + cpu_to_le32(SecurityBlob->NegotiateFlags); + pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); + BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += BCC(smb_buffer); + BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, + &bytes_returned, 1); + + if (smb_buffer_response->Status.CifsError == + (NT_STATUS_MORE_PROCESSING_REQUIRED)) + rc = 0; + + if (rc) { +/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ + } else if ((smb_buffer_response->WordCount == 3) + || (smb_buffer_response->WordCount == 4)) { + pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); + pSMBr->resp.SecurityBlobLength = + le16_to_cpu(pSMBr->resp.SecurityBlobLength); + if (pSMBr->resp.Action & GUEST_LOGIN) + cFYI(1, (" Guest login")); + /* Do we want to set anything in SesInfo struct when guest login? */ + + bcc_ptr = pByteArea(smb_buffer_response); + /* response can have either 3 or 4 word count - Samba sends 3 */ + + SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; + if (SecurityBlob2->MessageType != NtLmChallenge) { + cFYI(1, + ("Unexpected NTLMSSP message type received %d", + SecurityBlob2->MessageType)); + } else if (ses) { + ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ + cFYI(1, ("UID = %d ", ses->Suid)); + if ((pSMBr->resp.hdr.WordCount == 3) + || ((pSMBr->resp.hdr.WordCount == 4) + && (pSMBr->resp.SecurityBlobLength < + pSMBr->resp.ByteCount))) { + if (pSMBr->resp.hdr.WordCount == 4) { + bcc_ptr += + pSMBr->resp.SecurityBlobLength; + cFYI(1, + ("Security Blob Length %d ", + pSMBr->resp.SecurityBlobLength)); + } + + cFYI(1, ("NTLMSSP Challenge rcvd ")); + + memcpy(ses->server->cryptKey, + SecurityBlob2->Challenge, + CIFS_CRYPTO_KEY_SIZE); + if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2) + *pNTLMv2_flag = TRUE; + + if((SecurityBlob2->NegotiateFlags & + NTLMSSP_NEGOTIATE_ALWAYS_SIGN) + || (sign_CIFS_PDUs > 1)) + ses->server->secMode |= + SECMODE_SIGN_REQUIRED; + if ((SecurityBlob2->NegotiateFlags & + NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs)) + ses->server->secMode |= + SECMODE_SIGN_ENABLED; + + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if ((long) (bcc_ptr) % 2) { + remaining_words = + (BCC(smb_buffer_response) + - 1) / 2; + bcc_ptr++; /* Unicode strings must be word aligned */ + } else { + remaining_words = + BCC + (smb_buffer_response) / 2; + } + len = + UniStrnlen((wchar_t *) bcc_ptr, + remaining_words - 1); +/* We look for obvious messed up bcc or strings in response so we do not go off + the end since (at least) WIN2K and Windows XP have a major bug in not null + terminating last Unicode string in response */ + ses->serverOS = + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_strfromUCS_le(ses->serverOS, + (wchar_t *) + bcc_ptr, len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + remaining_words -= len + 1; + ses->serverOS[2 * len] = 0; + ses->serverOS[1 + (2 * len)] = 0; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) + bcc_ptr, + remaining_words + - 1); + ses->serverNOS = + cifs_kcalloc(2 * (len + 1), + GFP_KERNEL); + cifs_strfromUCS_le(ses-> + serverNOS, + (wchar_t *) + bcc_ptr, + len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + ses->serverNOS[2 * len] = 0; + ses->serverNOS[1 + + (2 * len)] = 0; + remaining_words -= len + 1; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); + /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ + ses->serverDomain = + cifs_kcalloc(2 * + (len + + 1), + GFP_KERNEL); + cifs_strfromUCS_le + (ses-> + serverDomain, + (wchar_t *) + bcc_ptr, len, + nls_codepage); + bcc_ptr += + 2 * (len + 1); + ses-> + serverDomain[2 + * len] + = 0; + ses-> + serverDomain[1 + + + (2 + * + len)] + = 0; + } /* else no more room so create dummy domain string */ + else + ses->serverDomain = + cifs_kcalloc(2, + GFP_KERNEL); + } else { /* no room so create dummy domain and NOS string */ + ses->serverDomain = + cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = + cifs_kcalloc(2, GFP_KERNEL); + } + } else { /* ASCII */ + len = strnlen(bcc_ptr, 1024); + if (((long) bcc_ptr + len) - (long) + pByteArea(smb_buffer_response) + <= BCC(smb_buffer_response)) { + ses->serverOS = + cifs_kcalloc(len + 1, + GFP_KERNEL); + strncpy(ses->serverOS, + bcc_ptr, len); + + bcc_ptr += len; + bcc_ptr[0] = 0; /* null terminate string */ + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverNOS = + cifs_kcalloc(len + 1, + GFP_KERNEL); + strncpy(ses->serverNOS, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverDomain = + cifs_kcalloc(len + 1, + GFP_KERNEL); + strncpy(ses->serverDomain, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + } else + cFYI(1, + ("Variable field of length %d extends beyond end of smb ", + len)); + } + } else { + cERROR(1, + (" Security Blob Length extends beyond end of SMB")); + } + } else { + cERROR(1, ("No session structure passed in.")); + } + } else { + cERROR(1, + (" Invalid Word count %d: ", + smb_buffer_response->WordCount)); + rc = -EIO; + } + + if (smb_buffer) + cifs_buf_release(smb_buffer); + + return rc; +} + +static int +CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, + char *ntlm_session_key, int ntlmv2_flag, + const struct nls_table *nls_codepage) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + SESSION_SETUP_ANDX *pSMB; + SESSION_SETUP_ANDX *pSMBr; + char *bcc_ptr; + char *user = ses->userName; + char *domain = ses->domainName; + int rc = 0; + int remaining_words = 0; + int bytes_returned = 0; + int len; + int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE); + PAUTHENTICATE_MESSAGE SecurityBlob; + + cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); + + smb_buffer = cifs_buf_get(); + if (smb_buffer == 0) { + return -ENOMEM; + } + smb_buffer_response = smb_buffer; + pSMB = (SESSION_SETUP_ANDX *) smb_buffer; + pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; + + /* send SMBsessionSetup here */ + header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, + NULL /* no tCon exists yet */ , 12 /* wct */ ); + pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); + pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; + pSMB->req.AndXCommand = 0xFF; + pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); + pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); + + pSMB->req.hdr.Uid = ses->Suid; + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + pSMB->req.Capabilities = + CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | + CAP_EXTENDED_SECURITY; + if (ses->capabilities & CAP_UNICODE) { + smb_buffer->Flags2 |= SMBFLG2_UNICODE; + pSMB->req.Capabilities |= CAP_UNICODE; + } + if (ses->capabilities & CAP_STATUS32) { + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; + pSMB->req.Capabilities |= CAP_STATUS32; + } + if (ses->capabilities & CAP_DFS) { + smb_buffer->Flags2 |= SMBFLG2_DFS; + pSMB->req.Capabilities |= CAP_DFS; + } + pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); + + bcc_ptr = (char *) &pSMB->req.SecurityBlob; + SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr; + strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); + SecurityBlob->MessageType = NtLmAuthenticate; + bcc_ptr += SecurityBlobLength; + SecurityBlob->NegotiateFlags = + NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | + NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | + 0x80000000 | NTLMSSP_NEGOTIATE_128; + if(sign_CIFS_PDUs) + SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; + if(ntlmv2_flag) + SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; + +/* setup pointers to domain name and workstation name */ + + SecurityBlob->WorkstationName.Buffer = 0; + SecurityBlob->WorkstationName.Length = 0; + SecurityBlob->WorkstationName.MaximumLength = 0; + SecurityBlob->SessionKey.Length = 0; + SecurityBlob->SessionKey.MaximumLength = 0; + SecurityBlob->SessionKey.Buffer = 0; + + SecurityBlob->LmChallengeResponse.Length = 0; + SecurityBlob->LmChallengeResponse.MaximumLength = 0; + SecurityBlob->LmChallengeResponse.Buffer = 0; + + SecurityBlob->NtChallengeResponse.Length = + cpu_to_le16(CIFS_SESSION_KEY_SIZE); + SecurityBlob->NtChallengeResponse.MaximumLength = + cpu_to_le16(CIFS_SESSION_KEY_SIZE); + memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE); + SecurityBlob->NtChallengeResponse.Buffer = + cpu_to_le32(SecurityBlobLength); + SecurityBlobLength += CIFS_SESSION_KEY_SIZE; + bcc_ptr += CIFS_SESSION_KEY_SIZE; + + if (ses->capabilities & CAP_UNICODE) { + if (domain == NULL) { + SecurityBlob->DomainName.Buffer = 0; + SecurityBlob->DomainName.Length = 0; + SecurityBlob->DomainName.MaximumLength = 0; + } else { + SecurityBlob->DomainName.Length = + cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + nls_codepage); + SecurityBlob->DomainName.Length *= 2; + SecurityBlob->DomainName.MaximumLength = + cpu_to_le16(SecurityBlob->DomainName.Length); + SecurityBlob->DomainName.Buffer = + cpu_to_le32(SecurityBlobLength); + bcc_ptr += SecurityBlob->DomainName.Length; + SecurityBlobLength += SecurityBlob->DomainName.Length; + SecurityBlob->DomainName.Length = + cpu_to_le16(SecurityBlob->DomainName.Length); + } + if (user == NULL) { + SecurityBlob->UserName.Buffer = 0; + SecurityBlob->UserName.Length = 0; + SecurityBlob->UserName.MaximumLength = 0; + } else { + SecurityBlob->UserName.Length = + cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64, + nls_codepage); + SecurityBlob->UserName.Length *= 2; + SecurityBlob->UserName.MaximumLength = + cpu_to_le16(SecurityBlob->UserName.Length); + SecurityBlob->UserName.Buffer = + cpu_to_le32(SecurityBlobLength); + bcc_ptr += SecurityBlob->UserName.Length; + SecurityBlobLength += SecurityBlob->UserName.Length; + SecurityBlob->UserName.Length = + cpu_to_le16(SecurityBlob->UserName.Length); + } + + /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage); + SecurityBlob->WorkstationName.Length *= 2; + SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length); + SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength); + bcc_ptr += SecurityBlob->WorkstationName.Length; + SecurityBlobLength += SecurityBlob->WorkstationName.Length; + SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */ + + if ((long) bcc_ptr % 2) { + *bcc_ptr = 0; + bcc_ptr++; + } + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + 32, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; /* null term version string */ + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + 64, nls_codepage); + bcc_ptr += 2 * bytes_returned; + *(bcc_ptr + 1) = 0; + *(bcc_ptr + 2) = 0; + bcc_ptr += 2; /* null terminate network opsys string */ + *(bcc_ptr + 1) = 0; + *(bcc_ptr + 2) = 0; + bcc_ptr += 2; /* null domain */ + } else { /* ASCII */ + if (domain == NULL) { + SecurityBlob->DomainName.Buffer = 0; + SecurityBlob->DomainName.Length = 0; + SecurityBlob->DomainName.MaximumLength = 0; + } else { + SecurityBlob->NegotiateFlags |= + NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; + strncpy(bcc_ptr, domain, 63); + SecurityBlob->DomainName.Length = strnlen(domain, 64); + SecurityBlob->DomainName.MaximumLength = + cpu_to_le16(SecurityBlob->DomainName.Length); + SecurityBlob->DomainName.Buffer = + cpu_to_le32(SecurityBlobLength); + bcc_ptr += SecurityBlob->DomainName.Length; + SecurityBlobLength += SecurityBlob->DomainName.Length; + SecurityBlob->DomainName.Length = + cpu_to_le16(SecurityBlob->DomainName.Length); + } + if (user == NULL) { + SecurityBlob->UserName.Buffer = 0; + SecurityBlob->UserName.Length = 0; + SecurityBlob->UserName.MaximumLength = 0; + } else { + strncpy(bcc_ptr, user, 63); + SecurityBlob->UserName.Length = strnlen(user, 64); + SecurityBlob->UserName.MaximumLength = + cpu_to_le16(SecurityBlob->UserName.Length); + SecurityBlob->UserName.Buffer = + cpu_to_le32(SecurityBlobLength); + bcc_ptr += SecurityBlob->UserName.Length; + SecurityBlobLength += SecurityBlob->UserName.Length; + SecurityBlob->UserName.Length = + cpu_to_le16(SecurityBlob->UserName.Length); + } + /* BB fill in our workstation name if known BB */ + + strcpy(bcc_ptr, "Linux version "); + bcc_ptr += strlen("Linux version "); + strcpy(bcc_ptr, UTS_RELEASE); + bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); + bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; + bcc_ptr++; /* null domain */ + *bcc_ptr = 0; + } + SecurityBlob->NegotiateFlags = + cpu_to_le32(SecurityBlob->NegotiateFlags); + pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); + BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += BCC(smb_buffer); + BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, + &bytes_returned, 1); + if (rc) { +/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ + } else if ((smb_buffer_response->WordCount == 3) + || (smb_buffer_response->WordCount == 4)) { + pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); + pSMBr->resp.SecurityBlobLength = + le16_to_cpu(pSMBr->resp.SecurityBlobLength); + if (pSMBr->resp.Action & GUEST_LOGIN) + cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ +/* if(SecurityBlob2->MessageType != NtLm??){ + cFYI("Unexpected message type on auth response is %d ")); + } */ + if (ses) { + cFYI(1, + ("Does UID on challenge %d match auth response UID %d ", + ses->Suid, smb_buffer_response->Uid)); + ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */ + bcc_ptr = pByteArea(smb_buffer_response); + /* response can have either 3 or 4 word count - Samba sends 3 */ + if ((pSMBr->resp.hdr.WordCount == 3) + || ((pSMBr->resp.hdr.WordCount == 4) + && (pSMBr->resp.SecurityBlobLength < + pSMBr->resp.ByteCount))) { + if (pSMBr->resp.hdr.WordCount == 4) { + bcc_ptr += + pSMBr->resp.SecurityBlobLength; + cFYI(1, + ("Security Blob Length %d ", + pSMBr->resp.SecurityBlobLength)); + } + + cFYI(1, + ("NTLMSSP response to Authenticate ")); + + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if ((long) (bcc_ptr) % 2) { + remaining_words = + (BCC(smb_buffer_response) + - 1) / 2; + bcc_ptr++; /* Unicode strings must be word aligned */ + } else { + remaining_words = BCC(smb_buffer_response) / 2; + } + len = + UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1); +/* We look for obvious messed up bcc or strings in response so we do not go off + the end since (at least) WIN2K and Windows XP have a major bug in not null + terminating last Unicode string in response */ + ses->serverOS = + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_strfromUCS_le(ses->serverOS, + (wchar_t *) + bcc_ptr, len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + remaining_words -= len + 1; + ses->serverOS[2 * len] = 0; + ses->serverOS[1 + (2 * len)] = 0; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) + bcc_ptr, + remaining_words + - 1); + ses->serverNOS = + cifs_kcalloc(2 * (len + 1), + GFP_KERNEL); + cifs_strfromUCS_le(ses-> + serverNOS, + (wchar_t *) + bcc_ptr, + len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + ses->serverNOS[2 * len] = 0; + ses->serverNOS[1+(2*len)] = 0; + remaining_words -= len + 1; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); + /* last string not always null terminated (e.g. for Windows XP & 2000) */ + ses->serverDomain = + cifs_kcalloc(2 * + (len + + 1), + GFP_KERNEL); + cifs_strfromUCS_le + (ses-> + serverDomain, + (wchar_t *) + bcc_ptr, len, + nls_codepage); + bcc_ptr += + 2 * (len + 1); + ses-> + serverDomain[2 + * len] + = 0; + ses-> + serverDomain[1 + + + (2 + * + len)] + = 0; + } /* else no more room so create dummy domain string */ + else + ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL); + } else { /* no room so create dummy domain and NOS string */ + ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); + } + } else { /* ASCII */ + len = strnlen(bcc_ptr, 1024); + if (((long) bcc_ptr + len) - + (long) pByteArea(smb_buffer_response) + <= BCC(smb_buffer_response)) { + ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); + strncpy(ses->serverOS,bcc_ptr, len); + + bcc_ptr += len; + bcc_ptr[0] = 0; /* null terminate the string */ + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL); + strncpy(ses->serverNOS, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL); + strncpy(ses->serverDomain, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + } else + cFYI(1, + ("Variable field of length %d extends beyond end of smb ", + len)); + } + } else { + cERROR(1, + (" Security Blob Length extends beyond end of SMB")); + } + } else { + cERROR(1, ("No session structure passed in.")); + } + } else { + cERROR(1, + (" Invalid Word count %d: ", + smb_buffer_response->WordCount)); + rc = -EIO; + } + + if (smb_buffer) + cifs_buf_release(smb_buffer); + + return rc; +} + +int +CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, + const char *tree, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + TCONX_REQ *pSMB; + TCONX_RSP *pSMBr; + char *bcc_ptr; + int rc = 0; + int length; + + if (ses == NULL) + return -EIO; + + smb_buffer = cifs_buf_get(); + if (smb_buffer == 0) { + return -ENOMEM; + } + smb_buffer_response = smb_buffer; + + header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, + NULL /*no tid */ , 4 /*wct */ ); + smb_buffer->Uid = ses->Suid; + pSMB = (TCONX_REQ *) smb_buffer; + pSMBr = (TCONX_RSP *) smb_buffer_response; + + pSMB->AndXCommand = 0xFF; + pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); + pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ + bcc_ptr = &(pSMB->Password[0]); + bcc_ptr++; /* skip password */ + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + if (ses->capabilities & CAP_STATUS32) { + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; + } + if (ses->capabilities & CAP_DFS) { + smb_buffer->Flags2 |= SMBFLG2_DFS; + } + if (ses->capabilities & CAP_UNICODE) { + smb_buffer->Flags2 |= SMBFLG2_UNICODE; + length = + cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage); + bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */ + bcc_ptr += 2; /* skip trailing null */ + } else { /* ASCII */ + + strcpy(bcc_ptr, tree); + bcc_ptr += strlen(tree) + 1; + } + strcpy(bcc_ptr, "?????"); + bcc_ptr += strlen("?????"); + bcc_ptr += 1; + BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += BCC(smb_buffer); + BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0); + + /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ + /* above now done in SendReceive */ + if ((rc == 0) && (tcon != NULL)) { + tcon->tidStatus = CifsGood; + tcon->tid = smb_buffer_response->Tid; + bcc_ptr = pByteArea(smb_buffer_response); + length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); + /* skip service field (NB: this field is always ASCII) */ + bcc_ptr += length + 1; + strncpy(tcon->treeName, tree, MAX_TREE_SIZE); + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + length = UniStrnlen((wchar_t *) bcc_ptr, 512); + if (((long) bcc_ptr + (2 * length)) - + (long) pByteArea(smb_buffer_response) <= + BCC(smb_buffer_response)) { + if(tcon->nativeFileSystem) + kfree(tcon->nativeFileSystem); + tcon->nativeFileSystem = + cifs_kcalloc(length + 2, GFP_KERNEL); + cifs_strfromUCS_le(tcon->nativeFileSystem, + (wchar_t *) bcc_ptr, + length, nls_codepage); + bcc_ptr += 2 * length; + bcc_ptr[0] = 0; /* null terminate the string */ + bcc_ptr[1] = 0; + bcc_ptr += 2; + } + /* else do not bother copying these informational fields */ + } else { + length = strnlen(bcc_ptr, 1024); + if (((long) bcc_ptr + length) - + (long) pByteArea(smb_buffer_response) <= + BCC(smb_buffer_response)) { + if(tcon->nativeFileSystem) + kfree(tcon->nativeFileSystem); + tcon->nativeFileSystem = + cifs_kcalloc(length + 1, GFP_KERNEL); + strncpy(tcon->nativeFileSystem, bcc_ptr, + length); + } + /* else do not bother copying these informational fields */ + } + tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); + cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags)); + } else if ((rc == 0) && tcon == NULL) { + /* all we need to save for IPC$ connection */ + ses->ipc_tid = smb_buffer_response->Tid; + } + + if (smb_buffer) + cifs_buf_release(smb_buffer); + return rc; +} + +int +cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) +{ + int rc = 0; + int xid; + struct cifsSesInfo *ses = NULL; + struct task_struct *cifsd_task; + + xid = GetXid(); + + if (cifs_sb->tcon) { + ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/ + rc = CIFSSMBTDis(xid, cifs_sb->tcon); + if (rc == -EBUSY) { + FreeXid(xid); + return 0; + } + tconInfoFree(cifs_sb->tcon); + if ((ses) && (ses->server)) { + /* save off task so we do not refer to ses later */ + cifsd_task = ses->server->tsk; + cFYI(1, ("About to do SMBLogoff ")); + rc = CIFSSMBLogoff(xid, ses); + if (rc == -EBUSY) { + FreeXid(xid); + return 0; + } else if (rc == -ESHUTDOWN) { + cFYI(1,("Waking up socket by sending it signal")); + send_sig(SIGKILL,cifsd_task,1); + rc = 0; + } /* else - we have an smb session + left on this socket do not kill cifsd */ + } else + cFYI(1, ("No session or bad tcon")); + } + + cifs_sb->tcon = NULL; + if (ses) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 2); + } + if (ses) + sesInfoFree(ses); + + FreeXid(xid); + return rc; /* BB check if we should always return zero here */ +} + +int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, + struct nls_table * nls_info) +{ + int rc = 0; + char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + int ntlmv2_flag = FALSE; + + /* what if server changes its buffer size after dropping the session? */ + if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { + rc = CIFSSMBNegotiate(xid, pSesInfo); + if(rc == -EAGAIN) /* retry only once on 1st time connection */ { + rc = CIFSSMBNegotiate(xid, pSesInfo); + if(rc == -EAGAIN) + rc = -EHOSTDOWN; + } + if(rc == 0) { + spin_lock(&GlobalMid_Lock); + if(pSesInfo->server->tcpStatus != CifsExiting) + pSesInfo->server->tcpStatus = CifsGood; + else + rc = -EHOSTDOWN; + spin_unlock(&GlobalMid_Lock); + + } + } + if (!rc) { + pSesInfo->capabilities = pSesInfo->server->capabilities; + if(linuxExtEnabled == 0) + pSesInfo->capabilities &= (~CAP_UNIX); + pSesInfo->sequence_number = 0; + cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", + pSesInfo->server->secMode, + pSesInfo->server->capabilities, + pSesInfo->server->timeZone)); + if (extended_security + && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) + && (pSesInfo->server->secType == NTLMSSP)) { + cFYI(1, ("New style sesssetup ")); + rc = CIFSSpnegoSessSetup(xid, pSesInfo, + NULL /* security blob */, + 0 /* blob length */, + nls_info); + } else if (extended_security + && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) + && (pSesInfo->server->secType == RawNTLMSSP)) { + cFYI(1, ("NTLMSSP sesssetup ")); + rc = CIFSNTLMSSPNegotiateSessSetup(xid, + pSesInfo, + &ntlmv2_flag, + nls_info); + if (!rc) { + if(ntlmv2_flag) { + char * v2_response; + cFYI(1,("Can use more secure NTLM version 2 password hash")); + CalcNTLMv2_partial_mac_key(pSesInfo, + nls_info); + v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); + if(v2_response) { + CalcNTLMv2_response(pSesInfo,v2_response); +/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ + kfree(v2_response); + /* BB Put dummy sig in SessSetup PDU? */ + } else + rc = -ENOMEM; + + } else { + SMBNTencrypt(pSesInfo->password, + pSesInfo->server->cryptKey, + ntlm_session_key); + + cifs_calculate_mac_key(pSesInfo->mac_signing_key, + ntlm_session_key, + pSesInfo->password); + } + /* for better security the weaker lanman hash not sent + in AuthSessSetup so we no longer calculate it */ + + rc = CIFSNTLMSSPAuthSessSetup(xid, + pSesInfo, + ntlm_session_key, + ntlmv2_flag, + nls_info); + } + } else { /* old style NTLM 0.12 session setup */ + SMBNTencrypt(pSesInfo->password, + pSesInfo->server->cryptKey, + ntlm_session_key); + + cifs_calculate_mac_key(pSesInfo->mac_signing_key, + ntlm_session_key, pSesInfo->password); + rc = CIFSSessSetup(xid, pSesInfo, + ntlm_session_key, nls_info); + } + if (rc) { + cERROR(1,("Send error in SessSetup = %d",rc)); + } else { + cFYI(1,("CIFS Session Established successfully")); + pSesInfo->status = CifsGood; + } + } + return rc; +} + diff -urN linux-2.4.27/fs/cifs/dir.c linux-2.4.27-cifs-1.20c/fs/cifs/dir.c --- linux-2.4.27/fs/cifs/dir.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/dir.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,425 @@ +/* + * fs/cifs/dir.c + * + * vfs operations that deal with dentries + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include "cifsfs.h" +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" + +void +renew_parental_timestamps(struct dentry *direntry) +{ + /* BB check if there is a way to get the kernel to do this or if we really need this */ + do { + direntry->d_time = jiffies; + direntry = direntry->d_parent; + } while (!IS_ROOT(direntry)); +} + +/* Note: caller must free return buffer */ +char * +build_path_from_dentry(struct dentry *direntry) +{ + struct dentry *temp; + int namelen = 0; + char *full_path; + + if(direntry == NULL) + return NULL; /* not much we can do if dentry is freed and + we need to reopen the file after it was closed implicitly + when the server crashed */ + +cifs_bp_rename_retry: + for (temp = direntry; !IS_ROOT(temp);) { + namelen += (1 + temp->d_name.len); + temp = temp->d_parent; + if(temp == NULL) { + cERROR(1,("corrupt dentry")); + return NULL; + } + } + + full_path = kmalloc(namelen+1, GFP_KERNEL); + if(full_path == NULL) + return full_path; + full_path[namelen] = 0; /* trailing null */ + + for (temp = direntry; !IS_ROOT(temp);) { + namelen -= 1 + temp->d_name.len; + if (namelen < 0) { + break; + } else { + full_path[namelen] = '\\'; + strncpy(full_path + namelen + 1, temp->d_name.name, + temp->d_name.len); + cFYI(0, (" name: %s ", full_path + namelen)); + } + temp = temp->d_parent; + if(temp == NULL) { + cERROR(1,("corrupt dentry")); + kfree(full_path); + return NULL; + } + } + if (namelen != 0) { + cERROR(1, + ("We did not end path lookup where we expected namelen is %d", + namelen)); + /* presumably this is only possible if we were racing with a rename + of one of the parent directories (we can not lock the dentries + above us to prevent this, but retrying should be harmless) */ + kfree(full_path); + namelen = 0; + goto cifs_bp_rename_retry; + } + + return full_path; +} + +/* Note: caller must free return buffer */ +char * +build_wildcard_path_from_dentry(struct dentry *direntry) +{ + struct dentry *temp; + int namelen = 0; + char *full_path; + + if(direntry == NULL) + return NULL; /* not much we can do if dentry is freed and + we need to reopen the file after it was closed implicitly + when the server crashed */ + +cifs_bwp_rename_retry: + for (temp = direntry; !IS_ROOT(temp);) { + namelen += (1 + temp->d_name.len); + temp = temp->d_parent; + if(temp == NULL) { + cERROR(1,("corrupt dentry")); + return NULL; + } + } + + full_path = kmalloc(namelen+3, GFP_KERNEL); + if(full_path == NULL) + return full_path; + + full_path[namelen] = '\\'; + full_path[namelen+1] = '*'; + full_path[namelen+2] = 0; /* trailing null */ + + for (temp = direntry; !IS_ROOT(temp);) { + namelen -= 1 + temp->d_name.len; + if (namelen < 0) { + break; + } else { + full_path[namelen] = '\\'; + strncpy(full_path + namelen + 1, temp->d_name.name, + temp->d_name.len); + cFYI(0, (" name: %s ", full_path + namelen)); + } + temp = temp->d_parent; + if(temp == NULL) { + cERROR(1,("corrupt dentry")); + kfree(full_path); + return NULL; + } + } + if (namelen != 0) { + cERROR(1, + ("We did not end path lookup where we expected namelen is %d", + namelen)); + /* presumably this is only possible if we were racing with a rename + of one of the parent directories (we can not lock the dentries + above us to prevent this, but retrying should be harmless) */ + kfree(full_path); + namelen = 0; + goto cifs_bwp_rename_retry; + } + + return full_path; +} + +/* Inode operations in similar order to how they appear in the Linux file fs.h */ + +int +cifs_create(struct inode *inode, struct dentry *direntry, int mode) +{ + int rc = -ENOENT; + int xid; + int oplock = 0; /* no sense requested oplock if we are just going to + immediately close the file */ + __u16 fileHandle; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + FILE_ALL_INFO * buf = NULL; + struct inode *newinode = NULL; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&direntry->d_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&direntry->d_sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + + /* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */ + + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF, + GENERIC_WRITE, CREATE_NOT_DIR, + &fileHandle, &oplock, buf, cifs_sb->local_nls); + if (rc) { + cFYI(1, ("cifs_create returned 0x%x ", rc)); + } else { + /* BB for case of overwriting existing file can we use the inode that was + passed in rather than creating new one?? */ + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb,xid); + else + rc = cifs_get_inode_info(&newinode, full_path, + buf, inode->i_sb,xid); + + if (rc != 0) { + cFYI(1,("Create worked but get_inode_info failed with rc = %d", + rc)); + } else { + direntry->d_op = &cifs_dentry_ops; + d_instantiate(direntry, newinode); + } + CIFSSMBClose(xid, pTcon, fileHandle); + + if(newinode) { + newinode->i_mode = mode; + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, + (__u64)-1, + (__u64)-1, + 0 /* dev */, + cifs_sb->local_nls); + else { /* BB implement via Windows security descriptors */ + /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ + /* in the meantime could set r/o dos attribute when perms are eg: + mode & 0222 == 0 */ + } + } + } + + if (buf) + kfree(buf); + if (full_path) + kfree(full_path); + FreeXid(xid); + + return rc; +} + +int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int device_number) +{ + int rc = -EPERM; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + struct inode * newinode = NULL; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&direntry->d_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&direntry->d_sb->s_vfs_rename_sem); + if(full_path == NULL) + rc = -ENOMEM; + + if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { + rc = CIFSSMBUnixSetPerms(xid, pTcon, + full_path, mode, current->euid, current->egid, + device_number, cifs_sb->local_nls); + if(!rc) { + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb,xid); + direntry->d_op = &cifs_dentry_ops; + if(rc == 0) + d_instantiate(direntry, newinode); + } + } + + if (full_path) + kfree(full_path); + FreeXid(xid); + + return rc; +} + + +struct dentry * +cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry) +{ + int xid; + int rc = 0; /* to get around spurious gcc warning, set to zero here */ + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct inode *newInode = NULL; + char *full_path = NULL; + + xid = GetXid(); + + cFYI(1, + (" parent inode = 0x%p name is: %s and dentry = 0x%p", + parent_dir_inode, direntry->d_name.name, direntry)); + + /* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */ + + /* check whether path exists */ + + cifs_sb = CIFS_SB(parent_dir_inode->i_sb); + pTcon = cifs_sb->tcon; + + /* can not grab the rename sem here since it would + deadlock in the cases (beginning of sys_rename itself) + in which we already have the sb rename sem */ + full_path = build_path_from_dentry(direntry); + if(full_path == NULL) { + FreeXid(xid); + return ERR_PTR(-ENOMEM); + } + + if (direntry->d_inode != NULL) { + cFYI(1, (" non-NULL inode in lookup")); + } else { + cFYI(1, (" NULL inode in lookup")); + } + cFYI(1, + (" Full path: %s inode = 0x%p", full_path, direntry->d_inode)); + + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&newInode, full_path, + parent_dir_inode->i_sb,xid); + else + rc = cifs_get_inode_info(&newInode, full_path, NULL, + parent_dir_inode->i_sb,xid); + + if ((rc == 0) && (newInode != NULL)) { + direntry->d_op = &cifs_dentry_ops; + d_add(direntry, newInode); + + /* since paths are not looked up by component - the parent directories are presumed to be good here */ + renew_parental_timestamps(direntry); + + } else if (rc == -ENOENT) { + rc = 0; + d_add(direntry, NULL); + } else { + cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc)); + /* BB special case check for Access Denied - watch security + exposure of returning dir info implicitly via different rc + if file exists or not but no access BB */ + } + + if (full_path) + kfree(full_path); + FreeXid(xid); + return ERR_PTR(rc); +} + +int +cifs_dir_open(struct inode *inode, struct file *file) +{ /* NB: currently unused since searches are opened in readdir */ + int rc = 0; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + if(file->f_dentry) { + down(&file->f_dentry->d_sb->s_vfs_rename_sem); + full_path = build_wildcard_path_from_dentry(file->f_dentry); + up(&file->f_dentry->d_sb->s_vfs_rename_sem); + } else { + FreeXid(xid); + return -EIO; + } + + cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path)); + + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +static int +cifs_d_revalidate(struct dentry *direntry, int flags) +{ + int isValid = 1; + +/* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */ + + if (direntry->d_inode) { + if (cifs_revalidate(direntry)) { + /* unlock_kernel(); */ + return 0; + } + } else { + cFYI(1, + ("In cifs_d_revalidate with no inode but name = %s and dentry 0x%p", + direntry->d_name.name, direntry)); + } + +/* unlock_kernel(); */ + + return isValid; +} + +/* static int cifs_d_delete(struct dentry *direntry) +{ + int rc = 0; + + cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name)); + + return rc; +} */ + +struct dentry_operations cifs_dentry_ops = { + .d_revalidate = cifs_d_revalidate, +/* d_delete: cifs_d_delete, *//* not needed except for debugging */ + /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ +}; diff -urN linux-2.4.27/fs/cifs/file.c linux-2.4.27-cifs-1.20c/fs/cifs/file.c --- linux-2.4.27/fs/cifs/file.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/file.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,2185 @@ +/* + * fs/cifs/file.c + * + * vfs operations that deal with files + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cifsfs.h" +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_unicode.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" + +int +cifs_open(struct inode *inode, struct file *file) +{ + int rc = -EACCES; + int xid, oplock; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsFileInfo *pCifsFile; + struct cifsInodeInfo *pCifsInode; + char *full_path = NULL; + int desiredAccess = 0x20197; + int disposition; + __u16 netfid; + FILE_ALL_INFO * buf = NULL; + time_t temp; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&inode->i_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(file->f_dentry); + up(&inode->i_sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + + cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + desiredAccess = GENERIC_READ; + else if ((file->f_flags & O_ACCMODE) == O_WRONLY) + desiredAccess = GENERIC_WRITE; + else if ((file->f_flags & O_ACCMODE) == O_RDWR) { + /* GENERIC_ALL is too much permission to request */ + /* can cause unnecessary access denied on create */ + /* desiredAccess = GENERIC_ALL; */ + desiredAccess = GENERIC_READ | GENERIC_WRITE; + } + +/********************************************************************* + * open flag mapping table: + * + * POSIX Flag CIFS Disposition + * ---------- ---------------- + * O_CREAT FILE_OPEN_IF + * O_CREAT | O_EXCL FILE_CREATE + * O_CREAT | O_TRUNC FILE_OVERWRITE_IF + * O_TRUNC FILE_OVERWRITE + * none of the above FILE_OPEN + * + * Note that there is not a direct match between disposition + * FILE_SUPERSEDE (ie create whether or not file exists although + * O_CREAT | O_TRUNC is similar but truncates the existing + * file rather than creating a new file as FILE_SUPERSEDE does + * (which uses the attributes / metadata passed in on open call) + *? + *? O_SYNC is a reasonable match to CIFS writethrough flag + *? and the read write flags match reasonably. O_LARGEFILE + *? is irrelevant because largefile support is always used + *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, + * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation + *********************************************************************/ + + /* For 2.4 case, file was already checked for existence + before create by vfs lookup and created in create + entry point, we are now just opening the newly + created file with the right desiredAccess flags */ + + if((file->f_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + disposition = FILE_OPEN_IF; + else if((file->f_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) + disposition = FILE_OVERWRITE_IF; + else if((file->f_flags & O_CREAT) == O_CREAT) + disposition = FILE_OPEN_IF; + else + disposition = FILE_OPEN; + + if (oplockEnabled) + oplock = REQ_OPLOCK; + else + oplock = FALSE; + + /* BB pass O_SYNC flag through on file attributes .. BB */ + + /* Also refresh inode by passing in file_info buf returned by SMBOpen + and calling get_inode_info with returned buf (at least + helps non-Unix server case */ + + /* BB we can not do this if this is the second open of a file + and the first handle has writebehind data, we might be + able to simply do a filemap_fdatawrite/filemap_fdatawait first */ + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + if(buf==0) { + if (full_path) + kfree(full_path); + FreeXid(xid); + return -ENOMEM; + } + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, + CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls); + if (rc) { + cFYI(1, ("cifs_open returned 0x%x ", rc)); + cFYI(1, ("oplock: %d ", oplock)); + } else { + file->private_data = + kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); + if (file->private_data) { + memset(file->private_data, 0, sizeof(struct cifsFileInfo)); + pCifsFile = (struct cifsFileInfo *) file->private_data; + pCifsFile->netfid = netfid; + pCifsFile->pid = current->pid; + init_MUTEX(&pCifsFile->fh_sem); + pCifsFile->pfile = file; /* needed for writepage */ + pCifsFile->pInode = inode; + pCifsFile->invalidHandle = FALSE; + pCifsFile->closePend = FALSE; + write_lock(&GlobalSMBSeslock); + spin_lock(&files_lock); + list_add(&pCifsFile->tlist,&pTcon->openFileList); + pCifsInode = CIFS_I(file->f_dentry->d_inode); + if(pCifsInode) { + /* want handles we can use to read with first */ + /* in the list so we do not have to walk the */ + /* list to search for one in prepare_write */ + if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + list_add_tail(&pCifsFile->flist,&pCifsInode->openFileList); + } else { + list_add(&pCifsFile->flist,&pCifsInode->openFileList); + } + spin_unlock(&files_lock); + write_unlock(&GlobalSMBSeslock); + if(pCifsInode->clientCanCacheRead) { + /* we have the inode open somewhere else + no need to discard cache data */ + } else { + if(buf) { + /* BB need same check in cifs_create too? */ + + /* if not oplocked, invalidate inode pages if mtime + or file size changed */ + temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime)); + if((file->f_dentry->d_inode->i_mtime == temp) && + (file->f_dentry->d_inode->i_size == (loff_t)le64_to_cpu(buf->EndOfFile))) { + cFYI(1,("inode unchanged on server")); + } else { + if(file->f_dentry->d_inode->i_mapping) { + /* BB no need to lock inode until after invalidate*/ + /* since namei code should already have it locked?*/ + filemap_fdatasync(file->f_dentry->d_inode->i_mapping); + } + cFYI(1,("invalidating remote inode since open detected it changed")); + invalidate_inode_pages(file->f_dentry->d_inode); + } + } + } + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, + full_path, inode->i_sb,xid); + else + rc = cifs_get_inode_info(&file->f_dentry->d_inode, + full_path, buf, inode->i_sb,xid); + + if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { + pCifsInode->clientCanCacheAll = TRUE; + pCifsInode->clientCanCacheRead = TRUE; + cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); + } else if((oplock & 0xF) == OPLOCK_READ) + pCifsInode->clientCanCacheRead = TRUE; + } else { + spin_unlock(&files_lock); + write_unlock(&GlobalSMBSeslock); + } + if(oplock & CIFS_CREATE_ACTION) { + /* time to set mode which we can not set earlier due + to problems creating new read-only files */ + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, + (__u64)-1, + (__u64)-1, + 0 /* dev */, + cifs_sb->local_nls); + else {/* BB implement via Windows security descriptors */ + /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ + /* in the meantime could set r/o dos attribute when perms are eg: + mode & 0222 == 0 */ + } + } + } + } + + if (buf) + kfree(buf); + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +/* Try to reaquire byte range locks that were released when session */ +/* to server was lost */ +static int cifs_relock_file(struct cifsFileInfo * cifsFile) +{ + int rc = 0; + +/* BB list all locks open on this file and relock */ + + return rc; +} + +static int cifs_reopen_file(struct inode *inode, struct file *file, int can_flush) +{ + int rc = -EACCES; + int xid, oplock; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsFileInfo *pCifsFile; + struct cifsInodeInfo *pCifsInode; + char *full_path = NULL; + int desiredAccess = 0x20197; + int disposition = FILE_OPEN; + __u16 netfid; + + if(inode == NULL) + return -EBADF; + if (file->private_data) { + pCifsFile = (struct cifsFileInfo *) file->private_data; + } else + return -EBADF; + + xid = GetXid(); + down(&pCifsFile->fh_sem); + if(pCifsFile->invalidHandle == FALSE) { + up(&pCifsFile->fh_sem); + FreeXid(xid); + return 0; + } + + if(file->f_dentry == NULL) { + up(&pCifsFile->fh_sem); + cFYI(1,("failed file reopen, no valid name if dentry freed")); + FreeXid(xid); + return -EBADF; + } + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; +/* can not grab rename sem here because various ops, including +those that already have the rename sem can end up causing writepage +to get called and if the server was down that means we end up here, +and we can never tell if the caller already has the rename_sem */ + full_path = build_path_from_dentry(file->f_dentry); + if(full_path == NULL) { + up(&pCifsFile->fh_sem); + FreeXid(xid); + return -ENOMEM; + } + + cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + desiredAccess = GENERIC_READ; + else if ((file->f_flags & O_ACCMODE) == O_WRONLY) + desiredAccess = GENERIC_WRITE; + else if ((file->f_flags & O_ACCMODE) == O_RDWR) { + /* GENERIC_ALL is too much permission to request */ + /* can cause unnecessary access denied on create */ + /* desiredAccess = GENERIC_ALL; */ + desiredAccess = GENERIC_READ | GENERIC_WRITE; + } + + if (oplockEnabled) + oplock = REQ_OPLOCK; + else + oplock = FALSE; + + + /* Can not refresh inode by passing in file_info buf to be returned + by SMBOpen and then calling get_inode_info with returned buf + since file might have write behind data that needs to be flushed + and server version of file size can be stale. If we + knew for sure that inode was not dirty locally we could do this */ + +/* buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + if(buf==0) { + up(&pCifsFile->fh_sem); + if (full_path) + kfree(full_path); + FreeXid(xid); + return -ENOMEM; + }*/ + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, + CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls); + if (rc) { + up(&pCifsFile->fh_sem); + cFYI(1, ("cifs_open returned 0x%x ", rc)); + cFYI(1, ("oplock: %d ", oplock)); + } else { + pCifsFile->netfid = netfid; + pCifsFile->invalidHandle = FALSE; + up(&pCifsFile->fh_sem); + pCifsInode = CIFS_I(inode); + if(pCifsInode) { + if(can_flush) { + filemap_fdatasync(inode->i_mapping); + filemap_fdatawait(inode->i_mapping); + /* temporarily disable caching while we + go to server to get inode info */ + pCifsInode->clientCanCacheAll = FALSE; + pCifsInode->clientCanCacheRead = FALSE; + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&inode, + full_path, inode->i_sb,xid); + else + rc = cifs_get_inode_info(&inode, + full_path, NULL, inode->i_sb,xid); + } /* else we are writing out data to server already + and could deadlock if we tried to flush data, and + since we do not know if we have data that would + invalidate the current end of file on the server + we can not go to the server to get the new + inod info */ + if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { + pCifsInode->clientCanCacheAll = TRUE; + pCifsInode->clientCanCacheRead = TRUE; + cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); + } else if((oplock & 0xF) == OPLOCK_READ) { + pCifsInode->clientCanCacheRead = TRUE; + pCifsInode->clientCanCacheAll = FALSE; + } else { + pCifsInode->clientCanCacheRead = FALSE; + pCifsInode->clientCanCacheAll = FALSE; + } + cifs_relock_file(pCifsFile); + } + } + + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +int +cifs_close(struct inode *inode, struct file *file) +{ + int rc = 0; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsFileInfo *pSMBFile = + (struct cifsFileInfo *) file->private_data; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + if (pSMBFile) { + pSMBFile->closePend = TRUE; + spin_lock(&files_lock); + if(pTcon) { + /* no sense reconnecting to close a file that is + already closed */ + if (pTcon->tidStatus != CifsNeedReconnect) { + spin_unlock(&files_lock); + rc = CIFSSMBClose(xid,pTcon,pSMBFile->netfid); + spin_lock(&files_lock); + } + } + list_del(&pSMBFile->flist); + list_del(&pSMBFile->tlist); + spin_unlock(&files_lock); + if(pSMBFile->search_resume_name) + kfree(pSMBFile->search_resume_name); + kfree(file->private_data); + file->private_data = NULL; + } else + rc = -EBADF; + + if(list_empty(&(CIFS_I(inode)->openFileList))) { + cFYI(1,("closing last open instance for inode %p",inode)); + /* if the file is not open we do not know if we can cache + info on this inode, much less write behind and read ahead */ + CIFS_I(inode)->clientCanCacheRead = FALSE; + CIFS_I(inode)->clientCanCacheAll = FALSE; + } + if((rc ==0) && CIFS_I(inode)->write_behind_rc) + rc = CIFS_I(inode)->write_behind_rc; + FreeXid(xid); + return rc; +} + +int +cifs_closedir(struct inode *inode, struct file *file) +{ + int rc = 0; + int xid; + struct cifsFileInfo *pSMBFileStruct = + (struct cifsFileInfo *) file->private_data; + + cFYI(1, ("Closedir inode = 0x%p with ", inode)); + + xid = GetXid(); + + if (pSMBFileStruct) { + cFYI(1, ("Freeing private data in close dir")); + kfree(file->private_data); + file->private_data = NULL; + } + FreeXid(xid); + return rc; +} + +int +cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) +{ + int rc, xid; + __u32 lockType = LOCKING_ANDX_LARGE_FILES; + __u32 numLock = 0; + __u32 numUnlock = 0; + __u64 length; + int wait_flag = FALSE; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + length = 1 + pfLock->fl_end - pfLock->fl_start; + + rc = -EACCES; + + xid = GetXid(); + + cFYI(1, + ("Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld end: %lld", + cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start, + pfLock->fl_end)); + + if (pfLock->fl_flags & FL_POSIX) + cFYI(1, ("Posix ")); + if (pfLock->fl_flags & FL_FLOCK) + cFYI(1, ("Flock ")); +/* if (pfLock->fl_flags & FL_SLEEP) { + cFYI(1, ("Blocking lock ")); + wait_flag = TRUE; + } */ + if (pfLock->fl_flags & FL_ACCESS) + cFYI(1, ("Process suspended by mandatory locking - not implemented yet ")); + if (pfLock->fl_flags & FL_LEASE) + cFYI(1, ("Lease on file - not implemented yet")); + if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_ACCESS | FL_LEASE))) + cFYI(1, ("Unknown lock flags 0x%x",pfLock->fl_flags)); + + if (pfLock->fl_type == F_WRLCK) { + cFYI(1, ("F_WRLCK ")); + numLock = 1; + } else if (pfLock->fl_type == F_UNLCK) { + cFYI(1, ("F_UNLCK ")); + numUnlock = 1; + } else if (pfLock->fl_type == F_RDLCK) { + cFYI(1, ("F_RDLCK ")); + lockType |= LOCKING_ANDX_SHARED_LOCK; + numLock = 1; + } else if (pfLock->fl_type == F_EXLCK) { + cFYI(1, ("F_EXLCK ")); + numLock = 1; + } else if (pfLock->fl_type == F_SHLCK) { + cFYI(1, ("F_SHLCK ")); + lockType |= LOCKING_ANDX_SHARED_LOCK; + numLock = 1; + } else + cFYI(1, ("Unknown type of lock ")); + + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + + if (file->private_data == NULL) { + FreeXid(xid); + return -EBADF; + } + + if (IS_GETLK(cmd)) { + rc = CIFSSMBLock(xid, pTcon, + ((struct cifsFileInfo *) file-> + private_data)->netfid, + length, + pfLock->fl_start, 0, 1, lockType, + 0 /* wait flag */ ); + if (rc == 0) { + rc = CIFSSMBLock(xid, pTcon, + ((struct cifsFileInfo *) file-> + private_data)->netfid, + length, + pfLock->fl_start, 1 /* numUnlock */ , + 0 /* numLock */ , lockType, + 0 /* wait flag */ ); + pfLock->fl_type = F_UNLCK; + if (rc != 0) + cERROR(1, + ("Error unlocking previously locked range %d during test of lock ", + rc)); + rc = 0; + + } else { + /* if rc == ERR_SHARING_VIOLATION ? */ + rc = 0; /* do not change lock type to unlock since range in use */ + } + + FreeXid(xid); + return rc; + } + + rc = CIFSSMBLock(xid, pTcon, + ((struct cifsFileInfo *) file->private_data)-> + netfid, length, + pfLock->fl_start, numUnlock, numLock, lockType, + wait_flag); + FreeXid(xid); + return rc; +} + +ssize_t +cifs_write(struct file * file, const char *write_data, + size_t write_size, loff_t * poffset) +{ + int rc = 0; + unsigned int bytes_written = 0; + unsigned int total_written; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + int xid, long_op; + struct cifsFileInfo * open_file; + + if(file->f_dentry == NULL) + return -EBADF; + + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + if(cifs_sb == NULL) { + return -EBADF; + } + pTcon = cifs_sb->tcon; + + /*cFYI(1, + (" write %d bytes to offset %lld of %s", write_size, + *poffset, file->f_dentry->d_name.name)); */ + + if (file->private_data == NULL) { + return -EBADF; + } else { + open_file = (struct cifsFileInfo *) file->private_data; + } + + xid = GetXid(); + if(file->f_dentry->d_inode == NULL) { + FreeXid(xid); + return -EBADF; + } + + if (*poffset > file->f_dentry->d_inode->i_size) + long_op = 2; /* writes past end of file can take a long time */ + else + long_op = 1; + + for (total_written = 0; write_size > total_written; + total_written += bytes_written) { + rc = -EAGAIN; + while(rc == -EAGAIN) { + if(file->private_data == NULL) { + /* file has been closed on us */ + FreeXid(xid); + /* if we have gotten here we have written some data + and blocked, and the file has been freed on us + while we blocked so return what we managed to write */ + return total_written; + } + if(open_file->closePend) { + FreeXid(xid); + if(total_written) + return total_written; + else + return -EBADF; + } + if (open_file->invalidHandle) { + if((file->f_dentry == NULL) || + (file->f_dentry->d_inode == NULL)) { + FreeXid(xid); + return total_written; + } + /* we could deadlock if we called + filemap_fdatawait from here so tell + reopen_file not to flush data to server now */ + rc = cifs_reopen_file(file->f_dentry->d_inode, + file,FALSE); + if(rc != 0) + break; + } + + rc = CIFSSMBWrite(xid, pTcon, + open_file->netfid, + write_size - total_written, *poffset, + &bytes_written, + write_data + total_written, long_op); + } + if (rc || (bytes_written == 0)) { + if (total_written) + break; + else { + FreeXid(xid); + return rc; + } + } else + *poffset += bytes_written; + long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */ + } + +#ifdef CONFIG_CIFS_STATS + if(total_written > 0) { + atomic_inc(&pTcon->num_writes); + spin_lock(&pTcon->stat_lock); + pTcon->bytes_written += total_written; + spin_unlock(&pTcon->stat_lock); + } +#endif + + /* since the write may have blocked check these pointers again */ + if(file->f_dentry) { + if(file->f_dentry->d_inode) { + file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime = + CURRENT_TIME; + if (total_written > 0) { + if (*poffset > file->f_dentry->d_inode->i_size) + file->f_dentry->d_inode->i_size = *poffset; + } + mark_inode_dirty_sync(file->f_dentry->d_inode); + } + } + FreeXid(xid); + return total_written; +} + +static int +cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) +{ + struct address_space *mapping = page->mapping; + loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + char * write_data; + int rc = -EFAULT; + int bytes_written = 0; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct inode *inode; + struct cifsInodeInfo *cifsInode; + struct cifsFileInfo *open_file = NULL; + struct list_head *tmp; + struct list_head *tmp1; + + if (!mapping) { + return -EFAULT; + } else if(!mapping->host) { + return -EFAULT; + } + + inode = page->mapping->host; + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + offset += (loff_t)from; + write_data = kmap(page); + write_data += from; + + if((to > PAGE_CACHE_SIZE) || (from > to)) { + kunmap(page); + return -EIO; + } + + /* racing with truncate? */ + if(offset > mapping->host->i_size) { + kunmap(page); + return 0; /* don't care */ + } + + /* check to make sure that we are not extending the file */ + if(mapping->host->i_size - offset < (loff_t)to) + to = (unsigned)(mapping->host->i_size - offset); + + + cifsInode = CIFS_I(mapping->host); + read_lock(&GlobalSMBSeslock); + /* BB we should start at the end */ + list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, flist); + if(open_file->closePend) + continue; + /* We check if file is open for writing first */ + if((open_file->pfile) && + ((open_file->pfile->f_flags & O_RDWR) || + (open_file->pfile->f_flags & O_WRONLY))) { + read_unlock(&GlobalSMBSeslock); + bytes_written = cifs_write(open_file->pfile, write_data, + to-from, &offset); + read_lock(&GlobalSMBSeslock); + /* Does mm or vfs already set times? */ + inode->i_atime = inode->i_mtime = CURRENT_TIME; + if ((bytes_written > 0) && (offset)) { + rc = 0; + } else if(bytes_written < 0) { + if(rc == -EBADF) { + /* have seen a case in which + kernel seemed to have closed/freed a file + even with writes active so we might as well + see if there are other file structs to try + for the same inode before giving up */ + continue; + } else + rc = bytes_written; + } + break; /* now that we found a valid file handle + and tried to write to it we are done, no + sense continuing to loop looking for another */ + } + if(tmp->next == NULL) { + cFYI(1,("File instance %p removed",tmp)); + break; + } + } + read_unlock(&GlobalSMBSeslock); + if(open_file == NULL) { + cFYI(1,("No writeable filehandles for inode")); + rc = -EIO; + } + + kunmap(page); + return rc; +} + +#if 0 +static int +cifs_writepages(struct address_space *mapping, struct writeback_control *wbc) +{ + int rc = -EFAULT; + int xid; + + xid = GetXid(); +/* call 16K write then Setpageuptodate */ + FreeXid(xid); + return rc; +} +#endif + +static int +cifs_writepage(struct page* page) +{ + int rc = -EFAULT; + int xid; + + xid = GetXid(); +/* BB add check for wbc flags */ + page_cache_get(page); + if (!Page_Uptodate(page)) { + cFYI(1,("ppw - page not up to date")); + } + + rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE); + SetPageUptodate(page); /* BB add check for error and Clearuptodate? */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) + unlock_page(page); +#else + UnlockPage(page); +#endif + page_cache_release(page); + FreeXid(xid); + return rc; +} + +static int +cifs_commit_write(struct file *file, struct page *page, unsigned offset, + unsigned to) +{ + int xid; + int rc = 0; + struct inode *inode = page->mapping->host; + loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + char * page_data; + + xid = GetXid(); + cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to)); + if (position > inode->i_size){ + inode->i_size = position; + /*if (file->private_data == NULL) { + rc = -EBADF; + } else { + open_file = (struct cifsFileInfo *)file->private_data; + cifs_sb = CIFS_SB(inode->i_sb); + rc = -EAGAIN; + while(rc == -EAGAIN) { + if((open_file->invalidHandle) && + (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode,file); + if(rc != 0) + break; + } + if(!open_file->closePend) { + rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, + position, open_file->netfid, + open_file->pid,FALSE); + } else { + rc = -EBADF; + break; + } + } + cFYI(1,(" SetEOF (commit write) rc = %d",rc)); + }*/ + } + if (!Page_Uptodate(page)) { + position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; + /* can not rely on (or let) writepage write this data */ + if(to < offset) { + cFYI(1,("Illegal offsets, can not copy from %d to %d", + offset,to)); + FreeXid(xid); + return rc; + } + /* this is probably better than directly calling + partialpage_write since in this function + the file handle is known which we might as well + leverage */ + /* BB check if anything else missing out of ppw */ + /* such as updating last write time */ + page_data = kmap(page); + rc = cifs_write(file, page_data+offset,to-offset, + &position); + if(rc > 0) + rc = 0; + /* else if rc < 0 should we set writebehind rc? */ + kunmap(page); + } else { + set_page_dirty(page); + } + + FreeXid(xid); + return rc; +} + +int +cifs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + int xid; + int rc = 0; + struct inode * inode = file->f_dentry->d_inode; + + xid = GetXid(); + + cFYI(1, ("Sync file - name: %s datasync: 0x%x ", + dentry->d_name.name, datasync)); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) + rc = filemap_fdatasync(inode->i_mapping); +#else + filemap_fdatasync(inode->i_mapping); +#endif + if(rc == 0) + CIFS_I(inode)->write_behind_rc = 0; + FreeXid(xid); + return rc; +} + +static int +cifs_sync_page(struct page *page) +{ + struct address_space *mapping; + struct inode *inode; + unsigned long index = page->index; + unsigned int rpages = 0; + int rc = 0; + + cFYI(1,("sync page %p",page)); + mapping = page->mapping; + if (!mapping) + return 0; + inode = mapping->host; + if (!inode) + return 0; + +/* fill in rpages then + result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */ + + cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); + + if (rc < 0) + return rc; + return 0; +} + +/* + * As file closes, flush all cached write data for this inode checking + * for write behind errors. + * + */ +int cifs_flush(struct file *file) +{ + struct inode * inode = file->f_dentry->d_inode; + int rc = 0; + + /* Rather than do the steps manually: */ + /* lock the inode for writing */ + /* loop through pages looking for write behind data (dirty pages) */ + /* coalesce into contiguous 16K (or smaller) chunks to write to server */ + /* send to server (prefer in parallel) */ + /* deal with writebehind errors */ + /* unlock inode for writing */ + /* filemapfdatawrite appears easier for the time being */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) + rc = filemap_fdatasync(inode->i_mapping); +#else + filemap_fdatasync(inode->i_mapping); +#endif + if(rc == 0) /* reset wb rc if we were able to write out dirty pages */ + CIFS_I(inode)->write_behind_rc = 0; + + cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc)); + + return rc; +} + + +ssize_t +cifs_read(struct file * file, char *read_data, size_t read_size, + loff_t * poffset) +{ + int rc = -EACCES; + unsigned int bytes_read = 0; + unsigned int total_read; + unsigned int current_read_size; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + int xid; + char * current_offset; + struct cifsFileInfo * open_file; + + xid = GetXid(); + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + + if (file->private_data == NULL) { + FreeXid(xid); + return -EBADF; + } + open_file = (struct cifsFileInfo *)file->private_data; + + if((file->f_flags & O_ACCMODE) == O_WRONLY) { + cFYI(1,("attempting read on write only file instance")); + } + + for (total_read = 0,current_offset=read_data; read_size > total_read; + total_read += bytes_read,current_offset+=bytes_read) { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) + current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize); +#else + current_read_size = min(read_size - total_read,cifs_sb->rsize); +#endif + rc = -EAGAIN; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode, + file,TRUE); + if(rc != 0) + break; + } + + rc = CIFSSMBRead(xid, pTcon, + open_file->netfid, + current_read_size, *poffset, + &bytes_read, ¤t_offset); + } + if (rc || (bytes_read == 0)) { + if (total_read) { + break; + } else { + FreeXid(xid); + return rc; + } + } else { +#ifdef CONFIG_CIFS_STATS + atomic_inc(&pTcon->num_reads); + spin_lock(&pTcon->stat_lock); + pTcon->bytes_read += total_read; + spin_unlock(&pTcon->stat_lock); +#endif + *poffset += bytes_read; + } + } + FreeXid(xid); + return total_read; +} + +int cifs_file_mmap(struct file * file, struct vm_area_struct * vma) +{ + struct dentry * dentry = file->f_dentry; + int rc, xid; + + xid = GetXid(); + rc = cifs_revalidate(dentry); + if (rc) { + cFYI(1,("Validation prior to mmap failed, error=%d", rc)); + FreeXid(xid); + return rc; + } + rc = generic_file_mmap(file, vma); + FreeXid(xid); + return rc; +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +static void cifs_copy_cache_pages(struct address_space *mapping, + struct list_head *pages, int bytes_read, + char *data,struct pagevec * plru_pvec) +{ + struct page *page; + char * target; + + while (bytes_read > 0) { + if(list_empty(pages)) + break; + + page = list_entry(pages->prev, struct page, lru); + list_del(&page->lru); + + if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { + page_cache_release(page); + cFYI(1,("Add page cache failed")); + continue; + } + + target = kmap_atomic(page,KM_USER0); + + if(PAGE_CACHE_SIZE > bytes_read) { + memcpy(target,data,bytes_read); + /* zero the tail end of this partial page */ + memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read); + bytes_read = 0; + } else { + memcpy(target,data,PAGE_CACHE_SIZE); + bytes_read -= PAGE_CACHE_SIZE; + } + kunmap_atomic(target,KM_USER0); + + flush_dcache_page(page); + SetPageUptodate(page); + unlock_page(page); + if (!pagevec_add(plru_pvec, page)) + __pagevec_lru_add(plru_pvec); + data += PAGE_CACHE_SIZE; + } + return; +} + + +static int +cifs_readpages(struct file *file, struct address_space *mapping, + struct list_head *page_list, unsigned num_pages) +{ + int rc = -EACCES; + int xid; + loff_t offset; + struct page * page; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + int bytes_read = 0; + unsigned int read_size,i; + char * smb_read_data = NULL; + struct smb_com_read_rsp * pSMBr; + struct pagevec lru_pvec; + struct cifsFileInfo * open_file; + + xid = GetXid(); + if (file->private_data == NULL) { + FreeXid(xid); + return -EBADF; + } + open_file = (struct cifsFileInfo *)file->private_data; + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + + pagevec_init(&lru_pvec, 0); + + for(i = 0;iprev, struct page, lru); + offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + + /* count adjacent pages that we will read into */ + contig_pages = 0; + expected_index = list_entry(page_list->prev,struct page,lru)->index; + list_for_each_entry_reverse(tmp_page,page_list,lru) { + if(tmp_page->index == expected_index) { + contig_pages++; + expected_index++; + } else { + break; + } + } + if(contig_pages + i > num_pages) { + contig_pages = num_pages - i; + } + + /* for reads over a certain size could initiate async read ahead */ + + read_size = contig_pages * PAGE_CACHE_SIZE; + /* Read size needs to be in multiples of one page */ + read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK); + + rc = -EAGAIN; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode, + file, TRUE); + if(rc != 0) + break; + } + + rc = CIFSSMBRead(xid, pTcon, + open_file->netfid, + read_size, offset, + &bytes_read, &smb_read_data); + /* BB need to check return code here */ + if(rc== -EAGAIN) { + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = NULL; + } + } + } + if ((rc < 0) || (smb_read_data == NULL)) { + cFYI(1,("Read error in readpages: %d",rc)); + /* clean up remaing pages off list */ + while (!list_empty(page_list) && (i < num_pages)) { + page = list_entry(page_list->prev, struct page, lru); + list_del(&page->lru); + page_cache_release(page); + } + break; + } else if (bytes_read > 0) { + pSMBr = (struct smb_com_read_rsp *)smb_read_data; + cifs_copy_cache_pages(mapping, page_list, bytes_read, + smb_read_data + 4 /* RFC1001 hdr */ + + le16_to_cpu(pSMBr->DataOffset), &lru_pvec); + + i += bytes_read >> PAGE_CACHE_SHIFT; +#ifdef CONFIG_CIFS_STATS + atomic_inc(&pTcon->num_reads); + spin_lock(&pTcon->stat_lock); + pTcon->bytes_read += bytes_read; + spin_unlock(&pTcon->stat_lock); +#endif + if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { + cFYI(1,("Partial page %d of %d read to cache",i++,num_pages)); + + i++; /* account for partial page */ + + /* server copy of file can have smaller size than client */ + /* BB do we need to verify this common case ? this case is ok - + if we are at server EOF we will hit it on next read */ + + /* while(!list_empty(page_list) && (i < num_pages)) { + page = list_entry(page_list->prev,struct page, list); + list_del(&page->list); + page_cache_release(page); + } + break; */ + } + } else { + cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset)); + /* BB turn off caching and do new lookup on file size at server? */ + while (!list_empty(page_list) && (i < num_pages)) { + page = list_entry(page_list->prev, struct page, lru); + list_del(&page->lru); + page_cache_release(page); /* BB removeme - replace with zero of page? */ + } + break; + } + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = NULL; + } + bytes_read = 0; + } + + pagevec_lru_add(&lru_pvec); + +/* need to free smb_read_data buf before exit */ + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = NULL; + } + + FreeXid(xid); + return rc; +} +#endif + +static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * poffset) +{ + char * read_data; + int rc; + + page_cache_get(page); + read_data = kmap(page); + /* for reads over a certain size could initiate async read ahead */ + + rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset); + + if (rc < 0) + goto io_error; + else { + cFYI(1,("Bytes read %d ",rc)); + } + + file->f_dentry->d_inode->i_atime = CURRENT_TIME; + + if(PAGE_CACHE_SIZE > rc) { + memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc); + } + flush_dcache_page(page); + SetPageUptodate(page); + rc = 0; + +io_error: + kunmap(page); + page_cache_release(page); + return rc; +} + +static int +cifs_readpage(struct file *file, struct page *page) +{ + loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + int rc = -EACCES; + int xid; + + xid = GetXid(); + + if (file->private_data == NULL) { + FreeXid(xid); + return -EBADF; + } + + cFYI(1,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset)); + + rc = cifs_readpage_worker(file,page,&offset); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) + unlock_page(page); +#else + UnlockPage(page); +#endif + + FreeXid(xid); + return rc; +} + +/* We do not want to update the file size from server for inodes + open for write - to avoid races with writepage extending + the file - in the future we could consider allowing + refreshing the inode only on increases in the file size + but this is tricky to do without racing with writebehind + page caching in the current Linux kernel design */ + +int is_size_safe_to_change(struct cifsInodeInfo * cifsInode) +{ + struct list_head *tmp; + struct list_head *tmp1; + struct cifsFileInfo *open_file = NULL; + int rc = TRUE; + + if(cifsInode == NULL) + return rc; + + read_lock(&GlobalSMBSeslock); + list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, flist); + if(open_file == NULL) + break; + if(open_file->closePend) + continue; + /* We check if file is open for writing, + BB we could supplement this with a check to see if file size + changes have been flushed to server - ie inode metadata dirty */ + if((open_file->pfile) && + ((open_file->pfile->f_flags & O_RDWR) || + (open_file->pfile->f_flags & O_WRONLY))) { + rc = FALSE; + break; + } + if(tmp->next == NULL) { + cFYI(1,("File instance %p removed",tmp)); + break; + } + } + read_unlock(&GlobalSMBSeslock); + return rc; +} + + +void +fill_in_inode(struct inode *tmp_inode, + FILE_DIRECTORY_INFO * pfindData, int *pobject_type) +{ + struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); + struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); + + pfindData->ExtFileAttributes = + le32_to_cpu(pfindData->ExtFileAttributes); + pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); + pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); + cifsInfo->cifsAttrs = pfindData->ExtFileAttributes; + cifsInfo->time = jiffies; + + /* Linux can not store file creation time unfortunately so ignore it */ + tmp_inode->i_atime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); + tmp_inode->i_mtime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); + tmp_inode->i_ctime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); + /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ + /* 2767 perms - indicate mandatory locking */ + /* BB fill in uid and gid here? with help from winbind? + or retrieve from NTFS stream extended attribute */ + if(atomic_read(&cifsInfo->inUse) == 0) { + tmp_inode->i_uid = cifs_sb->mnt_uid; + tmp_inode->i_gid = cifs_sb->mnt_gid; + /* set default mode. will override for dirs below */ + tmp_inode->i_mode = cifs_sb->mnt_file_mode; + } + + cFYI(0, + ("CIFS FFIRST: Attributes came in as 0x%x", + pfindData->ExtFileAttributes)); + if (pfindData->ExtFileAttributes & ATTR_REPARSE) { + *pobject_type = DT_LNK; + /* BB can this and S_IFREG or S_IFDIR be set as in Windows? */ + tmp_inode->i_mode |= S_IFLNK; + } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) { + *pobject_type = DT_DIR; + /* override default perms since we do not lock dirs */ + if(atomic_read(&cifsInfo->inUse) == 0) { + tmp_inode->i_mode = cifs_sb->mnt_dir_mode; + } + tmp_inode->i_mode |= S_IFDIR; + } else { + *pobject_type = DT_REG; + tmp_inode->i_mode |= S_IFREG; + if(pfindData->ExtFileAttributes & ATTR_READONLY) + tmp_inode->i_mode &= ~(S_IWUGO); + + }/* could add code here - to validate if device or weird share type? */ + + /* can not fill in nlink here as in qpathinfo version and Unx search */ + if(atomic_read(&cifsInfo->inUse) == 0) { + atomic_set(&cifsInfo->inUse,1); + } + if(is_size_safe_to_change(cifsInfo)) { + /* can not safely change the file size here if the + client is writing to it due to potential races */ + tmp_inode->i_size = pfindData->EndOfFile; + + /* 512 bytes (2**9) is the fake blocksize that must be used */ + /* for this calculation, even though the reported blocksize is larger */ + tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9; + } + + if (pfindData->AllocationSize < pfindData->EndOfFile) + cFYI(1, ("Possible sparse file: allocation size less than end of file ")); + cFYI(1, + ("File Size %ld and blocks %ld and blocksize %ld", + (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks, + tmp_inode->i_blksize)); + if (S_ISREG(tmp_inode->i_mode)) { + cFYI(1, (" File inode ")); + tmp_inode->i_op = &cifs_file_inode_ops; + tmp_inode->i_fop = &cifs_file_ops; + tmp_inode->i_data.a_ops = &cifs_addr_ops; + } else if (S_ISDIR(tmp_inode->i_mode)) { + cFYI(1, (" Directory inode")); + tmp_inode->i_op = &cifs_dir_inode_ops; + tmp_inode->i_fop = &cifs_dir_ops; + } else if (S_ISLNK(tmp_inode->i_mode)) { + cFYI(1, (" Symbolic Link inode ")); + tmp_inode->i_op = &cifs_symlink_inode_ops; + } else { + cFYI(1, (" Init special inode ")); + init_special_inode(tmp_inode, tmp_inode->i_mode, + kdev_t_to_nr(tmp_inode->i_rdev)); + } +} + +void +unix_fill_in_inode(struct inode *tmp_inode, + FILE_UNIX_INFO * pfindData, int *pobject_type) +{ + struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); + cifsInfo->time = jiffies; + atomic_inc(&cifsInfo->inUse); + + tmp_inode->i_atime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); + tmp_inode->i_mtime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime)); + tmp_inode->i_ctime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); + + tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); + pfindData->Type = le32_to_cpu(pfindData->Type); + if (pfindData->Type == UNIX_FILE) { + *pobject_type = DT_REG; + tmp_inode->i_mode |= S_IFREG; + } else if (pfindData->Type == UNIX_SYMLINK) { + *pobject_type = DT_LNK; + tmp_inode->i_mode |= S_IFLNK; + } else if (pfindData->Type == UNIX_DIR) { + *pobject_type = DT_DIR; + tmp_inode->i_mode |= S_IFDIR; + } else if (pfindData->Type == UNIX_CHARDEV) { + *pobject_type = DT_CHR; + tmp_inode->i_mode |= S_IFCHR; + tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), + le64_to_cpu(pfindData->DevMinor) & MINORMASK); + } else if (pfindData->Type == UNIX_BLOCKDEV) { + *pobject_type = DT_BLK; + tmp_inode->i_mode |= S_IFBLK; + tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), + le64_to_cpu(pfindData->DevMinor) & MINORMASK); + } else if (pfindData->Type == UNIX_FIFO) { + *pobject_type = DT_FIFO; + tmp_inode->i_mode |= S_IFIFO; + } else if (pfindData->Type == UNIX_SOCKET) { + *pobject_type = DT_SOCK; + tmp_inode->i_mode |= S_IFSOCK; + } + + tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); + tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); + tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); + + pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes); + if(is_size_safe_to_change(cifsInfo)) { + /* can not safely change the file size here if the + client is writing to it due to potential races */ + pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); + tmp_inode->i_size = pfindData->EndOfFile; + + /* 512 bytes (2**9) is the fake blocksize that must be used */ + /* for this calculation, not the real blocksize */ + tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9; + } + + if (S_ISREG(tmp_inode->i_mode)) { + cFYI(1, ("File inode")); + tmp_inode->i_op = &cifs_file_inode_ops; + tmp_inode->i_fop = &cifs_file_ops; + tmp_inode->i_data.a_ops = &cifs_addr_ops; + } else if (S_ISDIR(tmp_inode->i_mode)) { + cFYI(1, ("Directory inode")); + tmp_inode->i_op = &cifs_dir_inode_ops; + tmp_inode->i_fop = &cifs_dir_ops; + } else if (S_ISLNK(tmp_inode->i_mode)) { + cFYI(1, ("Symbolic Link inode")); + tmp_inode->i_op = &cifs_symlink_inode_ops; +/* tmp_inode->i_fop = *//* do not need to set to anything */ + } else { + cFYI(1, ("Special inode")); + init_special_inode(tmp_inode, tmp_inode->i_mode, + kdev_t_to_nr(tmp_inode->i_rdev)); + } +} + +static void +construct_dentry(struct qstr *qstring, struct file *file, + struct inode **ptmp_inode, struct dentry **pnew_dentry) +{ + struct dentry *tmp_dentry; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsInodeInfo *pCifsI; + + cFYI(1, ("For %s ", qstring->name)); + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + + qstring->hash = full_name_hash(qstring->name, qstring->len); + tmp_dentry = d_lookup(file->f_dentry, qstring); + if (tmp_dentry) { + cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode)); + *ptmp_inode = tmp_dentry->d_inode; + /* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */ + if(*ptmp_inode == NULL) { + *ptmp_inode = new_inode(file->f_dentry->d_sb); + if(*ptmp_inode == NULL) + return; + d_instantiate(tmp_dentry, *ptmp_inode); + insert_inode_hash(*ptmp_inode); + pCifsI = CIFS_I(*ptmp_inode); + INIT_LIST_HEAD(&pCifsI->openFileList); + /* can not enable caching for this inode + until a file instance is open and we + can check the oplock flag on the open + response */ + (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) + (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ +#endif + pCifsI->clientCanCacheRead = FALSE; + pCifsI->clientCanCacheAll = FALSE; + pCifsI->time = 0; + /* do not need to set cifs Attrs since + they are about to be overwritten + in fill_in_inode */ + atomic_set(&pCifsI->inUse, 0); + } + } else { + tmp_dentry = d_alloc(file->f_dentry, qstring); + if(tmp_dentry == NULL) { + cERROR(1,("Failed allocating dentry")); + return; + } + + if(ptmp_inode) { + *ptmp_inode = new_inode(file->f_dentry->d_sb); + if(*ptmp_inode == NULL) + return; + pCifsI = CIFS_I(*ptmp_inode); + insert_inode_hash(*ptmp_inode); + INIT_LIST_HEAD(&pCifsI->openFileList); + /* can not enable caching for this inode + until a file instance is open and we + can check the oplock flag on the open + response */ + (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) + (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ +#endif + pCifsI->clientCanCacheRead = FALSE; + pCifsI->clientCanCacheAll = FALSE; + pCifsI->time = 0; + /* do not need to set cifs Attrs since + they are about to be overwritten + in fill_in_inode */ + atomic_set(&pCifsI->inUse, 0); + } + tmp_dentry->d_op = &cifs_dentry_ops; + d_instantiate(tmp_dentry, *ptmp_inode); + d_rehash(tmp_dentry); + } + + tmp_dentry->d_time = jiffies; + *pnew_dentry = tmp_dentry; +} + +static void reset_resume_key(struct file * dir_file, + unsigned char * filename, + unsigned int len,int Unicode,struct nls_table * nls_tab) { + struct cifsFileInfo *cifsFile; + + cifsFile = (struct cifsFileInfo *)dir_file->private_data; + if(cifsFile == NULL) + return; + if(cifsFile->search_resume_name) { + kfree(cifsFile->search_resume_name); + } + + if(Unicode) + len *= 2; + cifsFile->resume_name_length = len; + + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + + if(cifsFile->search_resume_name == NULL) { + cERROR(1,("failed new resume key allocate, length %d", + cifsFile->resume_name_length)); + return; + } + if(Unicode) + cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name, + filename, len, nls_tab); + else + memcpy(cifsFile->search_resume_name, filename, + cifsFile->resume_name_length); + cFYI(1,("Reset resume key to: %s with len %d",filename,len)); + return; +} + + + +static int +cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData, + struct file *file, filldir_t filldir, void *direntry) +{ + struct inode *tmp_inode; + struct dentry *tmp_dentry; + int object_type,rc; + + pqstring->name = pfindData->FileName; + pqstring->len = pfindData->FileNameLength; + + construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); + if((tmp_inode == NULL) || (tmp_dentry == NULL)) { + return -ENOMEM; + } + fill_in_inode(tmp_inode, pfindData, &object_type); + rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, + tmp_inode->i_ino, object_type); + if(rc) { + /* due to readdir error we need to recalculate resume + key so next readdir will restart on right entry */ + cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName)); + } + dput(tmp_dentry); + return rc; +} + +static int +cifs_filldir_unix(struct qstr *pqstring, + FILE_UNIX_INFO * pUnixFindData, struct file *file, + filldir_t filldir, void *direntry) +{ + struct inode *tmp_inode; + struct dentry *tmp_dentry; + int object_type, rc; + + pqstring->name = pUnixFindData->FileName; + pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); + + construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); + if((tmp_inode == NULL) || (tmp_dentry == NULL)) { + return -ENOMEM; + } + + unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type); + rc = filldir(direntry, pUnixFindData->FileName, pqstring->len, + file->f_pos, tmp_inode->i_ino, object_type); + if(rc) { + /* due to readdir error we need to recalculate resume + key so next readdir will restart on right entry */ + cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName)); + } + dput(tmp_dentry); + return rc; +} + +int +cifs_readdir(struct file *file, void *direntry, filldir_t filldir) +{ + int rc = 0; + int xid; + int Unicode = FALSE; + int UnixSearch = FALSE; + unsigned int bufsize, i; + __u16 searchHandle; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsFileInfo *cifsFile = NULL; + char *full_path = NULL; + char *data; + struct qstr qstring; + T2_FFIRST_RSP_PARMS findParms; + T2_FNEXT_RSP_PARMS findNextParms; + FILE_DIRECTORY_INFO *pfindData; + FILE_DIRECTORY_INFO *lastFindData; + FILE_UNIX_INFO *pfindDataUnix; + + xid = GetXid(); + + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; + if(bufsize > CIFS_MAX_MSGSIZE) { + FreeXid(xid); + return -EIO; + } + data = kmalloc(bufsize, GFP_KERNEL); + pfindData = (FILE_DIRECTORY_INFO *) data; + + if(file->f_dentry == NULL) { + FreeXid(xid); + return -EIO; + } + down(&file->f_dentry->d_sb->s_vfs_rename_sem); + full_path = build_wildcard_path_from_dentry(file->f_dentry); + up(&file->f_dentry->d_sb->s_vfs_rename_sem); + + + cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); + + switch ((int) file->f_pos) { + case 0: + if (filldir(direntry, ".", 1, file->f_pos, + file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { + cERROR(1, ("Filldir for current dir failed ")); + break; + } + file->f_pos++; + /* fallthrough */ + case 1: + if (filldir(direntry, "..", 2, file->f_pos, + file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { + cERROR(1, ("Filldir for parent dir failed ")); + break; + } + file->f_pos++; + /* fallthrough */ + case 2: + if (file->private_data != NULL) { + cifsFile = + (struct cifsFileInfo *) file->private_data; + if (cifsFile->endOfSearch) { + if(cifsFile->emptyDir) { + cFYI(1, ("End of search, empty dir")); + rc = 0; + break; + } + } else { + cifsFile->invalidHandle = TRUE; + CIFSFindClose(xid, pTcon, cifsFile->netfid); + } + if(cifsFile->search_resume_name) { + kfree(cifsFile->search_resume_name); + cifsFile->search_resume_name = NULL; + } + } + rc = CIFSFindFirst(xid, pTcon, full_path, pfindData, + &findParms, cifs_sb->local_nls, + &Unicode, &UnixSearch); + cFYI(1, ("Count: %d End: %d ", findParms.SearchCount, + findParms.EndofSearch)); + + if (rc == 0) { + searchHandle = findParms.SearchHandle; + if(file->private_data == NULL) + file->private_data = + kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL); + if (file->private_data) { + memset(file->private_data, 0, + sizeof (struct cifsFileInfo)); + cifsFile = + (struct cifsFileInfo *) file->private_data; + cifsFile->netfid = searchHandle; + cifsFile->invalidHandle = FALSE; + init_MUTEX(&cifsFile->fh_sem); + } else { + rc = -ENOMEM; + break; + } + + renew_parental_timestamps(file->f_dentry); + lastFindData = + (FILE_DIRECTORY_INFO *) ((char *) pfindData + + findParms.LastNameOffset); + if((char *)lastFindData > (char *)pfindData + bufsize) { + cFYI(1,("last search entry past end of packet")); + rc = -EIO; + break; + } + /* Offset of resume key same for levels 257 and 514 */ + cifsFile->resume_key = lastFindData->FileIndex; + if(UnixSearch == FALSE) { + cifsFile->resume_name_length = + le32_to_cpu(lastFindData->FileNameLength); + if(cifsFile->resume_name_length > bufsize - 64) { + cFYI(1,("Illegal resume file name length %d", + cifsFile->resume_name_length)); + rc = -ENOMEM; + break; + } + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + cFYI(1,("Last file: %s with name %d bytes long", + lastFindData->FileName, + cifsFile->resume_name_length)); + memcpy(cifsFile->search_resume_name, + lastFindData->FileName, + cifsFile->resume_name_length); + } else { + pfindDataUnix = (FILE_UNIX_INFO *)lastFindData; + if (Unicode == TRUE) { + for(i=0;(pfindDataUnix->FileName[i] + | pfindDataUnix->FileName[i+1]); + i+=2) { + if(i > bufsize-64) + break; + } + cifsFile->resume_name_length = i + 2; + } else { + cifsFile->resume_name_length = + strnlen(pfindDataUnix->FileName, + bufsize-63); + } + if(cifsFile->resume_name_length > bufsize - 64) { + cFYI(1,("Illegal resume file name length %d", + cifsFile->resume_name_length)); + rc = -ENOMEM; + break; + } + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + cFYI(1,("Last file: %s with name %d bytes long", + pfindDataUnix->FileName, + cifsFile->resume_name_length)); + memcpy(cifsFile->search_resume_name, + pfindDataUnix->FileName, + cifsFile->resume_name_length); + } + for (i = 2; i < (unsigned int)findParms.SearchCount + 2; i++) { + if (UnixSearch == FALSE) { + pfindData->FileNameLength = + le32_to_cpu(pfindData->FileNameLength); + if (Unicode == TRUE) + pfindData->FileNameLength = + cifs_strfromUCS_le + (pfindData->FileName, + (wchar_t *) + pfindData->FileName, + (pfindData-> + FileNameLength) / 2, + cifs_sb->local_nls); + qstring.len = pfindData->FileNameLength; + if (((qstring.len != 1) + || (pfindData->FileName[0] != '.')) + && ((qstring.len != 2) + || (pfindData-> + FileName[0] != '.') + || (pfindData-> + FileName[1] != '.'))) { + if(cifs_filldir(&qstring, + pfindData, + file, filldir, + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + reset_resume_key(file, pfindData->FileName,qstring.len, + Unicode, cifs_sb->local_nls); + findParms.EndofSearch = 0; + break; + } + file->f_pos++; + } + } else { /* UnixSearch */ + pfindDataUnix = + (FILE_UNIX_INFO *) pfindData; + if (Unicode == TRUE) + qstring.len = + cifs_strfromUCS_le + (pfindDataUnix->FileName, + (wchar_t *) + pfindDataUnix->FileName, + MAX_PATHCONF, + cifs_sb->local_nls); + else + qstring.len = + strnlen(pfindDataUnix-> + FileName, + MAX_PATHCONF); + if (((qstring.len != 1) + || (pfindDataUnix-> + FileName[0] != '.')) + && ((qstring.len != 2) + || (pfindDataUnix-> + FileName[0] != '.') + || (pfindDataUnix-> + FileName[1] != '.'))) { + if(cifs_filldir_unix(&qstring, + pfindDataUnix, + file, + filldir, + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findParms.EndofSearch = 0; + reset_resume_key(file, pfindDataUnix->FileName, + qstring.len,Unicode,cifs_sb->local_nls); + break; + } + file->f_pos++; + } + } + /* works also for Unix ff struct since first field of both */ + pfindData = + (FILE_DIRECTORY_INFO *) ((char *) pfindData + + le32_to_cpu(pfindData->NextEntryOffset)); + /* BB also should check to make sure that pointer is not beyond the end of the SMB */ + /* if(pfindData > lastFindData) rc = -EIO; break; */ + } /* end for loop */ + if ((findParms.EndofSearch != 0) && cifsFile) { + cifsFile->endOfSearch = TRUE; + if(findParms.SearchCount == 2) + cifsFile->emptyDir = TRUE; + } + } else { + if (cifsFile) + cifsFile->endOfSearch = TRUE; + /* unless parent directory gone do not return error */ + rc = 0; + } + break; + default: + if (file->private_data == NULL) { + rc = -EBADF; + cFYI(1, + ("Readdir on closed srch, pos = %lld", + file->f_pos)); + } else { + cifsFile = (struct cifsFileInfo *) file->private_data; + if (cifsFile->endOfSearch) { + rc = 0; + cFYI(1, ("End of search ")); + break; + } + searchHandle = cifsFile->netfid; + rc = CIFSFindNext(xid, pTcon, pfindData, + &findNextParms, searchHandle, + cifsFile->search_resume_name, + cifsFile->resume_name_length, + cifsFile->resume_key, + &Unicode, &UnixSearch); + cFYI(1,("Count: %d End: %d ", + findNextParms.SearchCount, + findNextParms.EndofSearch)); + if ((rc == 0) && (findNextParms.SearchCount != 0)) { + /* BB save off resume key, key name and name length */ + lastFindData = + (FILE_DIRECTORY_INFO *) ((char *) pfindData + + findNextParms.LastNameOffset); + if((char *)lastFindData > (char *)pfindData + bufsize) { + cFYI(1,("last search entry past end of packet")); + rc = -EIO; + break; + } + /* Offset of resume key same for levels 257 and 514 */ + cifsFile->resume_key = lastFindData->FileIndex; + + if(UnixSearch == FALSE) { + cifsFile->resume_name_length = + le32_to_cpu(lastFindData->FileNameLength); + if(cifsFile->resume_name_length > bufsize - 64) { + cFYI(1,("Illegal resume file name length %d", + cifsFile->resume_name_length)); + rc = -ENOMEM; + break; + } + /* Free the memory allocated by previous findfirst + or findnext call - we can not reuse the memory since + the resume name may not be same string length */ + if(cifsFile->search_resume_name) + kfree(cifsFile->search_resume_name); + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + cFYI(1,("Last file: %s with name %d bytes long", + lastFindData->FileName, + cifsFile->resume_name_length)); + memcpy(cifsFile->search_resume_name, + lastFindData->FileName, + cifsFile->resume_name_length); + } else { + pfindDataUnix = (FILE_UNIX_INFO *)lastFindData; + if (Unicode == TRUE) { + for(i=0;(pfindDataUnix->FileName[i] + | pfindDataUnix->FileName[i+1]); + i+=2) { + if(i > bufsize-64) + break; + } + cifsFile->resume_name_length = i + 2; + } else { + cifsFile->resume_name_length = + strnlen(pfindDataUnix-> + FileName, + MAX_PATHCONF); + } + if(cifsFile->resume_name_length > bufsize - 64) { + cFYI(1,("Illegal resume file name length %d", + cifsFile->resume_name_length)); + rc = -ENOMEM; + break; + } + /* Free the memory allocated by previous findfirst + or findnext call - we can not reuse the memory since + the resume name may not be same string length */ + if(cifsFile->search_resume_name) + kfree(cifsFile->search_resume_name); + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + cFYI(1,("fnext last file: %s with name %d bytes long", + pfindDataUnix->FileName, + cifsFile->resume_name_length)); + memcpy(cifsFile->search_resume_name, + pfindDataUnix->FileName, + cifsFile->resume_name_length); + } + + for (i = 0; i < findNextParms.SearchCount; i++) { + pfindData->FileNameLength = + le32_to_cpu(pfindData-> + FileNameLength); + if (UnixSearch == FALSE) { + if (Unicode == TRUE) + pfindData->FileNameLength = + cifs_strfromUCS_le + (pfindData->FileName, + (wchar_t *) + pfindData->FileName, + (pfindData->FileNameLength)/ 2, + cifs_sb->local_nls); + qstring.len = + pfindData->FileNameLength; + if (((qstring.len != 1) + || (pfindData->FileName[0] != '.')) + && ((qstring.len != 2) + || (pfindData->FileName[0] != '.') + || (pfindData->FileName[1] != + '.'))) { + if(cifs_filldir + (&qstring, + pfindData, + file, filldir, + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findNextParms.EndofSearch = 0; + reset_resume_key(file, pfindData->FileName,qstring.len, + Unicode,cifs_sb->local_nls); + break; + } + file->f_pos++; + } + } else { /* UnixSearch */ + pfindDataUnix = + (FILE_UNIX_INFO *) + pfindData; + if (Unicode == TRUE) + qstring.len = + cifs_strfromUCS_le + (pfindDataUnix->FileName, + (wchar_t *) + pfindDataUnix->FileName, + MAX_PATHCONF, + cifs_sb->local_nls); + else + qstring.len = + strnlen + (pfindDataUnix-> + FileName, + MAX_PATHCONF); + if (((qstring.len != 1) + || (pfindDataUnix-> + FileName[0] != '.')) + && ((qstring.len != 2) + || (pfindDataUnix-> + FileName[0] != '.') + || (pfindDataUnix-> + FileName[1] != + '.'))) { + if(cifs_filldir_unix + (&qstring, + pfindDataUnix, + file, filldir, + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findNextParms.EndofSearch = 0; + reset_resume_key(file, pfindDataUnix->FileName,qstring.len, + Unicode,cifs_sb->local_nls); + break; + } + file->f_pos++; + } + } + pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + le32_to_cpu(pfindData->NextEntryOffset)); /* works also for Unix find struct since this is the first field of both */ + /* BB also should check to make sure that pointer is not beyond the end of the SMB */ + } /* end for loop */ + if (findNextParms.EndofSearch != 0) { + cifsFile->endOfSearch = TRUE; + } + } else { + cifsFile->endOfSearch = TRUE; + rc = 0; /* unless parent directory disappeared - do not return error here (eg Access Denied or no more files) */ + } + } + } /* end switch */ + if (data) + kfree(data); + if (full_path) + kfree(full_path); + FreeXid(xid); + + return rc; +} +int cifs_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + int rc = 0; + loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + cFYI(1,("prepare write for page %p from %d to %d",page,from,to)); + if (!Page_Uptodate(page)) { + /* if (to - from != PAGE_CACHE_SIZE) { + void *kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr, 0, from); + memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + } */ + /* If we are writing a full page it will be up to date, + no need to read from the server */ + if((to==PAGE_CACHE_SIZE) && (from == 0)) + SetPageUptodate(page); + + /* might as well read a page, it is fast enough */ + if((file->f_flags & O_ACCMODE) != O_WRONLY) { + rc = cifs_readpage_worker(file,page,&offset); + } else { + /* should we try using another + file handle if there is one - how would we lock it + to prevent close of that handle racing with this read? */ + /* In any case this will be written out by commit_write */ + } + } + + /* BB should we pass any errors back? e.g. if we do not have read access to the file */ + return 0; +} + + +struct address_space_operations cifs_addr_ops = { + .readpage = cifs_readpage, +/* .readpages = cifs_readpages, */ + .writepage = cifs_writepage, + .prepare_write = cifs_prepare_write, + .commit_write = cifs_commit_write, + .sync_page = cifs_sync_page, + /*.direct_IO = */ +}; diff -urN linux-2.4.27/fs/cifs/inode.c linux-2.4.27-cifs-1.20c/fs/cifs/inode.c --- linux-2.4.27/fs/cifs/inode.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/inode.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,1079 @@ +/* + * fs/cifs/inode.c + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include "cifsfs.h" +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" + +extern int is_size_safe_to_change(struct cifsInodeInfo *); + +struct inode * get_cifs_inode(struct super_block * sb) +{ + struct inode * newinode; + newinode = new_inode(sb); + cFYI(1,("got new inode %p",newinode)); + if(newinode) { + struct cifsInodeInfo * cifsInfo = CIFS_I(newinode); + cifsInfo->clientCanCacheRead = FALSE; + cifsInfo->clientCanCacheAll = FALSE; + INIT_LIST_HEAD(&cifsInfo->openFileList); + cifsInfo->cifsAttrs = 0x20; /* default */ + newinode->i_blksize = CIFS_MAX_MSGSIZE; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) + newinode->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ +#endif + atomic_set(&cifsInfo->inUse, 0); + cifsInfo->time = 0; + insert_inode_hash(newinode); + } + return newinode; + +} + +int +cifs_get_inode_info_unix(struct inode **pinode, + const unsigned char *search_path, + struct super_block *sb,int xid) +{ + int rc = 0; + FILE_UNIX_BASIC_INFO findData; + struct cifsTconInfo *pTcon; + struct inode *inode; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + char *tmp_path; + + pTcon = cifs_sb->tcon; + cFYI(1, (" Getting info on %s ", search_path)); + /* we could have done a find first instead but this returns more info */ + rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, + cifs_sb->local_nls); + /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */ + if (rc) { + if (rc == -EREMOTE) { + tmp_path = + kmalloc(strnlen + (pTcon->treeName, + MAX_TREE_SIZE + 1) + + strnlen(search_path, MAX_PATHCONF) + 1, + GFP_KERNEL); + if (tmp_path == NULL) { + return -ENOMEM; + } + /* have to skip first of the double backslash of UNC name */ + strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); + strncat(tmp_path, search_path, MAX_PATHCONF); + rc = connect_to_dfs_path(xid, pTcon->ses, + /* treename + */ tmp_path, + cifs_sb->local_nls); + kfree(tmp_path); + + /* BB fix up inode etc. */ + } else if (rc) { + return rc; + } + + } else { + struct cifsInodeInfo *cifsInfo; + + /* get new inode */ + if (*pinode == NULL) { + *pinode = get_cifs_inode(sb); + } + if(*pinode == NULL) { + return -ENOMEM; + } + + inode = *pinode; + cifsInfo = CIFS_I(inode); + + cFYI(1, (" Old time %ld ", cifsInfo->time)); + cifsInfo->time = jiffies; + cFYI(1, (" New time %ld ", cifsInfo->time)); + atomic_set(&cifsInfo->inUse,1); /* ok to set on every refresh of inode */ + + inode->i_atime = + cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime)); + inode->i_mtime = + cifs_NTtimeToUnix(le64_to_cpu + (findData.LastModificationTime)); + inode->i_ctime = + cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange)); + inode->i_mode = le64_to_cpu(findData.Permissions); + findData.Type = le32_to_cpu(findData.Type); + if (findData.Type == UNIX_FILE) { + inode->i_mode |= S_IFREG; + } else if (findData.Type == UNIX_SYMLINK) { + inode->i_mode |= S_IFLNK; + } else if (findData.Type == UNIX_DIR) { + inode->i_mode |= S_IFDIR; + } else if (findData.Type == UNIX_CHARDEV) { + inode->i_mode |= S_IFCHR; + inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), + le64_to_cpu(findData.DevMinor) & MINORMASK); + } else if (findData.Type == UNIX_BLOCKDEV) { + inode->i_mode |= S_IFBLK; + inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), + le64_to_cpu(findData.DevMinor) & MINORMASK); + } else if (findData.Type == UNIX_FIFO) { + inode->i_mode |= S_IFIFO; + } else if (findData.Type == UNIX_SOCKET) { + inode->i_mode |= S_IFSOCK; + } + inode->i_uid = le64_to_cpu(findData.Uid); + inode->i_gid = le64_to_cpu(findData.Gid); + inode->i_nlink = le64_to_cpu(findData.Nlinks); + findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes); + findData.EndOfFile = le64_to_cpu(findData.EndOfFile); + + if(is_size_safe_to_change(cifsInfo)) { + /* can not safely change the file size here if the + client is writing to it due to potential races */ + inode->i_size = findData.EndOfFile; +/* blksize needs to be multiple of two. So safer to default to blksize + and blkbits set in superblock so 2**blkbits and blksize will match */ +/* inode->i_blksize = + (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ + + /* This seems incredibly stupid but it turns out that + i_blocks is not related to (i_size / i_blksize), instead a + size of 512 is required to be used for calculating num blocks */ + + +/* inode->i_blocks = + (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/ + + /* 512 bytes (2**9) is the fake blocksize that must be used */ + /* for this calculation */ + inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9; + } + + if (findData.NumOfBytes < findData.EndOfFile) + cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file ")); + cFYI(1, + ("Size %ld and blocks %ld ", + (unsigned long) inode->i_size, inode->i_blocks)); + if (S_ISREG(inode->i_mode)) { + cFYI(1, (" File inode ")); + inode->i_op = &cifs_file_inode_ops; + inode->i_fop = &cifs_file_ops; + inode->i_data.a_ops = &cifs_addr_ops; + } else if (S_ISDIR(inode->i_mode)) { + cFYI(1, (" Directory inode")); + inode->i_op = &cifs_dir_inode_ops; + inode->i_fop = &cifs_dir_ops; + } else if (S_ISLNK(inode->i_mode)) { + cFYI(1, (" Symbolic Link inode ")); + inode->i_op = &cifs_symlink_inode_ops; +/* tmp_inode->i_fop = *//* do not need to set to anything */ + } else { + cFYI(1, (" Init special inode ")); + init_special_inode(inode, inode->i_mode, + kdev_t_to_nr(inode->i_rdev)); + } + } + return rc; +} + +int +cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, + FILE_ALL_INFO * pfindData, struct super_block *sb, int xid) +{ + int rc = 0; + struct cifsTconInfo *pTcon; + struct inode *inode; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + char *tmp_path; + char *buf = NULL; + + pTcon = cifs_sb->tcon; + cFYI(1,("Getting info on %s ", search_path)); + + if((pfindData == NULL) && (*pinode != NULL)) { + if(CIFS_I(*pinode)->clientCanCacheRead) { + cFYI(1,("No need to revalidate inode sizes on cached file ")); + return rc; + } + } + + /* if file info not passed in then get it from server */ + if(pfindData == NULL) { + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + pfindData = (FILE_ALL_INFO *)buf; + /* could do find first instead but this returns more info */ + rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, + cifs_sb->local_nls); + } + /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ + if (rc) { + if (rc == -EREMOTE) { + tmp_path = + kmalloc(strnlen + (pTcon->treeName, + MAX_TREE_SIZE + 1) + + strnlen(search_path, MAX_PATHCONF) + 1, + GFP_KERNEL); + if (tmp_path == NULL) { + if(buf) + kfree(buf); + return -ENOMEM; + } + + strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); + strncat(tmp_path, search_path, MAX_PATHCONF); + rc = connect_to_dfs_path(xid, pTcon->ses, + /* treename + */ tmp_path, + cifs_sb->local_nls); + kfree(tmp_path); + /* BB fix up inode etc. */ + } else if (rc) { + if(buf) + kfree(buf); + return rc; + } + } else { + struct cifsInodeInfo *cifsInfo; + + /* get new inode */ + if (*pinode == NULL) { + *pinode = get_cifs_inode(sb); + } + if(*pinode == NULL) + return -ENOMEM; + inode = *pinode; + cifsInfo = CIFS_I(inode); + pfindData->Attributes = le32_to_cpu(pfindData->Attributes); + cifsInfo->cifsAttrs = pfindData->Attributes; + cFYI(1, (" Old time %ld ", cifsInfo->time)); + cifsInfo->time = jiffies; + cFYI(1, (" New time %ld ", cifsInfo->time)); + +/* blksize needs to be multiple of two. So safer to default to blksize + and blkbits set in superblock so 2**blkbits and blksize will match */ +/* inode->i_blksize = + (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ + + /* Linux can not store file creation time unfortunately so we ignore it */ + inode->i_atime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); + inode->i_mtime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); + inode->i_ctime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); + cFYI(0, + (" Attributes came in as 0x%x ", pfindData->Attributes)); + + /* set default mode. will override for dirs below */ + if(atomic_read(&cifsInfo->inUse) == 0) + /* new inode, can safely set these fields */ + inode->i_mode = cifs_sb->mnt_file_mode; + + if (pfindData->Attributes & ATTR_REPARSE) { + /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */ + inode->i_mode |= S_IFLNK; + } else if (pfindData->Attributes & ATTR_DIRECTORY) { + /* override default perms since we do not do byte range locking on dirs */ + inode->i_mode = cifs_sb->mnt_dir_mode; + inode->i_mode |= S_IFDIR; + } else { + inode->i_mode |= S_IFREG; + /* treat the dos attribute of read-only as read-only mode e.g. 555 */ + if(cifsInfo->cifsAttrs & ATTR_READONLY) + inode->i_mode &= ~(S_IWUGO); + /* BB add code here - validate if device or weird share or device type? */ + } + if(is_size_safe_to_change(cifsInfo)) { + /* can not safely change the file size here if the + client is writing to it due to potential races */ + inode->i_size = le64_to_cpu(pfindData->EndOfFile); + + /* 512 bytes (2**9) is the fake blocksize that must be used */ + /* for this calculation */ + inode->i_blocks = (512 - 1 + pfindData->AllocationSize) + >> 9; + } + pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); + + cFYI(1, + (" Size %ld and blocks %ld ", + (unsigned long) inode->i_size, inode->i_blocks)); + inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); + + /* BB fill in uid and gid here? with help from winbind? + or retrieve from NTFS stream extended attribute */ + if(atomic_read(&cifsInfo->inUse) == 0) { + inode->i_uid = cifs_sb->mnt_uid; + inode->i_gid = cifs_sb->mnt_gid; + /* set so we do not keep refreshing these fields with + bad data after user has changed them in memory */ + atomic_set(&cifsInfo->inUse,1); + } + + if (S_ISREG(inode->i_mode)) { + cFYI(1, (" File inode ")); + inode->i_op = &cifs_file_inode_ops; + inode->i_fop = &cifs_file_ops; + inode->i_data.a_ops = &cifs_addr_ops; + } else if (S_ISDIR(inode->i_mode)) { + cFYI(1, (" Directory inode ")); + inode->i_op = &cifs_dir_inode_ops; + inode->i_fop = &cifs_dir_ops; + } else if (S_ISLNK(inode->i_mode)) { + cFYI(1, (" Symbolic Link inode ")); + inode->i_op = &cifs_symlink_inode_ops; + } else { + init_special_inode(inode, inode->i_mode, + kdev_t_to_nr(inode->i_rdev)); + } + } + if(buf) + kfree(buf); + return rc; +} + +void +cifs_read_inode(struct inode *inode) +{ /* gets root inode */ + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsInodeInfo *cifs_inode; + + cifs_sb = CIFS_SB(inode->i_sb); + xid = GetXid(); + + cifs_inode = CIFS_I(inode); + cifs_inode->cifsAttrs = ATTR_DIRECTORY; + atomic_set(&cifs_inode->inUse, 0); + cifs_inode->time = 0; + inode->i_blksize = CIFS_MAX_MSGSIZE; + inode->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ + + INIT_LIST_HEAD(&cifs_inode->openFileList); + + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid); + else + cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid); + /* can not call macro FreeXid here since in a void func */ + _FreeXid(xid); +} + +int +cifs_unlink(struct inode *inode, struct dentry *direntry) +{ + int rc = 0; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + struct cifsInodeInfo *cifsInode; + FILE_BASIC_INFO * pinfo_buf; + + cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode)); + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + +/* Unlink can be called from rename so we can not grab + the sem here since we deadlock otherwise */ +/* down(&direntry->d_sb->s_vfs_rename_sem);*/ + full_path = build_path_from_dentry(direntry); +/* up(&direntry->d_sb->s_vfs_rename_sem);*/ + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls); + + if (!rc) { + direntry->d_inode->i_nlink--; + } else if (rc == -ENOENT) { + d_drop(direntry); + } else if (rc == -ETXTBSY) { + int oplock = FALSE; + __u16 netfid; + + rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, + CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, + &netfid, &oplock, NULL, cifs_sb->local_nls); + if(rc==0) { + CIFSSMBRenameOpenFile(xid,pTcon,netfid, + NULL, cifs_sb->local_nls); + CIFSSMBClose(xid, pTcon, netfid); + direntry->d_inode->i_nlink--; + } + } else if (rc == -EACCES) { + /* try only if r/o attribute set in local lookup data? */ + pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL); + if(pinfo_buf) { + memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO)); + /* ATTRS set to normal clears r/o bit */ + pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); + rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf, + cifs_sb->local_nls); + kfree(pinfo_buf); + } + if(rc==0) { + rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls); + if (!rc) { + direntry->d_inode->i_nlink--; + } else if (rc == -ETXTBSY) { + int oplock = FALSE; + __u16 netfid; + + rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, + CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, + &netfid, &oplock, NULL, cifs_sb->local_nls); + if(rc==0) { + CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls); + CIFSSMBClose(xid, pTcon, netfid); + direntry->d_inode->i_nlink--; + } + /* BB if rc = -ETXTBUSY goto the rename logic BB */ + } + } + } + cifsInode = CIFS_I(direntry->d_inode); + cifsInode->time = 0; /* will force revalidate to get info when needed */ + direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = + CURRENT_TIME; + cifsInode = CIFS_I(inode); + cifsInode->time = 0; /* force revalidate of dir as well */ + + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +int +cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) +{ + int rc = 0; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + struct inode *newinode = NULL; + + cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode)); + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&inode->i_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&inode->i_sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + /* BB add setting the equivalent of mode via CreateX w/ACLs */ + rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls); + if (rc) { + cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); + d_drop(direntry); + } else { + inode->i_nlink++; + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb,xid); + else + rc = cifs_get_inode_info(&newinode, full_path,NULL, + inode->i_sb,xid); + + direntry->d_op = &cifs_dentry_ops; + d_instantiate(direntry, newinode); + if(direntry->d_inode) + direntry->d_inode->i_nlink = 2; + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, + (__u64)-1, + (__u64)-1, + 0 /* dev_t */, + cifs_sb->local_nls); + else { /* BB to be implemented via Windows secrty descriptors*/ + /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ + } + } + if (full_path) + kfree(full_path); + FreeXid(xid); + + return rc; +} + +int +cifs_rmdir(struct inode *inode, struct dentry *direntry) +{ + int rc = 0; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + struct cifsInodeInfo *cifsInode; + + cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode)); + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&inode->i_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&inode->i_sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + + rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls); + + if (!rc) { + inode->i_nlink--; + direntry->d_inode->i_size = 0; + direntry->d_inode->i_nlink = 0; + } + + cifsInode = CIFS_I(direntry->d_inode); + cifsInode->time = 0; /* force revalidate to go get info when needed */ + direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = + CURRENT_TIME; + + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +int +cifs_rename(struct inode *source_inode, struct dentry *source_direntry, + struct inode *target_inode, struct dentry *target_direntry) +{ + char *fromName; + char *toName; + struct cifs_sb_info *cifs_sb_source; + struct cifs_sb_info *cifs_sb_target; + struct cifsTconInfo *pTcon; + int xid; + int rc = 0; + + xid = GetXid(); + + cifs_sb_target = CIFS_SB(target_inode->i_sb); + cifs_sb_source = CIFS_SB(source_inode->i_sb); + pTcon = cifs_sb_source->tcon; + + if (pTcon != cifs_sb_target->tcon) { + FreeXid(xid); + return -EXDEV; /* BB actually could be allowed if same server, but + different share. Might eventually add support for this */ + } + + /* we already have the rename sem so we do not need + to grab it again here to protect the path integrity */ + fromName = build_path_from_dentry(source_direntry); + toName = build_path_from_dentry(target_direntry); + if((fromName == NULL) || (toName == NULL)) { + rc = -ENOMEM; + goto cifs_rename_exit; + } + + rc = CIFSSMBRename(xid, pTcon, fromName, toName, + cifs_sb_source->local_nls); + if(rc == -EEXIST) { + /* check if they are the same file + because rename of hardlinked files is a noop */ + FILE_UNIX_BASIC_INFO * info_buf_source; + FILE_UNIX_BASIC_INFO * info_buf_target; + + info_buf_source = + kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL); + if(info_buf_source != NULL) { + info_buf_target = info_buf_source+1; + rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, + info_buf_source, cifs_sb_source->local_nls); + if(rc == 0) { + rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName, + info_buf_target, + cifs_sb_target->local_nls); + } + if((rc == 0) && + (info_buf_source->UniqueId == + info_buf_target->UniqueId)) { + /* do not rename since the files are hardlinked + which is a noop */ + } else { + /* we either can not tell the files are hardlinked + (as with Windows servers) or files are not hardlinked + so delete the target manually before renaming to + follow POSIX rather than Windows semantics */ + cifs_unlink(target_inode, target_direntry); + rc = CIFSSMBRename(xid, pTcon, fromName, toName, + cifs_sb_source->local_nls); + } + kfree(info_buf_source); + } /* if we can not get memory just leave rc as EEXIST */ + } + + if((rc == -EIO)||(rc == -EEXIST)) { + int oplock = FALSE; + __u16 netfid; + + rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, + CREATE_NOT_DIR, + &netfid, &oplock, NULL, cifs_sb_source->local_nls); + if(rc==0) { + CIFSSMBRenameOpenFile(xid,pTcon,netfid, + toName, cifs_sb_source->local_nls); + CIFSSMBClose(xid, pTcon, netfid); + } + } + +cifs_rename_exit: + if (fromName) + kfree(fromName); + if (toName) + kfree(toName); + + FreeXid(xid); + return rc; +} + +int +cifs_revalidate(struct dentry *direntry) +{ + int xid; + int rc = 0; + char *full_path; + struct cifs_sb_info *cifs_sb; + struct cifsInodeInfo *cifsInode; + loff_t local_size; + time_t local_mtime; + int invalidate_inode = FALSE; + + if(direntry->d_inode == NULL) + return -ENOENT; + + cifsInode = CIFS_I(direntry->d_inode); + + if(cifsInode == NULL) + return -ENOENT; + + /* no sense revalidating inode info on file that no one can write */ + if(CIFS_I(direntry->d_inode)->clientCanCacheRead) + return rc; + + xid = GetXid(); + + cifs_sb = CIFS_SB(direntry->d_sb); + + /* can not safely grab the rename sem here if + rename calls revalidate since that would deadlock */ + full_path = build_path_from_dentry(direntry); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + cFYI(1, + ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld", + full_path, direntry->d_inode, + direntry->d_inode->i_count.counter, direntry, + direntry->d_time, jiffies)); + + if (cifsInode->time == 0){ + /* was set to zero previously to force revalidate */ + } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) { + if((S_ISREG(direntry->d_inode->i_mode) == 0) || + (direntry->d_inode->i_nlink == 1)) { + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; + } else { + cFYI(1,("Have to revalidate file due to hardlinks")); + } + } + + /* save mtime and size */ + local_mtime = direntry->d_inode->i_mtime; + local_size = direntry->d_inode->i_size; + + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { + rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path, + direntry->d_sb,xid); + if(rc) { + cFYI(1,("error on getting revalidate info %d",rc)); +/* if(rc != -ENOENT) + rc = 0; */ /* BB should we cache info on certain errors? */ + } + } else { + rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, + direntry->d_sb,xid); + if(rc) { + cFYI(1,("error on getting revalidate info %d",rc)); +/* if(rc != -ENOENT) + rc = 0; */ /* BB should we cache info on certain errors? */ + } + } + /* should we remap certain errors, access denied?, to zero */ + + /* if not oplocked, we invalidate inode pages if mtime + or file size had changed on server */ + + if((local_mtime == direntry->d_inode->i_mtime) && + (local_size == direntry->d_inode->i_size)) { + cFYI(1,("cifs_revalidate - inode unchanged")); + } else { + /* file may have changed on server */ + if(cifsInode->clientCanCacheRead) { + /* no need to invalidate inode pages since we were + the only ones who could have modified the file and + the server copy is staler than ours */ + } else { + invalidate_inode = TRUE; + } + } + + /* can not grab this sem since kernel filesys locking + documentation indicates i_sem may be taken by the kernel + on lookup and rename which could deadlock if we grab + the i_sem here as well */ +/* down(&direntry->d_inode->i_sem);*/ + /* need to write out dirty pages here */ + if(direntry->d_inode->i_mapping) { + /* do we need to lock inode until after invalidate completes below? */ + filemap_fdatasync(direntry->d_inode->i_mapping); + } + if(invalidate_inode) { + filemap_fdatawait(direntry->d_inode->i_mapping); + /* may eventually have to do this for open files too */ + if(list_empty(&(cifsInode->openFileList))) { + /* Has changed on server - flush read ahead pages */ + cFYI(1,("Invalidating read ahead data on closed file")); + invalidate_inode_pages(direntry->d_inode); + } + } +/* up(&direntry->d_inode->i_sem);*/ + + if (full_path) + kfree(full_path); + FreeXid(xid); + + return rc; +} + +/* int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + int err = cifs_revalidate(dentry); + if (!err) + generic_fillattr(dentry->d_inode, stat); + return err; +} */ + +void +cifs_truncate_file(struct inode *inode) +{ /* BB remove - may not need this function after all BB */ + int xid; + int rc = -EIO; + int found = FALSE; + struct cifsFileInfo *open_file = NULL; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsInodeInfo *cifsInode; + struct dentry *dirent; + struct list_head * tmp; + char *full_path = NULL; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + /* To avoid spurious oplock breaks from server, in the case + of inodes that we already have open, avoid doing path + based setting of file size if we can do it by handle. + This keeps our caching token (oplock) and avoids + timeouts when the local oplock break takes longer to flush + writebehind data than the SMB timeout for the SetPathInfo + request would allow */ + read_lock(&GlobalSMBSeslock); + cifsInode = CIFS_I(inode); + list_for_each(tmp, &cifsInode->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, flist); + /* We check if file is open for writing first */ + if((open_file->pfile) && (!open_file->invalidHandle) && + ((open_file->pfile->f_flags & O_RDWR) || + (open_file->pfile->f_flags & O_WRONLY))) { + read_unlock(&GlobalSMBSeslock); + found = TRUE; + rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size, + open_file->netfid,open_file->pid,FALSE); + if(rc == 0) { + FreeXid(xid); + return; + } + /* Do not need reopen and retry on EAGAIN since we will + retry by pathname below */ + if(rc == -EAGAIN) + rc = -EHOSTDOWN; + + break; /* now that we found one valid file handle no + sense continuing to loop trying others */ + } + } + if(found == FALSE) + read_unlock(&GlobalSMBSeslock); + + if (list_empty(&inode->i_dentry)) { + cERROR(1, + ("Can not get pathname from empty dentry in inode 0x%p ", + inode)); + FreeXid(xid); + return; + } + + dirent = list_entry(inode->i_dentry.next, struct dentry, d_alias); + if (dirent) { + full_path = build_path_from_dentry(dirent); + rc = CIFSSMBSetEOF(xid, pTcon, full_path, inode->i_size,FALSE, + cifs_sb->local_nls); + cFYI(1,(" SetEOF (truncate) rc = %d",rc)); + if (!rc) + CIFSSMBSetEOF(xid,pTcon,full_path,inode->i_size,TRUE,cifs_sb->local_nls); + /* allocation size setting seems optional so ignore return code */ + } + if (full_path) + kfree(full_path); + FreeXid(xid); + return; +} + +static int cifs_truncate_page(struct address_space *mapping, loff_t from) +{ + unsigned long index = from >> PAGE_CACHE_SHIFT; + unsigned offset = from & (PAGE_CACHE_SIZE-1); + struct page *page; + char *kaddr; + int rc = 0; + + page = grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + unlock_page(page); + page_cache_release(page); + return rc; +} + +int +cifs_setattr(struct dentry *direntry, struct iattr *attrs) +{ + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + int rc = -EACCES; + int found = FALSE; + struct cifsFileInfo *open_file = NULL; + FILE_BASIC_INFO time_buf; + int set_time = FALSE; + __u64 mode = 0xFFFFFFFFFFFFFFFFULL; + __u64 uid = 0xFFFFFFFFFFFFFFFFULL; + __u64 gid = 0xFFFFFFFFFFFFFFFFULL; + struct cifsInodeInfo *cifsInode; + struct list_head * tmp; + + xid = GetXid(); + + cFYI(1, + (" In cifs_setattr, name = %s attrs->iavalid 0x%x ", + direntry->d_name.name, attrs->ia_valid)); + cifs_sb = CIFS_SB(direntry->d_inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&direntry->d_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&direntry->d_sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + cifsInode = CIFS_I(direntry->d_inode); + + /* BB check if we need to refresh inode from server now ? BB */ + + /* need to flush data before changing file size on server */ + filemap_fdatasync(direntry->d_inode->i_mapping); + + if (attrs->ia_valid & ATTR_SIZE) { + read_lock(&GlobalSMBSeslock); + /* To avoid spurious oplock breaks from server, in the case + of inodes that we already have open, avoid doing path + based setting of file size if we can do it by handle. + This keeps our caching token (oplock) and avoids + timeouts when the local oplock break takes longer to flush + writebehind data than the SMB timeout for the SetPathInfo + request would allow */ + list_for_each(tmp, &cifsInode->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, flist); + /* We check if file is open for writing first */ + if((open_file->pfile) && + ((open_file->pfile->f_flags & O_RDWR) || + (open_file->pfile->f_flags & O_WRONLY))) { + if(open_file->invalidHandle == FALSE) { + /* we found a valid, writeable network file + handle to use to try to set the file size */ + __u16 nfid = open_file->netfid; + __u32 npid = open_file->pid; + read_unlock(&GlobalSMBSeslock); + found = TRUE; + rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, + nfid,npid,FALSE); + cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc)); + /* Do not need reopen and retry on EAGAIN since we will + retry by pathname below */ + + break; /* now that we found one valid file handle no + sense continuing to loop trying others */ + } + } + } + if(found == FALSE) { + read_unlock(&GlobalSMBSeslock); + } + + + if(rc != 0) { + /* Set file size by pathname rather than by handle either + because no valid, writeable file handle for it was found or + because there was an error setting it by handle */ + rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE, + cifs_sb->local_nls); + cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc)); + } + + /* Server is ok setting allocation size implicitly - no need to call: */ + /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/ + + if (rc == 0) { + rc = vmtruncate(direntry->d_inode, attrs->ia_size); + cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size); + } + } + if (attrs->ia_valid & ATTR_UID) { + cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); + uid = attrs->ia_uid; + /* entry->uid = cpu_to_le16(attr->ia_uid); */ + } + if (attrs->ia_valid & ATTR_GID) { + cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); + gid = attrs->ia_gid; + /* entry->gid = cpu_to_le16(attr->ia_gid); */ + } + + time_buf.Attributes = 0; + if (attrs->ia_valid & ATTR_MODE) { + cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); + mode = attrs->ia_mode; + /* entry->mode = cpu_to_le16(attr->ia_mode); */ + } + + if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) + && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) + rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, + 0 /* dev_t */, cifs_sb->local_nls); + else if (attrs->ia_valid & ATTR_MODE) { + if((mode & S_IWUGO) == 0) /* not writeable */ { + if((cifsInode->cifsAttrs & ATTR_READONLY) == 0) + time_buf.Attributes = + cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY); + } else if((mode & S_IWUGO) == S_IWUGO) { + if(cifsInode->cifsAttrs & ATTR_READONLY) + time_buf.Attributes = + cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY)); + } + /* BB to be implemented - via Windows security descriptors or streams */ + /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/ + } + + if (attrs->ia_valid & ATTR_ATIME) { + set_time = TRUE; + time_buf.LastAccessTime = + cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); + } else + time_buf.LastAccessTime = 0; + + if (attrs->ia_valid & ATTR_MTIME) { + set_time = TRUE; + time_buf.LastWriteTime = + cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); + } else + time_buf.LastWriteTime = 0; + + if (attrs->ia_valid & ATTR_CTIME) { + set_time = TRUE; + time_buf.ChangeTime = + cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); + } else + time_buf.ChangeTime = 0; + + if (set_time | time_buf.Attributes) { + /* BB what if setting one attribute fails + (such as size) but time setting works */ + time_buf.CreationTime = 0; /* do not change */ + /* In the future we should experiment - try setting timestamps + via Handle (SetFileInfo) instead of by path */ + rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, + cifs_sb->local_nls); + } + + /* do not need local check to inode_check_ok since the server does that */ + if (!rc) + rc = inode_setattr(direntry->d_inode, attrs); + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +void +cifs_delete_inode(struct inode *inode) +{ + cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode)); + /* may have to add back in if and when safe distributed caching of + directories added e.g. via FindNotify */ +} diff -urN linux-2.4.27/fs/cifs/link.c linux-2.4.27-cifs-1.20c/fs/cifs/link.c --- linux-2.4.27/fs/cifs/link.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/link.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,328 @@ +/* + * fs/cifs/link.c + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include "cifsfs.h" +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" + +int +cifs_hardlink(struct dentry *old_file, struct inode *inode, + struct dentry *direntry) +{ + int rc = -EACCES; + int xid; + char *fromName = NULL; + char *toName = NULL; + struct cifs_sb_info *cifs_sb_target; + struct cifsTconInfo *pTcon; + struct cifsInodeInfo *cifsInode; + + xid = GetXid(); + + cifs_sb_target = CIFS_SB(inode->i_sb); + pTcon = cifs_sb_target->tcon; + +/* No need to check for cross device links since server will do that + BB note DFS case in future though (when we may have to check) */ + + down(&inode->i_sb->s_vfs_rename_sem); + fromName = build_path_from_dentry(old_file); + toName = build_path_from_dentry(direntry); + up(&inode->i_sb->s_vfs_rename_sem); + if((fromName == NULL) || (toName == NULL)) { + rc = -ENOMEM; + goto cifs_hl_exit; + } + + if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX) + rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, + cifs_sb_target->local_nls); + else { + rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, + cifs_sb_target->local_nls); + if(rc == -EIO) + rc = -EOPNOTSUPP; + } + +/* if (!rc) */ + { + /* renew_parental_timestamps(old_file); + inode->i_nlink++; + mark_inode_dirty(inode); + d_instantiate(direntry, inode); */ + /* BB add call to either mark inode dirty or refresh its data and timestamp to current time */ + } + d_drop(direntry); /* force new lookup from server */ + cifsInode = CIFS_I(old_file->d_inode); + cifsInode->time = 0; /* will force revalidate to go get info when needed */ + +cifs_hl_exit: + if (fromName) + kfree(fromName); + if (toName) + kfree(toName); + FreeXid(xid); + return rc; +} + +int +cifs_follow_link(struct dentry *direntry, struct nameidata *nd) +{ + struct inode *inode = direntry->d_inode; + int rc = -EACCES; + int xid; + char *full_path = NULL; + char * target_path; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + + xid = GetXid(); + + down(&direntry->d_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&direntry->d_sb->s_vfs_rename_sem); + + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + target_path = kmalloc(PATH_MAX, GFP_KERNEL); + if(target_path == NULL) { + if (full_path) + kfree(full_path); + FreeXid(xid); + return -ENOMEM; + } + /* can not call the following line due to EFAULT in vfs_readlink which is presumably expecting a user space buffer */ + /* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1); */ + +/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ + if (pTcon->ses->capabilities & CAP_UNIX) + rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, + target_path, + PATH_MAX-1, + cifs_sb->local_nls); + else { + /* rc = CIFSSMBQueryReparseLinkInfo */ + /* BB Add code to Query ReparsePoint info */ + } + /* BB Anything else to do to handle recursive links? */ + /* BB Should we be using page symlink ops here? */ + + if (rc == 0) { + +/* BB Add special case check for Samba DFS symlinks */ + + target_path[PATH_MAX-1] = 0; + rc = vfs_follow_link(nd, target_path); + } + /* else EACCESS */ + + if (target_path) + kfree(target_path); + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +int +cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) +{ + int rc = -EOPNOTSUPP; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + struct inode *newinode = NULL; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&inode->i_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&inode->i_sb->s_vfs_rename_sem); + + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + + cFYI(1, ("Full path: %s ", full_path)); + cFYI(1, ("symname is %s", symname)); + + /* BB what if DFS and this volume is on different share? BB */ + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, + cifs_sb->local_nls); + /* else + rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */ + + if (rc == 0) { + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb,xid); + else + rc = cifs_get_inode_info(&newinode, full_path, NULL, + inode->i_sb,xid); + + if (rc != 0) { + cFYI(1, + ("Create symlink worked but get_inode_info failed with rc = %d ", + rc)); + } else { + direntry->d_op = &cifs_dentry_ops; + d_instantiate(direntry, newinode); + } + } + + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +int +cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) +{ + struct inode *inode = direntry->d_inode; + int rc = -EACCES; + int xid; + int oplock = FALSE; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + char *tmp_path = NULL; + char * tmpbuffer; + unsigned char * referrals = NULL; + int num_referrals = 0; + int len; + __u16 fid; + + xid = GetXid(); + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + +/* BB would it be safe against deadlock to grab this sem + even though rename itself grabs the sem and calls lookup? */ +/* down(&inode->i_sb->s_vfs_rename_sem);*/ + full_path = build_path_from_dentry(direntry); +/* up(&inode->i_sb->s_vfs_rename_sem);*/ + + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + + cFYI(1, + ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d", + full_path, inode, pBuffer, buflen)); + if(buflen > PATH_MAX) + len = PATH_MAX; + else + len = buflen; + tmpbuffer = kmalloc(len,GFP_KERNEL); + if(tmpbuffer == NULL) { + if (full_path) + kfree(full_path); + FreeXid(xid); + return -ENOMEM; + } + +/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, + tmpbuffer, + len - 1, + cifs_sb->local_nls); + else { + rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, + OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls); + if(!rc) { + rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, + tmpbuffer, + len - 1, + fid, + cifs_sb->local_nls); + if(CIFSSMBClose(xid, pTcon, fid)) { + cFYI(1,("Error closing junction point (open for ioctl)")); + } + if(rc == -EIO) { + /* Query if DFS Junction */ + tmp_path = + kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1, + GFP_KERNEL); + if (tmp_path) { + strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); + strncat(tmp_path, full_path, MAX_PATHCONF); + rc = get_dfs_path(xid, pTcon->ses, tmp_path, + cifs_sb->local_nls, &num_referrals, &referrals); + cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc)); + if((num_referrals == 0) && (rc == 0)) + rc = -EACCES; + else { + cFYI(1,("num referral: %d",num_referrals)); + if(referrals) { + cFYI(1,("referral string: %s ",referrals)); + strncpy(tmpbuffer, referrals, len-1); + } + } + if(referrals) + kfree(referrals); + kfree(tmp_path); + if(referrals) { + kfree(referrals); + } + } + /* BB add code like else decode referrals then memcpy to + tmpbuffer and free referrals string array BB */ + } + } + } + /* BB Anything else to do to handle recursive links? */ + /* BB Should we be using page ops here? */ + + /* BB null terminate returned string in pBuffer? BB */ + if (rc == 0) { + rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer); + cFYI(1, + ("vfs_readlink called from cifs_readlink returned %d", + rc)); + } + + if (tmpbuffer) { + kfree(tmpbuffer); + } + if (full_path) { + kfree(full_path); + } + FreeXid(xid); + return rc; +} diff -urN linux-2.4.27/fs/cifs/md4.c linux-2.4.27-cifs-1.20c/fs/cifs/md4.c --- linux-2.4.27/fs/cifs/md4.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/md4.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,203 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + a implementation of MD4 designed for use in the SMB authentication protocol + Copyright (C) Andrew Tridgell 1997-1998. + Modified by Steve French (sfrench@us.ibm.com) 2002-2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include +/* NOTE: This code makes no attempt to be fast! */ + +static __u32 +F(__u32 X, __u32 Y, __u32 Z) +{ + return (X & Y) | ((~X) & Z); +} + +static __u32 +G(__u32 X, __u32 Y, __u32 Z) +{ + return (X & Y) | (X & Z) | (Y & Z); +} + +static __u32 +H(__u32 X, __u32 Y, __u32 Z) +{ + return X ^ Y ^ Z; +} + +static __u32 +lshift(__u32 x, int s) +{ + x &= 0xFFFFFFFF; + return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); +} + +#define ROUND1(a,b,c,d,k,s) (*a) = lshift((*a) + F(*b,*c,*d) + X[k], s) +#define ROUND2(a,b,c,d,k,s) (*a) = lshift((*a) + G(*b,*c,*d) + X[k] + (__u32)0x5A827999,s) +#define ROUND3(a,b,c,d,k,s) (*a) = lshift((*a) + H(*b,*c,*d) + X[k] + (__u32)0x6ED9EBA1,s) + +/* this applies md4 to 64 byte chunks */ +static void +mdfour64(__u32 * M, __u32 * A, __u32 *B, __u32 * C, __u32 *D) +{ + int j; + __u32 AA, BB, CC, DD; + __u32 X[16]; + + + for (j = 0; j < 16; j++) + X[j] = M[j]; + + AA = *A; + BB = *B; + CC = *C; + DD = *D; + + ROUND1(A, B, C, D, 0, 3); + ROUND1(D, A, B, C, 1, 7); + ROUND1(C, D, A, B, 2, 11); + ROUND1(B, C, D, A, 3, 19); + ROUND1(A, B, C, D, 4, 3); + ROUND1(D, A, B, C, 5, 7); + ROUND1(C, D, A, B, 6, 11); + ROUND1(B, C, D, A, 7, 19); + ROUND1(A, B, C, D, 8, 3); + ROUND1(D, A, B, C, 9, 7); + ROUND1(C, D, A, B, 10, 11); + ROUND1(B, C, D, A, 11, 19); + ROUND1(A, B, C, D, 12, 3); + ROUND1(D, A, B, C, 13, 7); + ROUND1(C, D, A, B, 14, 11); + ROUND1(B, C, D, A, 15, 19); + + ROUND2(A, B, C, D, 0, 3); + ROUND2(D, A, B, C, 4, 5); + ROUND2(C, D, A, B, 8, 9); + ROUND2(B, C, D, A, 12, 13); + ROUND2(A, B, C, D, 1, 3); + ROUND2(D, A, B, C, 5, 5); + ROUND2(C, D, A, B, 9, 9); + ROUND2(B, C, D, A, 13, 13); + ROUND2(A, B, C, D, 2, 3); + ROUND2(D, A, B, C, 6, 5); + ROUND2(C, D, A, B, 10, 9); + ROUND2(B, C, D, A, 14, 13); + ROUND2(A, B, C, D, 3, 3); + ROUND2(D, A, B, C, 7, 5); + ROUND2(C, D, A, B, 11, 9); + ROUND2(B, C, D, A, 15, 13); + + ROUND3(A, B, C, D, 0, 3); + ROUND3(D, A, B, C, 8, 9); + ROUND3(C, D, A, B, 4, 11); + ROUND3(B, C, D, A, 12, 15); + ROUND3(A, B, C, D, 2, 3); + ROUND3(D, A, B, C, 10, 9); + ROUND3(C, D, A, B, 6, 11); + ROUND3(B, C, D, A, 14, 15); + ROUND3(A, B, C, D, 1, 3); + ROUND3(D, A, B, C, 9, 9); + ROUND3(C, D, A, B, 5, 11); + ROUND3(B, C, D, A, 13, 15); + ROUND3(A, B, C, D, 3, 3); + ROUND3(D, A, B, C, 11, 9); + ROUND3(C, D, A, B, 7, 11); + ROUND3(B, C, D, A, 15, 15); + + *A += AA; + *B += BB; + *C += CC; + *D += DD; + + *A &= 0xFFFFFFFF; + *B &= 0xFFFFFFFF; + *C &= 0xFFFFFFFF; + *D &= 0xFFFFFFFF; + + for (j = 0; j < 16; j++) + X[j] = 0; +} + +static void +copy64(__u32 * M, unsigned char *in) +{ + int i; + + for (i = 0; i < 16; i++) + M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) | + (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0); +} + +static void +copy4(unsigned char *out, __u32 x) +{ + out[0] = x & 0xFF; + out[1] = (x >> 8) & 0xFF; + out[2] = (x >> 16) & 0xFF; + out[3] = (x >> 24) & 0xFF; +} + +/* produce a md4 message digest from data of length n bytes */ +void +mdfour(unsigned char *out, unsigned char *in, int n) +{ + unsigned char buf[128]; + __u32 M[16]; + __u32 b = n * 8; + int i; + __u32 A = 0x67452301; + __u32 B = 0xefcdab89; + __u32 C = 0x98badcfe; + __u32 D = 0x10325476; + + while (n > 64) { + copy64(M, in); + mdfour64(M,&A,&B, &C, &D); + in += 64; + n -= 64; + } + + for (i = 0; i < 128; i++) + buf[i] = 0; + memcpy(buf, in, n); + buf[n] = 0x80; + + if (n <= 55) { + copy4(buf + 56, b); + copy64(M, buf); + mdfour64(M, &A, &B, &C, &D); + } else { + copy4(buf + 120, b); + copy64(M, buf); + mdfour64(M, &A, &B, &C, &D); + copy64(M, buf + 64); + mdfour64(M, &A, &B, &C, &D); + } + + for (i = 0; i < 128; i++) + buf[i] = 0; + copy64(M, buf); + + copy4(out, A); + copy4(out + 4, B); + copy4(out + 8, C); + copy4(out + 12, D); + + A = B = C = D = 0; +} diff -urN linux-2.4.27/fs/cifs/md5.c linux-2.4.27-cifs-1.20c/fs/cifs/md5.c --- linux-2.4.27/fs/cifs/md5.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/md5.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,363 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +/* This code slightly modified to fit into Samba by + abartlet@samba.org Jun 2001 + and to fit the cifs vfs by + Steve French sfrench@us.ibm.com */ + +#include +#include "md5.h" + +static void MD5Transform(__u32 buf[4], __u32 const in[16]); + +/* + * Note: this code is harmless on little-endian machines. + */ +static void +byteReverse(unsigned char *buf, unsigned longs) +{ + __u32 t; + do { + t = (__u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(__u32 *) buf = t; + buf += 4; + } while (--longs); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) +{ + register __u32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((__u32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memmove(p, buf, len); + return; + } + memmove(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (__u32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memmove(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (__u32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memmove(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned int count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (__u32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((__u32 *) ctx->in)[14] = ctx->bits[0]; + ((__u32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (__u32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memmove(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void +MD5Transform(__u32 buf[4], __u32 const in[16]) +{ + register __u32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/*********************************************************************** + the rfc 2104 version of hmac_md5 initialisation. +***********************************************************************/ +void +hmac_md5_init_rfc2104(unsigned char *key, int key_len, + struct HMACMD5Context *ctx) +{ + int i; + + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + unsigned char tk[16]; + struct MD5Context tctx; + + MD5Init(&tctx); + MD5Update(&tctx, key, key_len); + MD5Final(tk, &tctx); + + key = tk; + key_len = 16; + } + + /* start out by storing key in pads */ + memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad)); + memset(ctx->k_opad, 0, sizeof (ctx->k_opad)); + memcpy(ctx->k_ipad, key, key_len); + memcpy(ctx->k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < 64; i++) { + ctx->k_ipad[i] ^= 0x36; + ctx->k_opad[i] ^= 0x5c; + } + + MD5Init(&ctx->ctx); + MD5Update(&ctx->ctx, ctx->k_ipad, 64); +} + +/*********************************************************************** + the microsoft version of hmac_md5 initialisation. +***********************************************************************/ +void +hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, + struct HMACMD5Context *ctx) +{ + int i; + + /* if key is longer than 64 bytes truncate it */ + if (key_len > 64) { + key_len = 64; + } + + /* start out by storing key in pads */ + memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad)); + memset(ctx->k_opad, 0, sizeof (ctx->k_opad)); + memcpy(ctx->k_ipad, key, key_len); + memcpy(ctx->k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < 64; i++) { + ctx->k_ipad[i] ^= 0x36; + ctx->k_opad[i] ^= 0x5c; + } + + MD5Init(&ctx->ctx); + MD5Update(&ctx->ctx, ctx->k_ipad, 64); +} + +/*********************************************************************** + update hmac_md5 "inner" buffer +***********************************************************************/ +void +hmac_md5_update(const unsigned char *text, int text_len, + struct HMACMD5Context *ctx) +{ + MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */ +} + +/*********************************************************************** + finish off hmac_md5 "inner" buffer and generate outer one. +***********************************************************************/ +void +hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) +{ + struct MD5Context ctx_o; + + MD5Final(digest, &ctx->ctx); + + MD5Init(&ctx_o); + MD5Update(&ctx_o, ctx->k_opad, 64); + MD5Update(&ctx_o, digest, 16); + MD5Final(digest, &ctx_o); +} + +/*********************************************************** + single function to calculate an HMAC MD5 digest from data. + use the microsoft hmacmd5 init method because the key is 16 bytes. +************************************************************/ +void +hmac_md5(unsigned char key[16], unsigned char *data, int data_len, + unsigned char *digest) +{ + struct HMACMD5Context ctx; + hmac_md5_init_limK_to_64(key, 16, &ctx); + if (data_len != 0) { + hmac_md5_update(data, data_len, &ctx); + } + hmac_md5_final(digest, &ctx); +} diff -urN linux-2.4.27/fs/cifs/md5.h linux-2.4.27-cifs-1.20c/fs/cifs/md5.h --- linux-2.4.27/fs/cifs/md5.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/md5.h Wed Jul 14 00:25:05 2004 @@ -0,0 +1,38 @@ +#ifndef MD5_H +#define MD5_H +#ifndef HEADER_MD5_H +/* Try to avoid clashes with OpenSSL */ +#define HEADER_MD5_H +#endif + +struct MD5Context { + __u32 buf[4]; + __u32 bits[2]; + unsigned char in[64]; +}; +#endif /* !MD5_H */ + +#ifndef _HMAC_MD5_H +struct HMACMD5Context { + struct MD5Context ctx; + unsigned char k_ipad[65]; + unsigned char k_opad[65]; +}; +#endif /* _HMAC_MD5_H */ + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, unsigned char const *buf, + unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); + +/* The following definitions come from lib/hmacmd5.c */ + +void hmac_md5_init_rfc2104(unsigned char *key, int key_len, + struct HMACMD5Context *ctx); +void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, + struct HMACMD5Context *ctx); +void hmac_md5_update(const unsigned char *text, int text_len, + struct HMACMD5Context *ctx); +void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx); +void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, + unsigned char *digest); diff -urN linux-2.4.27/fs/cifs/misc.c linux-2.4.27-cifs-1.20c/fs/cifs/misc.c --- linux-2.4.27/fs/cifs/misc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/misc.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,463 @@ +/* + * fs/cifs/misc.c + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "smberr.h" +#include "nterr.h" + +extern kmem_cache_t *cifs_req_cachep; +extern struct task_struct * oplockThread; + +__u16 GlobalMid; /* multiplex id - rotating counter */ + +/* The xid serves as a useful identifier for each incoming vfs request, + in a similar way to the mid which is useful to track each sent smb, + and CurrentXid can also provide a running counter (although it + will eventually wrap past zero) of the total vfs operations handled + since the cifs fs was mounted */ + +unsigned int +_GetXid(void) +{ + unsigned int xid; + + spin_lock(&GlobalMid_Lock); + GlobalTotalActiveXid++; + if (GlobalTotalActiveXid > GlobalMaxActiveXid) + GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ + xid = GlobalCurrentXid++; + spin_unlock(&GlobalMid_Lock); + return xid; +} + +void +_FreeXid(unsigned int xid) +{ + spin_lock(&GlobalMid_Lock); + /* if(GlobalTotalActiveXid == 0) + BUG(); */ + GlobalTotalActiveXid--; + spin_unlock(&GlobalMid_Lock); +} + +struct cifsSesInfo * +sesInfoAlloc(void) +{ + struct cifsSesInfo *ret_buf; + + ret_buf = + (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo), + GFP_KERNEL); + if (ret_buf) { + memset(ret_buf, 0, sizeof (struct cifsSesInfo)); + write_lock(&GlobalSMBSeslock); + atomic_inc(&sesInfoAllocCount); + ret_buf->status = CifsNew; + list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList); + init_MUTEX(&ret_buf->sesSem); + write_unlock(&GlobalSMBSeslock); + } + return ret_buf; +} + +void +sesInfoFree(struct cifsSesInfo *buf_to_free) +{ + if (buf_to_free == NULL) { + cFYI(1, ("Null buffer passed to sesInfoFree")); + return; + } + + write_lock(&GlobalSMBSeslock); + atomic_dec(&sesInfoAllocCount); + list_del(&buf_to_free->cifsSessionList); + write_unlock(&GlobalSMBSeslock); + if (buf_to_free->serverOS) + kfree(buf_to_free->serverOS); + if (buf_to_free->serverDomain) + kfree(buf_to_free->serverDomain); + if (buf_to_free->serverNOS) + kfree(buf_to_free->serverNOS); + if (buf_to_free->password) + kfree(buf_to_free->password); + kfree(buf_to_free); +} + +struct cifsTconInfo * +tconInfoAlloc(void) +{ + struct cifsTconInfo *ret_buf; + ret_buf = + (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo), + GFP_KERNEL); + if (ret_buf) { + memset(ret_buf, 0, sizeof (struct cifsTconInfo)); + write_lock(&GlobalSMBSeslock); + atomic_inc(&tconInfoAllocCount); + list_add(&ret_buf->cifsConnectionList, + &GlobalTreeConnectionList); + ret_buf->tidStatus = CifsNew; + INIT_LIST_HEAD(&ret_buf->openFileList); + init_MUTEX(&ret_buf->tconSem); +#ifdef CONFIG_CIFS_STATS + ret_buf->stat_lock = SPIN_LOCK_UNLOCKED; +#endif + write_unlock(&GlobalSMBSeslock); + } + return ret_buf; +} + +void +tconInfoFree(struct cifsTconInfo *buf_to_free) +{ + if (buf_to_free == NULL) { + cFYI(1, ("Null buffer passed to tconInfoFree")); + return; + } + write_lock(&GlobalSMBSeslock); + atomic_dec(&tconInfoAllocCount); + list_del(&buf_to_free->cifsConnectionList); + write_unlock(&GlobalSMBSeslock); + if (buf_to_free->nativeFileSystem) + kfree(buf_to_free->nativeFileSystem); + kfree(buf_to_free); +} + +struct smb_hdr * +cifs_buf_get(void) +{ + struct smb_hdr *ret_buf = NULL; + +/* We could use negotiated size instead of max_msgsize - + but it may be more efficient to always alloc same size + albeit slightly larger than necessary and maxbuffersize + defaults to this and can not be bigger */ + ret_buf = + (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL); + + /* clear the first few header bytes */ + if (ret_buf) { + memset(ret_buf, 0, sizeof (struct smb_hdr)); + atomic_inc(&bufAllocCount); + } + + return ret_buf; +} + +void +cifs_buf_release(void *buf_to_free) +{ + + if (buf_to_free == NULL) { + cFYI(1, ("Null buffer passed to cifs_buf_release")); + return; + } + kmem_cache_free(cifs_req_cachep, buf_to_free); + + atomic_dec(&bufAllocCount); + return; +} + +void +header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , + const struct cifsTconInfo *treeCon, int word_count + /* length of fixed section (word count) in two byte units */ + ) +{ + int i; + __u32 tmp; + struct list_head* temp_item; + struct cifsSesInfo * ses; + char *temp = (char *) buffer; + + for (i = 0; i < MAX_CIFS_HDR_SIZE; i++) { + temp[i] = 0; /* BB is this needed ?? */ + } + + buffer->smb_buf_length = + (2 * word_count) + sizeof (struct smb_hdr) - + 4 /* RFC 1001 length field does not count */ + + 2 /* for bcc field itself */ ; + /* 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 */ + + buffer->Protocol[0] = 0xFF; + buffer->Protocol[1] = 'S'; + buffer->Protocol[2] = 'M'; + buffer->Protocol[3] = 'B'; + buffer->Command = smb_command; + buffer->Flags = 0x00; /* case sensitive */ + buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES; + tmp = cpu_to_le32(current->pid); + buffer->Pid = tmp & 0xFFFF; + tmp >>= 16; + buffer->PidHigh = tmp & 0xFFFF; + spin_lock(&GlobalMid_Lock); + GlobalMid++; + buffer->Mid = GlobalMid; + spin_unlock(&GlobalMid_Lock); + if (treeCon) { + buffer->Tid = treeCon->tid; + if (treeCon->ses) { + if (treeCon->ses->capabilities & CAP_UNICODE) + buffer->Flags2 |= SMBFLG2_UNICODE; + if (treeCon->ses->capabilities & CAP_STATUS32) { + buffer->Flags2 |= SMBFLG2_ERR_STATUS; + } + + buffer->Uid = treeCon->ses->Suid; /* always in LE format */ + if(multiuser_mount != 0) { + /* For the multiuser case, there are few obvious technically */ + /* possible mechanisms to match the local linux user (uid) */ + /* to a valid remote smb user (smb_uid): */ + /* 1) Query Winbind (or other local pam/nss daemon */ + /* for userid/password/logon_domain or credential */ + /* 2) Query Winbind for uid to sid to username mapping */ + /* and see if we have a matching password for existing*/ + /* session for that user perhas getting password by */ + /* adding a new pam_cifs module that stores passwords */ + /* so that the cifs vfs can get at that for all logged*/ + /* on users */ + /* 3) (Which is the mechanism we have chosen) */ + /* Search through sessions to the same server for a */ + /* a match on the uid that was passed in on mount */ + /* with the current processes uid (or euid?) and use */ + /* that smb uid. If no existing smb session for */ + /* that uid found, use the default smb session ie */ + /* the smb session for the volume mounted which is */ + /* the same as would be used if the multiuser mount */ + /* flag were disabled. */ + + /* BB Add support for establishing new tCon and SMB Session */ + /* with userid/password pairs found on the smb session */ + /* for other target tcp/ip addresses BB */ + if(current->uid != treeCon->ses->linux_uid) { + cFYI(1,("Multiuser mode and UID did not match tcon uid ")); + read_lock(&GlobalSMBSeslock); + list_for_each(temp_item, &GlobalSMBSessionList) { + ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); + if(ses->linux_uid == current->uid) { + if(ses->server == treeCon->ses->server) { + cFYI(1,("found matching uid substitute right smb_uid")); + buffer->Uid = ses->Suid; + break; + } else { + /* BB eventually call cifs_setup_session here */ + cFYI(1,("local UID found but smb sess with this server does not exist")); + } + } + } + read_unlock(&GlobalSMBSeslock); + } + } + } + if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) + buffer->Flags2 |= SMBFLG2_DFS; + if(treeCon->ses->server) + if(treeCon->ses->server->secMode & + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + } + +/* endian conversion of flags is now done just before sending */ + buffer->WordCount = (char) word_count; + return; +} + +int +checkSMBhdr(struct smb_hdr *smb, __u16 mid) +{ + /* Make sure that this really is an SMB, that it is a response, + and that the message ids match */ + if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) && + (mid == smb->Mid)) { + if(smb->Flags & SMBFLG_RESPONSE) + return 0; + else { + /* only one valid case where server sends us request */ + if(smb->Command == SMB_COM_LOCKING_ANDX) + return 0; + else + cERROR(1, ("Rcvd Request not response ")); + } + } else { /* bad signature or mid */ + if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff)) + cERROR(1, + ("Bad protocol string signature header %x ", + *(unsigned int *) smb->Protocol)); + if (mid != smb->Mid) + cERROR(1, ("Mids do not match")); + } + cERROR(1, ("bad smb detected. The Mid=%d", smb->Mid)); + return 1; +} + +int +checkSMB(struct smb_hdr *smb, __u16 mid, int length) +{ + cFYI(0, + ("Entering checkSMB with Length: %x, smb_buf_length: %x ", + length, ntohl(smb->smb_buf_length))); + if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) + || (ntohl(smb->smb_buf_length) > + CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)) { + if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { + cERROR(1, ("Length less than 2 + sizeof smb_hdr ")); + if (((unsigned int)length >= sizeof (struct smb_hdr) - 1) + && (smb->Status.CifsError != 0)) + return 0; /* some error cases do not return wct and bcc */ + + } + if (ntohl(smb->smb_buf_length) > + CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) + cERROR(1, + ("smb_buf_length greater than CIFS_MAX_MSGSIZE ... ")); + cERROR(1, + ("bad smb detected. Illegal length. The mid=%d", + smb->Mid)); + return 1; + } + + if (checkSMBhdr(smb, mid)) + return 1; + + if ((4 + ntohl(smb->smb_buf_length) != smbCalcSize(smb)) + || (4 + ntohl(smb->smb_buf_length) != (unsigned int)length)) { + return 0; + } else { + cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); + cERROR(1, + ("bad smb size detected. The Mid=%d", smb->Mid)); + return 1; + } +} +int +is_valid_oplock_break(struct smb_hdr *buf) +{ + struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf; + struct list_head *tmp; + struct list_head *tmp1; + struct cifsTconInfo *tcon; + struct cifsFileInfo *netfile; + + /* could add check for smb response flag 0x80 */ + cFYI(1,("Checking for oplock break")); + if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) + return FALSE; + if(pSMB->hdr.Flags & SMBFLG_RESPONSE) { + /* no sense logging error on invalid handle on oplock + break - harmless race between close request and oplock + break response is expected from time to time writing out + large dirty files cached on the client */ + if ((NT_STATUS_INVALID_HANDLE) == + le32_to_cpu(pSMB->hdr.Status.CifsError)) { + cFYI(1,("invalid handle on oplock break")); + return TRUE; + } else if (ERRbadfid == + le16_to_cpu(pSMB->hdr.Status.DosError.Error)) { + return TRUE; + } else { + return FALSE; /* on valid oplock brk we get "request" */ + } + } + if(pSMB->hdr.WordCount != 8) + return FALSE; + + cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel)); + if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) + return FALSE; + + /* look up tcon based on tid & uid */ + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalTreeConnectionList) { + tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + if (tcon->tid == buf->Tid) { +#ifdef CONFIG_CIFS_STATS + atomic_inc(&tcon->num_oplock_brks); +#endif + list_for_each(tmp1,&tcon->openFileList){ + netfile = list_entry(tmp1,struct cifsFileInfo,tlist); + if(pSMB->Fid == netfile->netfid) { + struct cifsInodeInfo *pCifsInode; + read_unlock(&GlobalSMBSeslock); + cFYI(1,("Matching file id, processing oplock break")); + pCifsInode = + CIFS_I(netfile->pInode); + pCifsInode->clientCanCacheAll = FALSE; + if(pSMB->OplockLevel == 0) + pCifsInode->clientCanCacheRead = FALSE; + pCifsInode->oplockPending = TRUE; + AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon); + cFYI(1,("about to wake up oplock thd")); + wake_up_process(oplockThread); + return TRUE; + } + } + read_unlock(&GlobalSMBSeslock); + cFYI(1,("No matching file for oplock break on connection")); + return TRUE; + } + } + read_unlock(&GlobalSMBSeslock); + cFYI(1,("Can not process oplock break for non-existent connection")); + return TRUE; +} + +void +dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) +{ + int i, j; + char debug_line[17]; + unsigned char *buffer; + + if (traceSMB == 0) + return; + + buffer = (unsigned char *) smb_buf; + for (i = 0, j = 0; i < smb_buf_length; i++, j++) { + if (i % 8 == 0) { /* we have reached the beginning of line */ + printk(KERN_DEBUG "| "); + j = 0; + } + printk("%0#4x ", buffer[i]); + debug_line[2 * j] = ' '; + if (isprint(buffer[i])) + debug_line[1 + (2 * j)] = buffer[i]; + else + debug_line[1 + (2 * j)] = '_'; + + if (i % 8 == 7) { /* we have reached end of line, time to print ascii */ + debug_line[16] = 0; + printk(" | %s\n", debug_line); + } + } + for (; j < 8; j++) { + printk(" "); + debug_line[2 * j] = ' '; + debug_line[1 + (2 * j)] = ' '; + } + printk( " | %s\n", debug_line); + return; +} diff -urN linux-2.4.27/fs/cifs/netmisc.c linux-2.4.27-cifs-1.20c/fs/cifs/netmisc.c --- linux-2.4.27/fs/cifs/netmisc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/netmisc.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,905 @@ +/* + * fs/cifs/netmisc.c + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * Error mapping routines from Samba libsmb/errormap.c + * Copyright (C) Andrew Tridgell 2001 + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include "cifsfs.h" +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "smberr.h" +#include "cifs_debug.h" +#include "nterr.h" + +struct smb_to_posix_error { + __u16 smb_err; + int posix_code; +}; + +const struct smb_to_posix_error mapping_table_ERRDOS[] = { + {ERRbadfunc, -EINVAL}, + {ERRbadfile, -ENOENT}, + {ERRbadpath, -ENOTDIR}, + {ERRnofids, -EMFILE}, + {ERRnoaccess, -EACCES}, + {ERRbadfid, -EBADF}, + {ERRbadmcb, -EIO}, + {ERRnomem, -ENOMEM}, + {ERRbadmem, -EFAULT}, + {ERRbadenv, -EFAULT}, + {ERRbadformat, -EINVAL}, + {ERRbadaccess, -EACCES}, + {ERRbaddata, -EIO}, + {ERRbaddrive, -ENXIO}, + {ERRremcd, -EACCES}, + {ERRdiffdevice, -EXDEV}, + {ERRnofiles, -ENOENT}, + {ERRbadshare, -ETXTBSY}, + {ERRlock, -EACCES}, + {ERRunsup, -EINVAL}, + {ERRnosuchshare,-ENXIO}, + {ERRfilexists, -EEXIST}, + {ERRinvparm, -EINVAL}, + {ERRdiskfull, -ENOSPC}, + {ERRinvname, -ENOENT}, + {ERRdirnotempty, -ENOTEMPTY}, + {ERRnotlocked, -ENOLCK}, + {ERRalreadyexists, -EEXIST}, + {ERRmoredata, -EOVERFLOW}, + {ErrQuota, -EDQUOT}, + {ErrNotALink, -ENOLINK}, + {ERRnetlogonNotStarted,-ENOPROTOOPT}, + {0, 0} +}; + +const struct smb_to_posix_error mapping_table_ERRSRV[] = { + {ERRerror, -EIO}, + {ERRbadpw, -EPERM}, + {ERRbadtype, -EREMOTE}, + {ERRaccess, -EACCES}, + {ERRinvtid, -ENXIO}, + {ERRinvnetname, -ENODEV}, + {ERRinvdevice, -ENXIO}, + {ERRqfull, -ENOSPC}, + {ERRqtoobig, -ENOSPC}, + {ERRqeof, -EIO}, + {ERRinvpfid, -EBADF}, + {ERRsmbcmd, -EBADRQC}, + {ERRsrverror, -EIO}, + {ERRbadBID, -EIO}, + {ERRfilespecs, -EINVAL}, + {ERRbadLink, -EIO}, + {ERRbadpermits, -EINVAL}, + {ERRbadPID, -ESRCH}, + {ERRsetattrmode, -EINVAL}, + {ERRpaused, -EHOSTDOWN}, + {ERRmsgoff, -EHOSTDOWN}, + {ERRnoroom, -ENOSPC}, + {ERRrmuns, -EUSERS}, + {ERRtimeout, -ETIME}, + {ERRnoresource, -ENOBUFS}, + {ERRtoomanyuids, -EUSERS}, + {ERRbaduid, -EACCES}, + {ERRusempx, -EIO}, + {ERRusestd, -EIO}, + {ERR_NOTIFY_ENUM_DIR, -ENOBUFS}, + {ERRaccountexpired, -EACCES}, + {ERRbadclient, -EACCES}, + {ERRbadLogonTime, -EACCES}, + {ERRpasswordExpired, -EACCES}, + {ERRnosupport, -EINVAL}, + {0, 0} +}; + +const struct smb_to_posix_error mapping_table_ERRHRD[] = { + {0, 0} +}; + +/* Convert string containing dotted ip address to binary form */ +/* returns 0 if invalid address */ + +/* BB add address family, change rc to status flag and return union or for ipv6 */ +/* will need parent to call something like inet_pton to convert ipv6 address BB */ +int +cifs_inet_pton(int address_family, char *cp,void *dst) +{ + struct in_addr address; + int value; + int digit; + int i; + char temp; + char bytes[4]; + char *end = bytes; + static const int addr_class_max[4] = + { 0xffffffff, 0xffffff, 0xffff, 0xff }; + + if(address_family != AF_INET) + return -EAFNOSUPPORT; + + for (i = 0; i < 4; i++) { + bytes[i] = 0; + } + + temp = *cp; + + while (TRUE) { + if (!isdigit(temp)) + return 0; + + value = 0; + digit = 0; + for (;;) { + if (isascii(temp) && isdigit(temp)) { + value = (value * 10) + temp - '0'; + temp = *++cp; + digit = 1; + } else + break; + } + + if (temp == '.') { + if ((end > bytes + 2) || (value > 255)) + return 0; + *end++ = value; + temp = *++cp; + } else if (temp == ':') { + cFYI(1,("IPv6 addresses not supported for CIFS mounts yet")); + return -1; + } else + break; + } + + /* check for last characters */ + if (temp != '\0' && (!isascii(temp) || !isspace(temp))) + if (temp != '\\') { + if (temp != '/') + return 0; + else + (*cp = '\\'); /* switch the slash the expected way */ + } + if (value > addr_class_max[end - bytes]) + return 0; + + address.s_addr = *((int *) bytes) | htonl(value); + *((int *)dst) = address.s_addr; + return 1; /* success */ +} + +/***************************************************************************** +convert a NT status code to a dos class/code + *****************************************************************************/ +/* NT status -> dos error map */ +static const struct { + __u8 dos_class; + __u16 dos_code; + __u32 ntstatus; +} ntstatus_to_dos_map[] = { + { + ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, { + ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, { + ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS}, { + ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, { + ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, { + ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA}, { + ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK}, { + ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC}, { + ERRDOS, 87, NT_STATUS_INVALID_CID}, { + ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER}, { + ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE}, { + ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE}, { + ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST}, { + ERRDOS, 38, NT_STATUS_END_OF_FILE}, { + ERRDOS, 34, NT_STATUS_WRONG_VOLUME}, { + ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE}, { + ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA}, { + ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR}, +/* { This NT error code was 'sqashed' + from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK + during the session setup } */ + { + ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY}, { + ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES}, { + ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW}, { + ERRDOS, 87, NT_STATUS_UNABLE_TO_FREE_VM}, { + ERRDOS, 87, NT_STATUS_UNABLE_TO_DELETE_SECTION}, { + ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE}, { + ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION}, { + ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE}, { + ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE}, { + ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION}, { + ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED}, +/* { This NT error code was 'sqashed' + from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE + during the session setup } */ + { + ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED}, { + ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL}, { + ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH}, { + ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION}, { + ERRHRD, ERRgeneral, NT_STATUS_UNWIND}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET}, { + ERRDOS, 158, NT_STATUS_NOT_LOCKED}, { + ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR}, { + ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM}, { + ERRDOS, 487, NT_STATUS_NOT_COMMITTED}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES}, { + ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_MIX}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER}, { + ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR}, { + ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_INVALID}, { /* mapping changed since shell does lookup on * and expects file not found */ + ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND}, { + ERRDOS, ERRalreadyexists, NT_STATUS_OBJECT_NAME_COLLISION}, { + ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, { + ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, { + ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, { + ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID}, { + ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND}, { + ERRDOS, 161, NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, { + ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN}, { + ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR}, { + ERRDOS, 23, NT_STATUS_DATA_ERROR}, { + ERRDOS, 23, NT_STATUS_CRC_ERROR}, { + ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG}, { + ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED}, { + ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE}, { + ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION}, { + ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED}, { + ERRDOS, 87, NT_STATUS_INVALID_PAGE_PROTECTION}, { + ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED}, { + ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, { + ERRDOS, 87, NT_STATUS_PORT_ALREADY_SET}, { + ERRDOS, 87, NT_STATUS_SECTION_NOT_IMAGE}, { + ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED}, { + ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING}, { + ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT}, { + ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP}, { + ERRDOS, 87, NT_STATUS_SECTION_PROTECTION}, { + ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED}, { + ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, { + ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, { + ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR}, { + ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT}, { + ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED}, { + ERRDOS, ERRbadfile, NT_STATUS_DELETE_PENDING}, { + ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED}, { + ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION}, { + ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN}, { + ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY}, { + ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE}, { + ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, { + ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS}, +/* { This NT error code was 'sqashed' + from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE + during the session setup } */ + { + ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { + ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, { + ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, { + ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP}, { + ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN}, +/* { This NT error code was 'sqashed' + from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE + during the session setup } */ + { + ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD}, { + ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD}, { + ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, { + ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { + ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { + ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { + ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, { + ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { + ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { + ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR}, { + ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL}, { + ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED}, { + ERRDOS, 112, NT_STATUS_DISK_FULL}, { + ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED}, { + ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED}, { + ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, { + ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY}, { + ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED}, { + ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL}, { + ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED}, { + ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA}, { + ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, { + ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION}, { + ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES}, { + ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, { + ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED}, +/* { This NT error code was 'sqashed' + from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES + during the session setup } */ + { + ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, { + ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, { + ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED}, { + ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE}, { + ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE}, { + ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED}, { + ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA}, { + ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED}, { + ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL}, { + ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE}, { + ERRDOS, 87, NT_STATUS_BAD_MASTER_BOOT_RECORD}, { + ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT}, { + ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE}, { + ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE}, { + ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE}, { + ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY}, { + ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION}, { + ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED}, { + ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING}, { + ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED}, { + ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING}, { + ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE}, { + ERRDOS, 121, NT_STATUS_IO_TIMEOUT}, { + ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED}, { + ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED}, { + ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED}, { + ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET}, { + ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY}, { + ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED}, { + ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING}, { + ERRDOS, 52, NT_STATUS_DUPLICATE_NAME}, { + ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH}, { + ERRDOS, 54, NT_STATUS_NETWORK_BUSY}, { + ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST}, { + ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS}, { + ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR}, { + ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE}, { + ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR}, { + ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER}, { + ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL}, { + ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE}, { + ERRDOS, 63, NT_STATUS_PRINT_CANCELLED}, { + ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED}, { + ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED}, { + ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE}, { + ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME}, { + ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES}, { + ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS}, { + ERRDOS, 70, NT_STATUS_SHARING_PAUSED}, { + ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED}, { + ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED}, { + ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT}, { + ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT}, { + ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE}, { + ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED}, { + ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT}, { + ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT}, { + ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY}, { + ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, { + ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN}, { + ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS}, { + ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, { + ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED}, { + ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL}, { + ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION}, { + ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER}, { + ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, { + ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, { + ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_1}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_2}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_3}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_4}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_5}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_6}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_7}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_8}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_9}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_10}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_11}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_12}, { + ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED}, { + ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED}, { + ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE}, { + ERRDOS, 203, 0xc0000100}, { + ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY}, { + ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR}, { + ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION}, { + ERRDOS, 206, NT_STATUS_NAME_TOO_LONG}, { + ERRDOS, 2401, NT_STATUS_FILES_OPEN}, { + ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE}, { + ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND}, { + ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION}, { + ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE}, { + ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_LDT}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT}, { + ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE}, { + ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO}, { + ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES}, { + ERRHRD, ERRgeneral, NT_STATUS_CANCELLED}, { + ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME}, { + ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED}, { + ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT}, { + ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP}, { + ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER}, { + ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP}, { + ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS}, { + ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS}, { + ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE}, { + ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, { + ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT}, { + ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC}, { + ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED}, { + ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED}, { + ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND}, { + ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT}, { + ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT}, { + ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT}, { + ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES}, { + ERRDOS, 59, NT_STATUS_LINK_FAILED}, { + ERRDOS, 59, NT_STATUS_LINK_TIMEOUT}, { + ERRDOS, 59, NT_STATUS_INVALID_CONNECTION}, { + ERRDOS, 59, NT_STATUS_INVALID_ADDRESS}, { + ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE}, { + ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION}, { + ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE}, { + ERRDOS, 124, NT_STATUS_INVALID_LEVEL}, { + ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE}, { + ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, { + ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, { + ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT}, { + ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR}, { + ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME}, { + ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS}, { + ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS}, { + ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS}, { + ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS}, { + ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG}, { + ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS}, { + ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED}, { + ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE}, { + ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, { + ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER}, { + ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, { + ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER}, { + ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER}, { + ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS}, { + ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY}, { + ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING}, { + ERRHRD, ERRgeneral, 0xc000016e}, { + ERRHRD, ERRgeneral, 0xc000016f}, { + ERRHRD, ERRgeneral, 0xc0000170}, { + ERRHRD, ERRgeneral, 0xc0000171}, { + ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH}, { + ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED}, { + ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA}, { + ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, { + ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA}, { + ERRHRD, ERRgeneral, 0xc0000179}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER}, { + ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS}, { + ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, { + ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN}, { + ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE}, { + ERRDOS, 87, NT_STATUS_DEVICE_CONFIGURATION_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR}, { + ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE}, { + ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER}, { + ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL}, { + ERRDOS, 19, NT_STATUS_TOO_LATE}, { + ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET}, +/* { This NT error code was 'sqashed' + from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE + during the session setup } */ + { + ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, { + ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, { + ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT}, { + ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, { + ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, { + ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, { + ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, { + ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, { + ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, { + ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, { + ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED}, { + ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, { + ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, { + ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT}, +/* { This NT error code was 'sqashed' + from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE + during the session setup } */ + { + ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, { + ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY}, { + ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED}, { + ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND}, { + ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD}, { + ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES}, { + ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS}, { + ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED}, { + ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED}, { + ERRDOS, 64, NT_STATUS_CONNECTION_RESET}, { + ERRDOS, 68, NT_STATUS_TOO_MANY_NODES}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE}, { + ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION}, { + ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION}, { + ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, { + ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED}, { + ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT}, { + ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH}, { + ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT}, { + ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, { + ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, { + ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, { + ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, { + ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, { + ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ}, { + ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK}, { + ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID}, { + ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS}, { + ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE}, { + ERRHRD, ERRgeneral, NT_STATUS_RETRY}, { + ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE}, { + ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET}, { + ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT}, { + ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, { + ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT}, { + ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED}, { + ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT}, { + ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, { + ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED}, { + ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID}, { + ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE}, { + ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED}, { + ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER}, { + ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE}, { + ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET}, { + ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION}, { + ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH}, { + ERRHRD, ERRgeneral, 0xc000024a}, { + ERRHRD, ERRgeneral, 0xc000024b}, { + ERRHRD, ERRgeneral, 0xc000024c}, { + ERRHRD, ERRgeneral, 0xc000024d}, { + ERRHRD, ERRgeneral, 0xc000024e}, { + ERRHRD, ERRgeneral, 0xc000024f}, { + ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT}, { + ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST}, { + ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1}, { + ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2}, { + ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT}, { + ERRSRV, 3, NT_STATUS_PATH_NOT_COVERED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE}, { + ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED}, { + ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT}, { + ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT}, { + ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT}, { + ERRHRD, ERRgeneral, 0xc000025d}, { + ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE}, { + ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, { + ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, { + ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, { + ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, { + ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, { + ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, { + ERRDOS, 21, 0xc000026e}, { + ERRDOS, 161, 0xc0000281}, { + ERRDOS, ERRnoaccess, 0xc000028a}, { + ERRDOS, ERRnoaccess, 0xc000028b}, { + ERRHRD, ERRgeneral, 0xc000028c}, { + ERRDOS, ERRnoaccess, 0xc000028d}, { + ERRDOS, ERRnoaccess, 0xc000028e}, { + ERRDOS, ERRnoaccess, 0xc000028f}, { + ERRDOS, ERRnoaccess, 0xc0000290}, { +ERRDOS, ERRbadfunc, 0xc000029c},}; + +/***************************************************************************** + Print an error message from the status code + *****************************************************************************/ +static void +cifs_print_status(__u32 status_code) +{ + int idx = 0; + + while (nt_errs[idx].nt_errstr != NULL) { + if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) == + (status_code & 0xFFFFFF)) { + printk(KERN_NOTICE "Status code returned 0x%08x %s\n", + status_code,nt_errs[idx].nt_errstr); + } + idx++; + } + return; +} + + +static void +ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode) +{ + int i; + if (ntstatus == 0) { + *eclass = 0; + *ecode = 0; + return; + } + for (i = 0; ntstatus_to_dos_map[i].ntstatus; i++) { + if (ntstatus == ntstatus_to_dos_map[i].ntstatus) { + *eclass = ntstatus_to_dos_map[i].dos_class; + *ecode = ntstatus_to_dos_map[i].dos_code; + return; + } + } + *eclass = ERRHRD; + *ecode = ERRgeneral; +} + +int +map_smb_to_linux_error(struct smb_hdr *smb) +{ + unsigned int i; + int rc = -EIO; /* if transport error smb error may not be set */ + __u8 smberrclass; + __u16 smberrcode; + + /* BB if NT Status codes - map NT BB */ + + /* old style smb error codes */ + if (smb->Status.CifsError == 0) + return 0; + + if (smb->Flags2 & SMBFLG2_ERR_STATUS) { + /* translate the newer STATUS codes to old style errors and then to POSIX errors */ + smb->Status.CifsError = le32_to_cpu(smb->Status.CifsError); + if(cifsFYI) + cifs_print_status(smb->Status.CifsError); + ntstatus_to_dos(smb->Status.CifsError, &smberrclass, + &smberrcode); + } else { + smberrclass = smb->Status.DosError.ErrorClass; + smb->Status.DosError.Error = + le16_to_cpu(smb->Status.DosError.Error); + smberrcode = smb->Status.DosError.Error; + } + + /* old style errors */ + + /* DOS class smb error codes - map DOS */ + if (smberrclass == ERRDOS) { /* one byte field no need to byte reverse */ + for (i = 0; + i < + sizeof (mapping_table_ERRDOS) / + sizeof (struct smb_to_posix_error); i++) { + if (mapping_table_ERRDOS[i].smb_err == 0) + break; + else if (mapping_table_ERRDOS[i].smb_err == smberrcode) { + rc = mapping_table_ERRDOS[i].posix_code; + break; + } + /* else try the next error mapping one to see if it will match */ + } + } else if (smberrclass == ERRSRV) { /* server class of error codes */ + for (i = 0; + i < + sizeof (mapping_table_ERRSRV) / + sizeof (struct smb_to_posix_error); i++) { + if (mapping_table_ERRSRV[i].smb_err == 0) + break; + else if (mapping_table_ERRSRV[i].smb_err == smberrcode) { + rc = mapping_table_ERRSRV[i].posix_code; + break; + } + /* else try the next error mapping one to see if it will match */ + } + } + /* else ERRHRD class errors or junk - return EIO */ + + cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", smberrcode,rc)); + + /* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */ + + return rc; +} + +/* + * calculate the size of the SMB message based on the fixed header + * portion, the number of word parameters and the data portion of the message + */ +unsigned int +smbCalcSize(struct smb_hdr *ptr) +{ + return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + + BCC(ptr)); +} + +/* The following are taken from fs/ntfs/util.c */ + +#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000) + + /* + * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units) + * into Unix UTC (based 1970-01-01, in seconds). + */ +time_t +cifs_NTtimeToUnix(__u64 ntutc) +{ + /* BB what about the timezone? BB */ + + /* Subtract the NTFS time offset, then convert to 1s intervals. */ + u64 t; + + t = ntutc - NTFS_TIME_OFFSET; + do_div(t, 10000000); + return (time_t)t; +} + +/* Convert the Unix UTC into NT UTC. */ +__u64 +cifs_UnixTimeToNT(time_t t) +{ + __u64 dce_time; + /* Convert to 100ns intervals and then add the NTFS time offset. */ + dce_time = (__u64) t * 10000000; + dce_time += NTFS_TIME_OFFSET; + return dce_time; +} diff -urN linux-2.4.27/fs/cifs/nterr.c linux-2.4.27-cifs-1.20c/fs/cifs/nterr.c --- linux-2.4.27/fs/cifs/nterr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/nterr.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,687 @@ +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Luke Kenneth Casson Leighton 1997-2001. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* NT error codes - see nterr.h */ +#include +#include +#include "nterr.h" + +const struct nt_err_code_struct nt_errs[] = { + {"NT_STATUS_OK", NT_STATUS_OK}, + {"NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL}, + {"NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED}, + {"NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS}, + {"NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH}, + {"NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION}, + {"STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW}, + {"NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR}, + {"NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA}, + {"NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE}, + {"NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK}, + {"NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC}, + {"NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID}, + {"NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED}, + {"NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER}, + {"NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE}, + {"NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE}, + {"NT_STATUS_INVALID_DEVICE_REQUEST", + NT_STATUS_INVALID_DEVICE_REQUEST}, + {"NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE}, + {"NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME}, + {"NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE}, + {"NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA}, + {"NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR}, + {"NT_STATUS_MORE_PROCESSING_REQUIRED", + NT_STATUS_MORE_PROCESSING_REQUIRED}, + {"NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY}, + {"NT_STATUS_CONFLICTING_ADDRESSES", + NT_STATUS_CONFLICTING_ADDRESSES}, + {"NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW}, + {"NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM}, + {"NT_STATUS_UNABLE_TO_DELETE_SECTION", + NT_STATUS_UNABLE_TO_DELETE_SECTION}, + {"NT_STATUS_INVALID_SYSTEM_SERVICE", + NT_STATUS_INVALID_SYSTEM_SERVICE}, + {"NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION}, + {"NT_STATUS_INVALID_LOCK_SEQUENCE", + NT_STATUS_INVALID_LOCK_SEQUENCE}, + {"NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE}, + {"NT_STATUS_INVALID_FILE_FOR_SECTION", + NT_STATUS_INVALID_FILE_FOR_SECTION}, + {"NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED}, + {"NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED}, + {"NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL}, + {"NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH}, + {"NT_STATUS_NONCONTINUABLE_EXCEPTION", + NT_STATUS_NONCONTINUABLE_EXCEPTION}, + {"NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION}, + {"NT_STATUS_UNWIND", NT_STATUS_UNWIND}, + {"NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK}, + {"NT_STATUS_INVALID_UNWIND_TARGET", + NT_STATUS_INVALID_UNWIND_TARGET}, + {"NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED}, + {"NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR}, + {"NT_STATUS_UNABLE_TO_DECOMMIT_VM", + NT_STATUS_UNABLE_TO_DECOMMIT_VM}, + {"NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED}, + {"NT_STATUS_INVALID_PORT_ATTRIBUTES", + NT_STATUS_INVALID_PORT_ATTRIBUTES}, + {"NT_STATUS_PORT_MESSAGE_TOO_LONG", + NT_STATUS_PORT_MESSAGE_TOO_LONG}, + {"NT_STATUS_INVALID_PARAMETER_MIX", + NT_STATUS_INVALID_PARAMETER_MIX}, + {"NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER}, + {"NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR}, + {"NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID}, + {"NT_STATUS_OBJECT_NAME_NOT_FOUND", + NT_STATUS_OBJECT_NAME_NOT_FOUND}, + {"NT_STATUS_OBJECT_NAME_COLLISION", + NT_STATUS_OBJECT_NAME_COLLISION}, + {"NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE}, + {"NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED}, + {"NT_STATUS_DEVICE_ALREADY_ATTACHED", + NT_STATUS_DEVICE_ALREADY_ATTACHED}, + {"NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID}, + {"NT_STATUS_OBJECT_PATH_NOT_FOUND", + NT_STATUS_OBJECT_PATH_NOT_FOUND}, + {"NT_STATUS_OBJECT_PATH_SYNTAX_BAD", + NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, + {"NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN}, + {"NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR}, + {"NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR}, + {"NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR}, + {"NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG}, + {"NT_STATUS_PORT_CONNECTION_REFUSED", + NT_STATUS_PORT_CONNECTION_REFUSED}, + {"NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE}, + {"NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION}, + {"NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED}, + {"NT_STATUS_INVALID_PAGE_PROTECTION", + NT_STATUS_INVALID_PAGE_PROTECTION}, + {"NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED}, + {"NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED", + NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, + {"NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET}, + {"NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE}, + {"NT_STATUS_SUSPEND_COUNT_EXCEEDED", + NT_STATUS_SUSPEND_COUNT_EXCEEDED}, + {"NT_STATUS_THREAD_IS_TERMINATING", + NT_STATUS_THREAD_IS_TERMINATING}, + {"NT_STATUS_BAD_WORKING_SET_LIMIT", + NT_STATUS_BAD_WORKING_SET_LIMIT}, + {"NT_STATUS_INCOMPATIBLE_FILE_MAP", + NT_STATUS_INCOMPATIBLE_FILE_MAP}, + {"NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION}, + {"NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED}, + {"NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE}, + {"NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY}, + {"NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE}, + {"NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR}, + {"NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT}, + {"NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED}, + {"NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING}, + {"NT_STATUS_CTL_FILE_NOT_SUPPORTED", + NT_STATUS_CTL_FILE_NOT_SUPPORTED}, + {"NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION}, + {"NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH}, + {"NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER}, + {"NT_STATUS_INVALID_PRIMARY_GROUP", + NT_STATUS_INVALID_PRIMARY_GROUP}, + {"NT_STATUS_NO_IMPERSONATION_TOKEN", + NT_STATUS_NO_IMPERSONATION_TOKEN}, + {"NT_STATUS_CANT_DISABLE_MANDATORY", + NT_STATUS_CANT_DISABLE_MANDATORY}, + {"NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS}, + {"NT_STATUS_NO_SUCH_LOGON_SESSION", + NT_STATUS_NO_SUCH_LOGON_SESSION}, + {"NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE}, + {"NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD}, + {"NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME}, + {"NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS}, + {"NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER}, + {"NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS}, + {"NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP}, + {"NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP}, + {"NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP}, + {"NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN}, + {"NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD}, + {"NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD}, + {"NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION}, + {"NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE}, + {"NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION}, + {"NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS}, + {"NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION}, + {"NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED}, + {"NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED}, + {"NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED}, + {"NT_STATUS_TOO_MANY_LUIDS_REQUESTED", + NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, + {"NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED}, + {"NT_STATUS_INVALID_SUB_AUTHORITY", + NT_STATUS_INVALID_SUB_AUTHORITY}, + {"NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL}, + {"NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID}, + {"NT_STATUS_INVALID_SECURITY_DESCR", + NT_STATUS_INVALID_SECURITY_DESCR}, + {"NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND}, + {"NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT}, + {"NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN}, + {"NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL}, + {"NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED}, + {"NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL}, + {"NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED}, + {"NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED}, + {"NT_STATUS_TOO_MANY_GUIDS_REQUESTED", + NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, + {"NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED}, + {"NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY}, + {"NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED}, + {"NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL}, + {"NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED}, + {"NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA}, + {"NT_STATUS_RESOURCE_DATA_NOT_FOUND", + NT_STATUS_RESOURCE_DATA_NOT_FOUND}, + {"NT_STATUS_RESOURCE_TYPE_NOT_FOUND", + NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, + {"NT_STATUS_RESOURCE_NAME_NOT_FOUND", + NT_STATUS_RESOURCE_NAME_NOT_FOUND}, + {"NT_STATUS_ARRAY_BOUNDS_EXCEEDED", + NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, + {"NT_STATUS_FLOAT_DENORMAL_OPERAND", + NT_STATUS_FLOAT_DENORMAL_OPERAND}, + {"NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, + {"NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT}, + {"NT_STATUS_FLOAT_INVALID_OPERATION", + NT_STATUS_FLOAT_INVALID_OPERATION}, + {"NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW}, + {"NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK}, + {"NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW}, + {"NT_STATUS_INTEGER_DIVIDE_BY_ZERO", + NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, + {"NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW}, + {"NT_STATUS_PRIVILEGED_INSTRUCTION", + NT_STATUS_PRIVILEGED_INSTRUCTION}, + {"NT_STATUS_TOO_MANY_PAGING_FILES", + NT_STATUS_TOO_MANY_PAGING_FILES}, + {"NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID}, + {"NT_STATUS_ALLOTTED_SPACE_EXCEEDED", + NT_STATUS_ALLOTTED_SPACE_EXCEEDED}, + {"NT_STATUS_INSUFFICIENT_RESOURCES", + NT_STATUS_INSUFFICIENT_RESOURCES}, + {"NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND}, + {"NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR}, + {"NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED}, + {"NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE}, + {"NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE}, + {"NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED}, + {"NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA}, + {"NT_STATUS_MEDIA_WRITE_PROTECTED", + NT_STATUS_MEDIA_WRITE_PROTECTED}, + {"NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY}, + {"NT_STATUS_INVALID_GROUP_ATTRIBUTES", + NT_STATUS_INVALID_GROUP_ATTRIBUTES}, + {"NT_STATUS_BAD_IMPERSONATION_LEVEL", + NT_STATUS_BAD_IMPERSONATION_LEVEL}, + {"NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS}, + {"NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS}, + {"NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE}, + {"NT_STATUS_BAD_MASTER_BOOT_RECORD", + NT_STATUS_BAD_MASTER_BOOT_RECORD}, + {"NT_STATUS_INSTRUCTION_MISALIGNMENT", + NT_STATUS_INSTRUCTION_MISALIGNMENT}, + {"NT_STATUS_INSTANCE_NOT_AVAILABLE", + NT_STATUS_INSTANCE_NOT_AVAILABLE}, + {"NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE}, + {"NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE}, + {"NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY}, + {"NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION}, + {"NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED}, + {"NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING}, + {"NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED}, + {"NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING}, + {"NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE}, + {"NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT}, + {"NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED}, + {"NT_STATUS_PROFILING_NOT_STARTED", + NT_STATUS_PROFILING_NOT_STARTED}, + {"NT_STATUS_PROFILING_NOT_STOPPED", + NT_STATUS_PROFILING_NOT_STOPPED}, + {"NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET}, + {"NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY}, + {"NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED}, + {"NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING}, + {"NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME}, + {"NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH}, + {"NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY}, + {"NT_STATUS_DEVICE_DOES_NOT_EXIST", + NT_STATUS_DEVICE_DOES_NOT_EXIST}, + {"NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS}, + {"NT_STATUS_ADAPTER_HARDWARE_ERROR", + NT_STATUS_ADAPTER_HARDWARE_ERROR}, + {"NT_STATUS_INVALID_NETWORK_RESPONSE", + NT_STATUS_INVALID_NETWORK_RESPONSE}, + {"NT_STATUS_UNEXPECTED_NETWORK_ERROR", + NT_STATUS_UNEXPECTED_NETWORK_ERROR}, + {"NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER}, + {"NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL}, + {"NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE}, + {"NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED}, + {"NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED}, + {"NT_STATUS_NETWORK_ACCESS_DENIED", + NT_STATUS_NETWORK_ACCESS_DENIED}, + {"NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE}, + {"NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME}, + {"NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES}, + {"NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS}, + {"NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED}, + {"NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED}, + {"NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED}, + {"NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT}, + {"NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT}, + {"NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE}, + {"NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED}, + {"NT_STATUS_VIRTUAL_CIRCUIT_CLOSED", + NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, + {"NT_STATUS_NO_SECURITY_ON_OBJECT", + NT_STATUS_NO_SECURITY_ON_OBJECT}, + {"NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT}, + {"NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY}, + {"NT_STATUS_CANT_ACCESS_DOMAIN_INFO", + NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, + {"NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF}, + {"NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE}, + {"NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE}, + {"NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE}, + {"NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN}, + {"NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS}, + {"NT_STATUS_DOMAIN_LIMIT_EXCEEDED", + NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, + {"NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED}, + {"NT_STATUS_INVALID_OPLOCK_PROTOCOL", + NT_STATUS_INVALID_OPLOCK_PROTOCOL}, + {"NT_STATUS_INTERNAL_DB_CORRUPTION", + NT_STATUS_INTERNAL_DB_CORRUPTION}, + {"NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR}, + {"NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED}, + {"NT_STATUS_BAD_DESCRIPTOR_FORMAT", + NT_STATUS_BAD_DESCRIPTOR_FORMAT}, + {"NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER}, + {"NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR}, + {"NT_STATUS_UNEXPECTED_MM_CREATE_ERR", + NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, + {"NT_STATUS_UNEXPECTED_MM_MAP_ERROR", + NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, + {"NT_STATUS_UNEXPECTED_MM_EXTEND_ERR", + NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, + {"NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS}, + {"NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS}, + {"NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1}, + {"NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2}, + {"NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3}, + {"NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4}, + {"NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5}, + {"NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6}, + {"NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7}, + {"NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8}, + {"NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9}, + {"NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10}, + {"NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11}, + {"NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12}, + {"NT_STATUS_REDIRECTOR_NOT_STARTED", + NT_STATUS_REDIRECTOR_NOT_STARTED}, + {"NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED}, + {"NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW}, + {"NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE}, + {"NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE}, + {"NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY}, + {"NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR}, + {"NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY}, + {"NT_STATUS_BAD_LOGON_SESSION_STATE", + NT_STATUS_BAD_LOGON_SESSION_STATE}, + {"NT_STATUS_LOGON_SESSION_COLLISION", + NT_STATUS_LOGON_SESSION_COLLISION}, + {"NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG}, + {"NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN}, + {"NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE}, + {"NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND}, + {"NT_STATUS_PROCESS_IS_TERMINATING", + NT_STATUS_PROCESS_IS_TERMINATING}, + {"NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE}, + {"NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION}, + {"NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE}, + {"NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED}, + {"NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT}, + {"NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST}, + {"NT_STATUS_ABIOS_LID_ALREADY_OWNED", + NT_STATUS_ABIOS_LID_ALREADY_OWNED}, + {"NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER}, + {"NT_STATUS_ABIOS_INVALID_COMMAND", + NT_STATUS_ABIOS_INVALID_COMMAND}, + {"NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID}, + {"NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", + NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, + {"NT_STATUS_ABIOS_INVALID_SELECTOR", + NT_STATUS_ABIOS_INVALID_SELECTOR}, + {"NT_STATUS_NO_LDT", NT_STATUS_NO_LDT}, + {"NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE}, + {"NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET}, + {"NT_STATUS_INVALID_LDT_DESCRIPTOR", + NT_STATUS_INVALID_LDT_DESCRIPTOR}, + {"NT_STATUS_INVALID_IMAGE_NE_FORMAT", + NT_STATUS_INVALID_IMAGE_NE_FORMAT}, + {"NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE}, + {"NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE}, + {"NT_STATUS_MAPPED_FILE_SIZE_ZERO", + NT_STATUS_MAPPED_FILE_SIZE_ZERO}, + {"NT_STATUS_TOO_MANY_OPENED_FILES", + NT_STATUS_TOO_MANY_OPENED_FILES}, + {"NT_STATUS_CANCELLED", NT_STATUS_CANCELLED}, + {"NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE}, + {"NT_STATUS_INVALID_COMPUTER_NAME", + NT_STATUS_INVALID_COMPUTER_NAME}, + {"NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED}, + {"NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT}, + {"NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP}, + {"NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER}, + {"NT_STATUS_MEMBERS_PRIMARY_GROUP", + NT_STATUS_MEMBERS_PRIMARY_GROUP}, + {"NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED}, + {"NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS}, + {"NT_STATUS_THREAD_NOT_IN_PROCESS", + NT_STATUS_THREAD_NOT_IN_PROCESS}, + {"NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE}, + {"NT_STATUS_PAGEFILE_QUOTA_EXCEEDED", + NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, + {"NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT}, + {"NT_STATUS_INVALID_IMAGE_LE_FORMAT", + NT_STATUS_INVALID_IMAGE_LE_FORMAT}, + {"NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ}, + {"NT_STATUS_INVALID_IMAGE_PROTECT", + NT_STATUS_INVALID_IMAGE_PROTECT}, + {"NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16}, + {"NT_STATUS_LOGON_SERVER_CONFLICT", + NT_STATUS_LOGON_SERVER_CONFLICT}, + {"NT_STATUS_TIME_DIFFERENCE_AT_DC", + NT_STATUS_TIME_DIFFERENCE_AT_DC}, + {"NT_STATUS_SYNCHRONIZATION_REQUIRED", + NT_STATUS_SYNCHRONIZATION_REQUIRED}, + {"NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND}, + {"NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED}, + {"NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED}, + {"NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND}, + {"NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND}, + {"NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT}, + {"NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT}, + {"NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT}, + {"NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES}, + {"NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED}, + {"NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT}, + {"NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION}, + {"NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS}, + {"NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED}, + {"NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE}, + {"NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION}, + {"NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE}, + {"NT_STATUS_PAGEFILE_CREATE_FAILED", + NT_STATUS_PAGEFILE_CREATE_FAILED}, + {"NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE}, + {"NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL}, + {"NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE}, + {"NT_STATUS_ILLEGAL_FLOAT_CONTEXT", + NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, + {"NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN}, + {"NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT}, + {"NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED}, + {"NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR}, + {"NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME}, + {"NT_STATUS_SERIAL_NO_DEVICE_INITED", + NT_STATUS_SERIAL_NO_DEVICE_INITED}, + {"NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS}, + {"NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS}, + {"NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS}, + {"NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS}, + {"NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED}, + {"NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS}, + {"NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG}, + {"NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR}, + {"NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE}, + {"NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS}, + {"NT_STATUS_LOGON_TYPE_NOT_GRANTED", + NT_STATUS_LOGON_TYPE_NOT_GRANTED}, + {"NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE}, + {"NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED", + NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, + {"NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR", + NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, + {"NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER}, + {"NT_STATUS_ILL_FORMED_SERVICE_ENTRY", + NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, + {"NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER}, + {"NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER}, + {"NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER}, + {"NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME}, + {"NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND", + NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, + {"NT_STATUS_FLOPPY_WRONG_CYLINDER", + NT_STATUS_FLOPPY_WRONG_CYLINDER}, + {"NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR}, + {"NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS}, + {"NT_STATUS_DISK_RECALIBRATE_FAILED", + NT_STATUS_DISK_RECALIBRATE_FAILED}, + {"NT_STATUS_DISK_OPERATION_FAILED", + NT_STATUS_DISK_OPERATION_FAILED}, + {"NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED}, + {"NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY}, + {"NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING}, + {"NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE}, + {"NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH}, + {"NT_STATUS_DEVICE_NOT_PARTITIONED", + NT_STATUS_DEVICE_NOT_PARTITIONED}, + {"NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA}, + {"NT_STATUS_UNABLE_TO_UNLOAD_MEDIA", + NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, + {"NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW}, + {"NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA}, + {"NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER}, + {"NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER}, + {"NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED}, + {"NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE}, + {"NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS}, + {"NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED", + NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, + {"NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN}, + {"NT_STATUS_CHILD_MUST_BE_VOLATILE", + NT_STATUS_CHILD_MUST_BE_VOLATILE}, + {"NT_STATUS_DEVICE_CONFIGURATION_ERROR", + NT_STATUS_DEVICE_CONFIGURATION_ERROR}, + {"NT_STATUS_DRIVER_INTERNAL_ERROR", + NT_STATUS_DRIVER_INTERNAL_ERROR}, + {"NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE}, + {"NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR}, + {"NT_STATUS_DEVICE_PROTOCOL_ERROR", + NT_STATUS_DEVICE_PROTOCOL_ERROR}, + {"NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER}, + {"NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL}, + {"NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE}, + {"NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET}, + {"NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT}, + {"NT_STATUS_TRUSTED_DOMAIN_FAILURE", + NT_STATUS_TRUSTED_DOMAIN_FAILURE}, + {"NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE", + NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, + {"NT_STATUS_EVENTLOG_FILE_CORRUPT", + NT_STATUS_EVENTLOG_FILE_CORRUPT}, + {"NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START}, + {"NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE}, + {"NT_STATUS_MUTANT_LIMIT_EXCEEDED", + NT_STATUS_MUTANT_LIMIT_EXCEEDED}, + {"NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED}, + {"NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED}, + {"NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK}, + {"NT_STATUS_NETWORK_CREDENTIAL_CONFLICT", + NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, + {"NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT}, + {"NT_STATUS_EVENTLOG_FILE_CHANGED", + NT_STATUS_EVENTLOG_FILE_CHANGED}, + {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", + NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, + {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", + NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, + {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", + NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT}, + {"NT_STATUS_DOMAIN_TRUST_INCONSISTENT", + NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, + {"NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED}, + {"NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY}, + {"NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED}, + {"NT_STATUS_RESOURCE_LANG_NOT_FOUND", + NT_STATUS_RESOURCE_LANG_NOT_FOUND}, + {"NT_STATUS_INSUFF_SERVER_RESOURCES", + NT_STATUS_INSUFF_SERVER_RESOURCES}, + {"NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE}, + {"NT_STATUS_INVALID_ADDRESS_COMPONENT", + NT_STATUS_INVALID_ADDRESS_COMPONENT}, + {"NT_STATUS_INVALID_ADDRESS_WILDCARD", + NT_STATUS_INVALID_ADDRESS_WILDCARD}, + {"NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES}, + {"NT_STATUS_ADDRESS_ALREADY_EXISTS", + NT_STATUS_ADDRESS_ALREADY_EXISTS}, + {"NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED}, + {"NT_STATUS_CONNECTION_DISCONNECTED", + NT_STATUS_CONNECTION_DISCONNECTED}, + {"NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET}, + {"NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES}, + {"NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED}, + {"NT_STATUS_TRANSACTION_TIMED_OUT", + NT_STATUS_TRANSACTION_TIMED_OUT}, + {"NT_STATUS_TRANSACTION_NO_RELEASE", + NT_STATUS_TRANSACTION_NO_RELEASE}, + {"NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH}, + {"NT_STATUS_TRANSACTION_RESPONDED", + NT_STATUS_TRANSACTION_RESPONDED}, + {"NT_STATUS_TRANSACTION_INVALID_ID", + NT_STATUS_TRANSACTION_INVALID_ID}, + {"NT_STATUS_TRANSACTION_INVALID_TYPE", + NT_STATUS_TRANSACTION_INVALID_TYPE}, + {"NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION}, + {"NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION}, + {"NT_STATUS_CANNOT_LOAD_REGISTRY_FILE", + NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, + {"NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED}, + {"NT_STATUS_SYSTEM_PROCESS_TERMINATED", + NT_STATUS_SYSTEM_PROCESS_TERMINATED}, + {"NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED}, + {"NT_STATUS_NO_BROWSER_SERVERS_FOUND", + NT_STATUS_NO_BROWSER_SERVERS_FOUND}, + {"NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR}, + {"NT_STATUS_DRIVER_CANCEL_TIMEOUT", + NT_STATUS_DRIVER_CANCEL_TIMEOUT}, + {"NT_STATUS_REPLY_MESSAGE_MISMATCH", + NT_STATUS_REPLY_MESSAGE_MISMATCH}, + {"NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT}, + {"NT_STATUS_IMAGE_CHECKSUM_MISMATCH", + NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, + {"NT_STATUS_LOST_WRITEBEHIND_DATA", + NT_STATUS_LOST_WRITEBEHIND_DATA}, + {"NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID", + NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, + {"NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE}, + {"NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND}, + {"NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM}, + {"NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE}, + {"NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ}, + {"NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK}, + {"NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID}, + {"NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS}, + {"NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE}, + {"NT_STATUS_RETRY", NT_STATUS_RETRY}, + {"NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE}, + {"NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET}, + {"NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND}, + {"NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW}, + {"NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT}, + {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", + NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, + {"NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT}, + {"NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE}, + {"NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED}, + {"NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT}, + {"NT_STATUS_ADDRESS_ALREADY_ASSOCIATED", + NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, + {"NT_STATUS_ADDRESS_NOT_ASSOCIATED", + NT_STATUS_ADDRESS_NOT_ASSOCIATED}, + {"NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID}, + {"NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE}, + {"NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE}, + {"NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE}, + {"NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE}, + {"NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE}, + {"NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED}, + {"NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED}, + {"NT_STATUS_BAD_COMPRESSION_BUFFER", + NT_STATUS_BAD_COMPRESSION_BUFFER}, + {"NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE}, + {"NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED}, + {"NT_STATUS_TIMER_RESOLUTION_NOT_SET", + NT_STATUS_TIMER_RESOLUTION_NOT_SET}, + {"NT_STATUS_CONNECTION_COUNT_LIMIT", + NT_STATUS_CONNECTION_COUNT_LIMIT}, + {"NT_STATUS_LOGIN_TIME_RESTRICTION", + NT_STATUS_LOGIN_TIME_RESTRICTION}, + {"NT_STATUS_LOGIN_WKSTA_RESTRICTION", + NT_STATUS_LOGIN_WKSTA_RESTRICTION}, + {"NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH}, + {"NT_STATUS_INSUFFICIENT_LOGON_INFO", + NT_STATUS_INSUFFICIENT_LOGON_INFO}, + {"NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT}, + {"NT_STATUS_BAD_SERVICE_ENTRYPOINT", + NT_STATUS_BAD_SERVICE_ENTRYPOINT}, + {"NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST}, + {"NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1}, + {"NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2}, + {"NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT}, + {"NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED}, + {"NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE}, + {"NT_STATUS_LICENSE_QUOTA_EXCEEDED", + NT_STATUS_LICENSE_QUOTA_EXCEEDED}, + {"NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT}, + {"NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT}, + {"NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT}, + {"NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE}, + {"NT_STATUS_UNSUPPORTED_COMPRESSION", + NT_STATUS_UNSUPPORTED_COMPRESSION}, + {"NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE}, + {"NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH", + NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, + {"NT_STATUS_DRIVER_ORDINAL_NOT_FOUND", + NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, + {"NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", + NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, + {"NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED}, + {"NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS}, + {"NT_STATUS_QUOTA_LIST_INCONSISTENT", + NT_STATUS_QUOTA_LIST_INCONSISTENT}, + {"NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE}, + {"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES}, + {"STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES}, + {"STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED}, + {NULL, 0} +}; diff -urN linux-2.4.27/fs/cifs/nterr.h linux-2.4.27-cifs-1.20c/fs/cifs/nterr.h --- linux-2.4.27/fs/cifs/nterr.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/nterr.h Wed Jul 14 00:25:05 2004 @@ -0,0 +1,556 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + NT error code constants + Copyright (C) Andrew Tridgell 1992-2000 + Copyright (C) John H Terpstra 1996-2000 + Copyright (C) Luke Kenneth Casson Leighton 1996-2000 + Copyright (C) Paul Ashton 1998-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + + +#ifndef _NTERR_H +#define _NTERR_H + +struct nt_err_code_struct { + char *nt_errstr; + __u32 nt_errcode; +}; + +extern const struct nt_err_code_struct nt_errs[]; + +/* Win32 Status codes. */ + +#define STATUS_BUFFER_OVERFLOW 0x80000005 +#define STATUS_MORE_ENTRIES 0x0105 +#define ERROR_INVALID_PARAMETER 0x0057 +#define ERROR_INSUFFICIENT_BUFFER 0x007a +#define STATUS_1804 0x070c +#define STATUS_NOTIFY_ENUM_DIR 0x010c + +/* Win32 Error codes extracted using a loop in smbclient then printing a + netmon sniff to a file. */ + +#define NT_STATUS_OK 0x0000 +#define STATUS_SOME_UNMAPPED 0x0107 +#define STATUS_BUFFER_OVERFLOW 0x80000005 +#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a +#define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001 +#define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002 +#define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003 +#define NT_STATUS_INFO_LENGTH_MISMATCH 0xC0000000 | 0x0004 +#define NT_STATUS_ACCESS_VIOLATION 0xC0000000 | 0x0005 +#define NT_STATUS_IN_PAGE_ERROR 0xC0000000 | 0x0006 +#define NT_STATUS_PAGEFILE_QUOTA 0xC0000000 | 0x0007 +#define NT_STATUS_INVALID_HANDLE 0xC0000000 | 0x0008 +#define NT_STATUS_BAD_INITIAL_STACK 0xC0000000 | 0x0009 +#define NT_STATUS_BAD_INITIAL_PC 0xC0000000 | 0x000a +#define NT_STATUS_INVALID_CID 0xC0000000 | 0x000b +#define NT_STATUS_TIMER_NOT_CANCELED 0xC0000000 | 0x000c +#define NT_STATUS_INVALID_PARAMETER 0xC0000000 | 0x000d +#define NT_STATUS_NO_SUCH_DEVICE 0xC0000000 | 0x000e +#define NT_STATUS_NO_SUCH_FILE 0xC0000000 | 0x000f +#define NT_STATUS_INVALID_DEVICE_REQUEST 0xC0000000 | 0x0010 +#define NT_STATUS_END_OF_FILE 0xC0000000 | 0x0011 +#define NT_STATUS_WRONG_VOLUME 0xC0000000 | 0x0012 +#define NT_STATUS_NO_MEDIA_IN_DEVICE 0xC0000000 | 0x0013 +#define NT_STATUS_UNRECOGNIZED_MEDIA 0xC0000000 | 0x0014 +#define NT_STATUS_NONEXISTENT_SECTOR 0xC0000000 | 0x0015 +#define NT_STATUS_MORE_PROCESSING_REQUIRED 0xC0000000 | 0x0016 +#define NT_STATUS_NO_MEMORY 0xC0000000 | 0x0017 +#define NT_STATUS_CONFLICTING_ADDRESSES 0xC0000000 | 0x0018 +#define NT_STATUS_NOT_MAPPED_VIEW 0xC0000000 | 0x0019 +#define NT_STATUS_UNABLE_TO_FREE_VM 0x80000000 | 0x001a +#define NT_STATUS_UNABLE_TO_DELETE_SECTION 0xC0000000 | 0x001b +#define NT_STATUS_INVALID_SYSTEM_SERVICE 0xC0000000 | 0x001c +#define NT_STATUS_ILLEGAL_INSTRUCTION 0xC0000000 | 0x001d +#define NT_STATUS_INVALID_LOCK_SEQUENCE 0xC0000000 | 0x001e +#define NT_STATUS_INVALID_VIEW_SIZE 0xC0000000 | 0x001f +#define NT_STATUS_INVALID_FILE_FOR_SECTION 0xC0000000 | 0x0020 +#define NT_STATUS_ALREADY_COMMITTED 0xC0000000 | 0x0021 +#define NT_STATUS_ACCESS_DENIED 0xC0000000 | 0x0022 +#define NT_STATUS_BUFFER_TOO_SMALL 0xC0000000 | 0x0023 +#define NT_STATUS_OBJECT_TYPE_MISMATCH 0xC0000000 | 0x0024 +#define NT_STATUS_NONCONTINUABLE_EXCEPTION 0xC0000000 | 0x0025 +#define NT_STATUS_INVALID_DISPOSITION 0xC0000000 | 0x0026 +#define NT_STATUS_UNWIND 0xC0000000 | 0x0027 +#define NT_STATUS_BAD_STACK 0xC0000000 | 0x0028 +#define NT_STATUS_INVALID_UNWIND_TARGET 0xC0000000 | 0x0029 +#define NT_STATUS_NOT_LOCKED 0xC0000000 | 0x002a +#define NT_STATUS_PARITY_ERROR 0xC0000000 | 0x002b +#define NT_STATUS_UNABLE_TO_DECOMMIT_VM 0xC0000000 | 0x002c +#define NT_STATUS_NOT_COMMITTED 0xC0000000 | 0x002d +#define NT_STATUS_INVALID_PORT_ATTRIBUTES 0xC0000000 | 0x002e +#define NT_STATUS_PORT_MESSAGE_TOO_LONG 0xC0000000 | 0x002f +#define NT_STATUS_INVALID_PARAMETER_MIX 0xC0000000 | 0x0030 +#define NT_STATUS_INVALID_QUOTA_LOWER 0xC0000000 | 0x0031 +#define NT_STATUS_DISK_CORRUPT_ERROR 0xC0000000 | 0x0032 +#define NT_STATUS_OBJECT_NAME_INVALID 0xC0000000 | 0x0033 +#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000000 | 0x0034 +#define NT_STATUS_OBJECT_NAME_COLLISION 0xC0000000 | 0x0035 +#define NT_STATUS_HANDLE_NOT_WAITABLE 0xC0000000 | 0x0036 +#define NT_STATUS_PORT_DISCONNECTED 0xC0000000 | 0x0037 +#define NT_STATUS_DEVICE_ALREADY_ATTACHED 0xC0000000 | 0x0038 +#define NT_STATUS_OBJECT_PATH_INVALID 0xC0000000 | 0x0039 +#define NT_STATUS_OBJECT_PATH_NOT_FOUND 0xC0000000 | 0x003a +#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 0xC0000000 | 0x003b +#define NT_STATUS_DATA_OVERRUN 0xC0000000 | 0x003c +#define NT_STATUS_DATA_LATE_ERROR 0xC0000000 | 0x003d +#define NT_STATUS_DATA_ERROR 0xC0000000 | 0x003e +#define NT_STATUS_CRC_ERROR 0xC0000000 | 0x003f +#define NT_STATUS_SECTION_TOO_BIG 0xC0000000 | 0x0040 +#define NT_STATUS_PORT_CONNECTION_REFUSED 0xC0000000 | 0x0041 +#define NT_STATUS_INVALID_PORT_HANDLE 0xC0000000 | 0x0042 +#define NT_STATUS_SHARING_VIOLATION 0xC0000000 | 0x0043 +#define NT_STATUS_QUOTA_EXCEEDED 0xC0000000 | 0x0044 +#define NT_STATUS_INVALID_PAGE_PROTECTION 0xC0000000 | 0x0045 +#define NT_STATUS_MUTANT_NOT_OWNED 0xC0000000 | 0x0046 +#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000000 | 0x0047 +#define NT_STATUS_PORT_ALREADY_SET 0xC0000000 | 0x0048 +#define NT_STATUS_SECTION_NOT_IMAGE 0xC0000000 | 0x0049 +#define NT_STATUS_SUSPEND_COUNT_EXCEEDED 0xC0000000 | 0x004a +#define NT_STATUS_THREAD_IS_TERMINATING 0xC0000000 | 0x004b +#define NT_STATUS_BAD_WORKING_SET_LIMIT 0xC0000000 | 0x004c +#define NT_STATUS_INCOMPATIBLE_FILE_MAP 0xC0000000 | 0x004d +#define NT_STATUS_SECTION_PROTECTION 0xC0000000 | 0x004e +#define NT_STATUS_EAS_NOT_SUPPORTED 0xC0000000 | 0x004f +#define NT_STATUS_EA_TOO_LARGE 0xC0000000 | 0x0050 +#define NT_STATUS_NONEXISTENT_EA_ENTRY 0xC0000000 | 0x0051 +#define NT_STATUS_NO_EAS_ON_FILE 0xC0000000 | 0x0052 +#define NT_STATUS_EA_CORRUPT_ERROR 0xC0000000 | 0x0053 +#define NT_STATUS_FILE_LOCK_CONFLICT 0xC0000000 | 0x0054 +#define NT_STATUS_LOCK_NOT_GRANTED 0xC0000000 | 0x0055 +#define NT_STATUS_DELETE_PENDING 0xC0000000 | 0x0056 +#define NT_STATUS_CTL_FILE_NOT_SUPPORTED 0xC0000000 | 0x0057 +#define NT_STATUS_UNKNOWN_REVISION 0xC0000000 | 0x0058 +#define NT_STATUS_REVISION_MISMATCH 0xC0000000 | 0x0059 +#define NT_STATUS_INVALID_OWNER 0xC0000000 | 0x005a +#define NT_STATUS_INVALID_PRIMARY_GROUP 0xC0000000 | 0x005b +#define NT_STATUS_NO_IMPERSONATION_TOKEN 0xC0000000 | 0x005c +#define NT_STATUS_CANT_DISABLE_MANDATORY 0xC0000000 | 0x005d +#define NT_STATUS_NO_LOGON_SERVERS 0xC0000000 | 0x005e +#define NT_STATUS_NO_SUCH_LOGON_SESSION 0xC0000000 | 0x005f +#define NT_STATUS_NO_SUCH_PRIVILEGE 0xC0000000 | 0x0060 +#define NT_STATUS_PRIVILEGE_NOT_HELD 0xC0000000 | 0x0061 +#define NT_STATUS_INVALID_ACCOUNT_NAME 0xC0000000 | 0x0062 +#define NT_STATUS_USER_EXISTS 0xC0000000 | 0x0063 +#define NT_STATUS_NO_SUCH_USER 0xC0000000 | 0x0064 +#define NT_STATUS_GROUP_EXISTS 0xC0000000 | 0x0065 +#define NT_STATUS_NO_SUCH_GROUP 0xC0000000 | 0x0066 +#define NT_STATUS_MEMBER_IN_GROUP 0xC0000000 | 0x0067 +#define NT_STATUS_MEMBER_NOT_IN_GROUP 0xC0000000 | 0x0068 +#define NT_STATUS_LAST_ADMIN 0xC0000000 | 0x0069 +#define NT_STATUS_WRONG_PASSWORD 0xC0000000 | 0x006a +#define NT_STATUS_ILL_FORMED_PASSWORD 0xC0000000 | 0x006b +#define NT_STATUS_PASSWORD_RESTRICTION 0xC0000000 | 0x006c +#define NT_STATUS_LOGON_FAILURE 0xC0000000 | 0x006d +#define NT_STATUS_ACCOUNT_RESTRICTION 0xC0000000 | 0x006e +#define NT_STATUS_INVALID_LOGON_HOURS 0xC0000000 | 0x006f +#define NT_STATUS_INVALID_WORKSTATION 0xC0000000 | 0x0070 +#define NT_STATUS_PASSWORD_EXPIRED 0xC0000000 | 0x0071 +#define NT_STATUS_ACCOUNT_DISABLED 0xC0000000 | 0x0072 +#define NT_STATUS_NONE_MAPPED 0xC0000000 | 0x0073 +#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 0xC0000000 | 0x0074 +#define NT_STATUS_LUIDS_EXHAUSTED 0xC0000000 | 0x0075 +#define NT_STATUS_INVALID_SUB_AUTHORITY 0xC0000000 | 0x0076 +#define NT_STATUS_INVALID_ACL 0xC0000000 | 0x0077 +#define NT_STATUS_INVALID_SID 0xC0000000 | 0x0078 +#define NT_STATUS_INVALID_SECURITY_DESCR 0xC0000000 | 0x0079 +#define NT_STATUS_PROCEDURE_NOT_FOUND 0xC0000000 | 0x007a +#define NT_STATUS_INVALID_IMAGE_FORMAT 0xC0000000 | 0x007b +#define NT_STATUS_NO_TOKEN 0xC0000000 | 0x007c +#define NT_STATUS_BAD_INHERITANCE_ACL 0xC0000000 | 0x007d +#define NT_STATUS_RANGE_NOT_LOCKED 0xC0000000 | 0x007e +#define NT_STATUS_DISK_FULL 0xC0000000 | 0x007f +#define NT_STATUS_SERVER_DISABLED 0xC0000000 | 0x0080 +#define NT_STATUS_SERVER_NOT_DISABLED 0xC0000000 | 0x0081 +#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 0xC0000000 | 0x0082 +#define NT_STATUS_GUIDS_EXHAUSTED 0xC0000000 | 0x0083 +#define NT_STATUS_INVALID_ID_AUTHORITY 0xC0000000 | 0x0084 +#define NT_STATUS_AGENTS_EXHAUSTED 0xC0000000 | 0x0085 +#define NT_STATUS_INVALID_VOLUME_LABEL 0xC0000000 | 0x0086 +#define NT_STATUS_SECTION_NOT_EXTENDED 0xC0000000 | 0x0087 +#define NT_STATUS_NOT_MAPPED_DATA 0xC0000000 | 0x0088 +#define NT_STATUS_RESOURCE_DATA_NOT_FOUND 0xC0000000 | 0x0089 +#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 0xC0000000 | 0x008a +#define NT_STATUS_RESOURCE_NAME_NOT_FOUND 0xC0000000 | 0x008b +#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 0xC0000000 | 0x008c +#define NT_STATUS_FLOAT_DENORMAL_OPERAND 0xC0000000 | 0x008d +#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 0xC0000000 | 0x008e +#define NT_STATUS_FLOAT_INEXACT_RESULT 0xC0000000 | 0x008f +#define NT_STATUS_FLOAT_INVALID_OPERATION 0xC0000000 | 0x0090 +#define NT_STATUS_FLOAT_OVERFLOW 0xC0000000 | 0x0091 +#define NT_STATUS_FLOAT_STACK_CHECK 0xC0000000 | 0x0092 +#define NT_STATUS_FLOAT_UNDERFLOW 0xC0000000 | 0x0093 +#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000000 | 0x0094 +#define NT_STATUS_INTEGER_OVERFLOW 0xC0000000 | 0x0095 +#define NT_STATUS_PRIVILEGED_INSTRUCTION 0xC0000000 | 0x0096 +#define NT_STATUS_TOO_MANY_PAGING_FILES 0xC0000000 | 0x0097 +#define NT_STATUS_FILE_INVALID 0xC0000000 | 0x0098 +#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 0xC0000000 | 0x0099 +#define NT_STATUS_INSUFFICIENT_RESOURCES 0xC0000000 | 0x009a +#define NT_STATUS_DFS_EXIT_PATH_FOUND 0xC0000000 | 0x009b +#define NT_STATUS_DEVICE_DATA_ERROR 0xC0000000 | 0x009c +#define NT_STATUS_DEVICE_NOT_CONNECTED 0xC0000000 | 0x009d +#define NT_STATUS_DEVICE_POWER_FAILURE 0xC0000000 | 0x009e +#define NT_STATUS_FREE_VM_NOT_AT_BASE 0xC0000000 | 0x009f +#define NT_STATUS_MEMORY_NOT_ALLOCATED 0xC0000000 | 0x00a0 +#define NT_STATUS_WORKING_SET_QUOTA 0xC0000000 | 0x00a1 +#define NT_STATUS_MEDIA_WRITE_PROTECTED 0xC0000000 | 0x00a2 +#define NT_STATUS_DEVICE_NOT_READY 0xC0000000 | 0x00a3 +#define NT_STATUS_INVALID_GROUP_ATTRIBUTES 0xC0000000 | 0x00a4 +#define NT_STATUS_BAD_IMPERSONATION_LEVEL 0xC0000000 | 0x00a5 +#define NT_STATUS_CANT_OPEN_ANONYMOUS 0xC0000000 | 0x00a6 +#define NT_STATUS_BAD_VALIDATION_CLASS 0xC0000000 | 0x00a7 +#define NT_STATUS_BAD_TOKEN_TYPE 0xC0000000 | 0x00a8 +#define NT_STATUS_BAD_MASTER_BOOT_RECORD 0xC0000000 | 0x00a9 +#define NT_STATUS_INSTRUCTION_MISALIGNMENT 0xC0000000 | 0x00aa +#define NT_STATUS_INSTANCE_NOT_AVAILABLE 0xC0000000 | 0x00ab +#define NT_STATUS_PIPE_NOT_AVAILABLE 0xC0000000 | 0x00ac +#define NT_STATUS_INVALID_PIPE_STATE 0xC0000000 | 0x00ad +#define NT_STATUS_PIPE_BUSY 0xC0000000 | 0x00ae +#define NT_STATUS_ILLEGAL_FUNCTION 0xC0000000 | 0x00af +#define NT_STATUS_PIPE_DISCONNECTED 0xC0000000 | 0x00b0 +#define NT_STATUS_PIPE_CLOSING 0xC0000000 | 0x00b1 +#define NT_STATUS_PIPE_CONNECTED 0xC0000000 | 0x00b2 +#define NT_STATUS_PIPE_LISTENING 0xC0000000 | 0x00b3 +#define NT_STATUS_INVALID_READ_MODE 0xC0000000 | 0x00b4 +#define NT_STATUS_IO_TIMEOUT 0xC0000000 | 0x00b5 +#define NT_STATUS_FILE_FORCED_CLOSED 0xC0000000 | 0x00b6 +#define NT_STATUS_PROFILING_NOT_STARTED 0xC0000000 | 0x00b7 +#define NT_STATUS_PROFILING_NOT_STOPPED 0xC0000000 | 0x00b8 +#define NT_STATUS_COULD_NOT_INTERPRET 0xC0000000 | 0x00b9 +#define NT_STATUS_FILE_IS_A_DIRECTORY 0xC0000000 | 0x00ba +#define NT_STATUS_NOT_SUPPORTED 0xC0000000 | 0x00bb +#define NT_STATUS_REMOTE_NOT_LISTENING 0xC0000000 | 0x00bc +#define NT_STATUS_DUPLICATE_NAME 0xC0000000 | 0x00bd +#define NT_STATUS_BAD_NETWORK_PATH 0xC0000000 | 0x00be +#define NT_STATUS_NETWORK_BUSY 0xC0000000 | 0x00bf +#define NT_STATUS_DEVICE_DOES_NOT_EXIST 0xC0000000 | 0x00c0 +#define NT_STATUS_TOO_MANY_COMMANDS 0xC0000000 | 0x00c1 +#define NT_STATUS_ADAPTER_HARDWARE_ERROR 0xC0000000 | 0x00c2 +#define NT_STATUS_INVALID_NETWORK_RESPONSE 0xC0000000 | 0x00c3 +#define NT_STATUS_UNEXPECTED_NETWORK_ERROR 0xC0000000 | 0x00c4 +#define NT_STATUS_BAD_REMOTE_ADAPTER 0xC0000000 | 0x00c5 +#define NT_STATUS_PRINT_QUEUE_FULL 0xC0000000 | 0x00c6 +#define NT_STATUS_NO_SPOOL_SPACE 0xC0000000 | 0x00c7 +#define NT_STATUS_PRINT_CANCELLED 0xC0000000 | 0x00c8 +#define NT_STATUS_NETWORK_NAME_DELETED 0xC0000000 | 0x00c9 +#define NT_STATUS_NETWORK_ACCESS_DENIED 0xC0000000 | 0x00ca +#define NT_STATUS_BAD_DEVICE_TYPE 0xC0000000 | 0x00cb +#define NT_STATUS_BAD_NETWORK_NAME 0xC0000000 | 0x00cc +#define NT_STATUS_TOO_MANY_NAMES 0xC0000000 | 0x00cd +#define NT_STATUS_TOO_MANY_SESSIONS 0xC0000000 | 0x00ce +#define NT_STATUS_SHARING_PAUSED 0xC0000000 | 0x00cf +#define NT_STATUS_REQUEST_NOT_ACCEPTED 0xC0000000 | 0x00d0 +#define NT_STATUS_REDIRECTOR_PAUSED 0xC0000000 | 0x00d1 +#define NT_STATUS_NET_WRITE_FAULT 0xC0000000 | 0x00d2 +#define NT_STATUS_PROFILING_AT_LIMIT 0xC0000000 | 0x00d3 +#define NT_STATUS_NOT_SAME_DEVICE 0xC0000000 | 0x00d4 +#define NT_STATUS_FILE_RENAMED 0xC0000000 | 0x00d5 +#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 0xC0000000 | 0x00d6 +#define NT_STATUS_NO_SECURITY_ON_OBJECT 0xC0000000 | 0x00d7 +#define NT_STATUS_CANT_WAIT 0xC0000000 | 0x00d8 +#define NT_STATUS_PIPE_EMPTY 0xC0000000 | 0x00d9 +#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 0xC0000000 | 0x00da +#define NT_STATUS_CANT_TERMINATE_SELF 0xC0000000 | 0x00db +#define NT_STATUS_INVALID_SERVER_STATE 0xC0000000 | 0x00dc +#define NT_STATUS_INVALID_DOMAIN_STATE 0xC0000000 | 0x00dd +#define NT_STATUS_INVALID_DOMAIN_ROLE 0xC0000000 | 0x00de +#define NT_STATUS_NO_SUCH_DOMAIN 0xC0000000 | 0x00df +#define NT_STATUS_DOMAIN_EXISTS 0xC0000000 | 0x00e0 +#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 0xC0000000 | 0x00e1 +#define NT_STATUS_OPLOCK_NOT_GRANTED 0xC0000000 | 0x00e2 +#define NT_STATUS_INVALID_OPLOCK_PROTOCOL 0xC0000000 | 0x00e3 +#define NT_STATUS_INTERNAL_DB_CORRUPTION 0xC0000000 | 0x00e4 +#define NT_STATUS_INTERNAL_ERROR 0xC0000000 | 0x00e5 +#define NT_STATUS_GENERIC_NOT_MAPPED 0xC0000000 | 0x00e6 +#define NT_STATUS_BAD_DESCRIPTOR_FORMAT 0xC0000000 | 0x00e7 +#define NT_STATUS_INVALID_USER_BUFFER 0xC0000000 | 0x00e8 +#define NT_STATUS_UNEXPECTED_IO_ERROR 0xC0000000 | 0x00e9 +#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 0xC0000000 | 0x00ea +#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 0xC0000000 | 0x00eb +#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 0xC0000000 | 0x00ec +#define NT_STATUS_NOT_LOGON_PROCESS 0xC0000000 | 0x00ed +#define NT_STATUS_LOGON_SESSION_EXISTS 0xC0000000 | 0x00ee +#define NT_STATUS_INVALID_PARAMETER_1 0xC0000000 | 0x00ef +#define NT_STATUS_INVALID_PARAMETER_2 0xC0000000 | 0x00f0 +#define NT_STATUS_INVALID_PARAMETER_3 0xC0000000 | 0x00f1 +#define NT_STATUS_INVALID_PARAMETER_4 0xC0000000 | 0x00f2 +#define NT_STATUS_INVALID_PARAMETER_5 0xC0000000 | 0x00f3 +#define NT_STATUS_INVALID_PARAMETER_6 0xC0000000 | 0x00f4 +#define NT_STATUS_INVALID_PARAMETER_7 0xC0000000 | 0x00f5 +#define NT_STATUS_INVALID_PARAMETER_8 0xC0000000 | 0x00f6 +#define NT_STATUS_INVALID_PARAMETER_9 0xC0000000 | 0x00f7 +#define NT_STATUS_INVALID_PARAMETER_10 0xC0000000 | 0x00f8 +#define NT_STATUS_INVALID_PARAMETER_11 0xC0000000 | 0x00f9 +#define NT_STATUS_INVALID_PARAMETER_12 0xC0000000 | 0x00fa +#define NT_STATUS_REDIRECTOR_NOT_STARTED 0xC0000000 | 0x00fb +#define NT_STATUS_REDIRECTOR_STARTED 0xC0000000 | 0x00fc +#define NT_STATUS_STACK_OVERFLOW 0xC0000000 | 0x00fd +#define NT_STATUS_NO_SUCH_PACKAGE 0xC0000000 | 0x00fe +#define NT_STATUS_BAD_FUNCTION_TABLE 0xC0000000 | 0x00ff +#define NT_STATUS_DIRECTORY_NOT_EMPTY 0xC0000000 | 0x0101 +#define NT_STATUS_FILE_CORRUPT_ERROR 0xC0000000 | 0x0102 +#define NT_STATUS_NOT_A_DIRECTORY 0xC0000000 | 0x0103 +#define NT_STATUS_BAD_LOGON_SESSION_STATE 0xC0000000 | 0x0104 +#define NT_STATUS_LOGON_SESSION_COLLISION 0xC0000000 | 0x0105 +#define NT_STATUS_NAME_TOO_LONG 0xC0000000 | 0x0106 +#define NT_STATUS_FILES_OPEN 0xC0000000 | 0x0107 +#define NT_STATUS_CONNECTION_IN_USE 0xC0000000 | 0x0108 +#define NT_STATUS_MESSAGE_NOT_FOUND 0xC0000000 | 0x0109 +#define NT_STATUS_PROCESS_IS_TERMINATING 0xC0000000 | 0x010a +#define NT_STATUS_INVALID_LOGON_TYPE 0xC0000000 | 0x010b +#define NT_STATUS_NO_GUID_TRANSLATION 0xC0000000 | 0x010c +#define NT_STATUS_CANNOT_IMPERSONATE 0xC0000000 | 0x010d +#define NT_STATUS_IMAGE_ALREADY_LOADED 0xC0000000 | 0x010e +#define NT_STATUS_ABIOS_NOT_PRESENT 0xC0000000 | 0x010f +#define NT_STATUS_ABIOS_LID_NOT_EXIST 0xC0000000 | 0x0110 +#define NT_STATUS_ABIOS_LID_ALREADY_OWNED 0xC0000000 | 0x0111 +#define NT_STATUS_ABIOS_NOT_LID_OWNER 0xC0000000 | 0x0112 +#define NT_STATUS_ABIOS_INVALID_COMMAND 0xC0000000 | 0x0113 +#define NT_STATUS_ABIOS_INVALID_LID 0xC0000000 | 0x0114 +#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0xC0000000 | 0x0115 +#define NT_STATUS_ABIOS_INVALID_SELECTOR 0xC0000000 | 0x0116 +#define NT_STATUS_NO_LDT 0xC0000000 | 0x0117 +#define NT_STATUS_INVALID_LDT_SIZE 0xC0000000 | 0x0118 +#define NT_STATUS_INVALID_LDT_OFFSET 0xC0000000 | 0x0119 +#define NT_STATUS_INVALID_LDT_DESCRIPTOR 0xC0000000 | 0x011a +#define NT_STATUS_INVALID_IMAGE_NE_FORMAT 0xC0000000 | 0x011b +#define NT_STATUS_RXACT_INVALID_STATE 0xC0000000 | 0x011c +#define NT_STATUS_RXACT_COMMIT_FAILURE 0xC0000000 | 0x011d +#define NT_STATUS_MAPPED_FILE_SIZE_ZERO 0xC0000000 | 0x011e +#define NT_STATUS_TOO_MANY_OPENED_FILES 0xC0000000 | 0x011f +#define NT_STATUS_CANCELLED 0xC0000000 | 0x0120 +#define NT_STATUS_CANNOT_DELETE 0xC0000000 | 0x0121 +#define NT_STATUS_INVALID_COMPUTER_NAME 0xC0000000 | 0x0122 +#define NT_STATUS_FILE_DELETED 0xC0000000 | 0x0123 +#define NT_STATUS_SPECIAL_ACCOUNT 0xC0000000 | 0x0124 +#define NT_STATUS_SPECIAL_GROUP 0xC0000000 | 0x0125 +#define NT_STATUS_SPECIAL_USER 0xC0000000 | 0x0126 +#define NT_STATUS_MEMBERS_PRIMARY_GROUP 0xC0000000 | 0x0127 +#define NT_STATUS_FILE_CLOSED 0xC0000000 | 0x0128 +#define NT_STATUS_TOO_MANY_THREADS 0xC0000000 | 0x0129 +#define NT_STATUS_THREAD_NOT_IN_PROCESS 0xC0000000 | 0x012a +#define NT_STATUS_TOKEN_ALREADY_IN_USE 0xC0000000 | 0x012b +#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 0xC0000000 | 0x012c +#define NT_STATUS_COMMITMENT_LIMIT 0xC0000000 | 0x012d +#define NT_STATUS_INVALID_IMAGE_LE_FORMAT 0xC0000000 | 0x012e +#define NT_STATUS_INVALID_IMAGE_NOT_MZ 0xC0000000 | 0x012f +#define NT_STATUS_INVALID_IMAGE_PROTECT 0xC0000000 | 0x0130 +#define NT_STATUS_INVALID_IMAGE_WIN_16 0xC0000000 | 0x0131 +#define NT_STATUS_LOGON_SERVER_CONFLICT 0xC0000000 | 0x0132 +#define NT_STATUS_TIME_DIFFERENCE_AT_DC 0xC0000000 | 0x0133 +#define NT_STATUS_SYNCHRONIZATION_REQUIRED 0xC0000000 | 0x0134 +#define NT_STATUS_DLL_NOT_FOUND 0xC0000000 | 0x0135 +#define NT_STATUS_OPEN_FAILED 0xC0000000 | 0x0136 +#define NT_STATUS_IO_PRIVILEGE_FAILED 0xC0000000 | 0x0137 +#define NT_STATUS_ORDINAL_NOT_FOUND 0xC0000000 | 0x0138 +#define NT_STATUS_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0139 +#define NT_STATUS_CONTROL_C_EXIT 0xC0000000 | 0x013a +#define NT_STATUS_LOCAL_DISCONNECT 0xC0000000 | 0x013b +#define NT_STATUS_REMOTE_DISCONNECT 0xC0000000 | 0x013c +#define NT_STATUS_REMOTE_RESOURCES 0xC0000000 | 0x013d +#define NT_STATUS_LINK_FAILED 0xC0000000 | 0x013e +#define NT_STATUS_LINK_TIMEOUT 0xC0000000 | 0x013f +#define NT_STATUS_INVALID_CONNECTION 0xC0000000 | 0x0140 +#define NT_STATUS_INVALID_ADDRESS 0xC0000000 | 0x0141 +#define NT_STATUS_DLL_INIT_FAILED 0xC0000000 | 0x0142 +#define NT_STATUS_MISSING_SYSTEMFILE 0xC0000000 | 0x0143 +#define NT_STATUS_UNHANDLED_EXCEPTION 0xC0000000 | 0x0144 +#define NT_STATUS_APP_INIT_FAILURE 0xC0000000 | 0x0145 +#define NT_STATUS_PAGEFILE_CREATE_FAILED 0xC0000000 | 0x0146 +#define NT_STATUS_NO_PAGEFILE 0xC0000000 | 0x0147 +#define NT_STATUS_INVALID_LEVEL 0xC0000000 | 0x0148 +#define NT_STATUS_WRONG_PASSWORD_CORE 0xC0000000 | 0x0149 +#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 0xC0000000 | 0x014a +#define NT_STATUS_PIPE_BROKEN 0xC0000000 | 0x014b +#define NT_STATUS_REGISTRY_CORRUPT 0xC0000000 | 0x014c +#define NT_STATUS_REGISTRY_IO_FAILED 0xC0000000 | 0x014d +#define NT_STATUS_NO_EVENT_PAIR 0xC0000000 | 0x014e +#define NT_STATUS_UNRECOGNIZED_VOLUME 0xC0000000 | 0x014f +#define NT_STATUS_SERIAL_NO_DEVICE_INITED 0xC0000000 | 0x0150 +#define NT_STATUS_NO_SUCH_ALIAS 0xC0000000 | 0x0151 +#define NT_STATUS_MEMBER_NOT_IN_ALIAS 0xC0000000 | 0x0152 +#define NT_STATUS_MEMBER_IN_ALIAS 0xC0000000 | 0x0153 +#define NT_STATUS_ALIAS_EXISTS 0xC0000000 | 0x0154 +#define NT_STATUS_LOGON_NOT_GRANTED 0xC0000000 | 0x0155 +#define NT_STATUS_TOO_MANY_SECRETS 0xC0000000 | 0x0156 +#define NT_STATUS_SECRET_TOO_LONG 0xC0000000 | 0x0157 +#define NT_STATUS_INTERNAL_DB_ERROR 0xC0000000 | 0x0158 +#define NT_STATUS_FULLSCREEN_MODE 0xC0000000 | 0x0159 +#define NT_STATUS_TOO_MANY_CONTEXT_IDS 0xC0000000 | 0x015a +#define NT_STATUS_LOGON_TYPE_NOT_GRANTED 0xC0000000 | 0x015b +#define NT_STATUS_NOT_REGISTRY_FILE 0xC0000000 | 0x015c +#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x015d +#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0xC0000000 | 0x015e +#define NT_STATUS_FT_MISSING_MEMBER 0xC0000000 | 0x015f +#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 0xC0000000 | 0x0160 +#define NT_STATUS_ILLEGAL_CHARACTER 0xC0000000 | 0x0161 +#define NT_STATUS_UNMAPPABLE_CHARACTER 0xC0000000 | 0x0162 +#define NT_STATUS_UNDEFINED_CHARACTER 0xC0000000 | 0x0163 +#define NT_STATUS_FLOPPY_VOLUME 0xC0000000 | 0x0164 +#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 0xC0000000 | 0x0165 +#define NT_STATUS_FLOPPY_WRONG_CYLINDER 0xC0000000 | 0x0166 +#define NT_STATUS_FLOPPY_UNKNOWN_ERROR 0xC0000000 | 0x0167 +#define NT_STATUS_FLOPPY_BAD_REGISTERS 0xC0000000 | 0x0168 +#define NT_STATUS_DISK_RECALIBRATE_FAILED 0xC0000000 | 0x0169 +#define NT_STATUS_DISK_OPERATION_FAILED 0xC0000000 | 0x016a +#define NT_STATUS_DISK_RESET_FAILED 0xC0000000 | 0x016b +#define NT_STATUS_SHARED_IRQ_BUSY 0xC0000000 | 0x016c +#define NT_STATUS_FT_ORPHANING 0xC0000000 | 0x016d +#define NT_STATUS_PARTITION_FAILURE 0xC0000000 | 0x0172 +#define NT_STATUS_INVALID_BLOCK_LENGTH 0xC0000000 | 0x0173 +#define NT_STATUS_DEVICE_NOT_PARTITIONED 0xC0000000 | 0x0174 +#define NT_STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000000 | 0x0175 +#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000000 | 0x0176 +#define NT_STATUS_EOM_OVERFLOW 0xC0000000 | 0x0177 +#define NT_STATUS_NO_MEDIA 0xC0000000 | 0x0178 +#define NT_STATUS_NO_SUCH_MEMBER 0xC0000000 | 0x017a +#define NT_STATUS_INVALID_MEMBER 0xC0000000 | 0x017b +#define NT_STATUS_KEY_DELETED 0xC0000000 | 0x017c +#define NT_STATUS_NO_LOG_SPACE 0xC0000000 | 0x017d +#define NT_STATUS_TOO_MANY_SIDS 0xC0000000 | 0x017e +#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x017f +#define NT_STATUS_KEY_HAS_CHILDREN 0xC0000000 | 0x0180 +#define NT_STATUS_CHILD_MUST_BE_VOLATILE 0xC0000000 | 0x0181 +#define NT_STATUS_DEVICE_CONFIGURATION_ERROR 0xC0000000 | 0x0182 +#define NT_STATUS_DRIVER_INTERNAL_ERROR 0xC0000000 | 0x0183 +#define NT_STATUS_INVALID_DEVICE_STATE 0xC0000000 | 0x0184 +#define NT_STATUS_IO_DEVICE_ERROR 0xC0000000 | 0x0185 +#define NT_STATUS_DEVICE_PROTOCOL_ERROR 0xC0000000 | 0x0186 +#define NT_STATUS_BACKUP_CONTROLLER 0xC0000000 | 0x0187 +#define NT_STATUS_LOG_FILE_FULL 0xC0000000 | 0x0188 +#define NT_STATUS_TOO_LATE 0xC0000000 | 0x0189 +#define NT_STATUS_NO_TRUST_LSA_SECRET 0xC0000000 | 0x018a +#define NT_STATUS_NO_TRUST_SAM_ACCOUNT 0xC0000000 | 0x018b +#define NT_STATUS_TRUSTED_DOMAIN_FAILURE 0xC0000000 | 0x018c +#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC0000000 | 0x018d +#define NT_STATUS_EVENTLOG_FILE_CORRUPT 0xC0000000 | 0x018e +#define NT_STATUS_EVENTLOG_CANT_START 0xC0000000 | 0x018f +#define NT_STATUS_TRUST_FAILURE 0xC0000000 | 0x0190 +#define NT_STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000000 | 0x0191 +#define NT_STATUS_NETLOGON_NOT_STARTED 0xC0000000 | 0x0192 +#define NT_STATUS_ACCOUNT_EXPIRED 0xC0000000 | 0x0193 +#define NT_STATUS_POSSIBLE_DEADLOCK 0xC0000000 | 0x0194 +#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000000 | 0x0195 +#define NT_STATUS_REMOTE_SESSION_LIMIT 0xC0000000 | 0x0196 +#define NT_STATUS_EVENTLOG_FILE_CHANGED 0xC0000000 | 0x0197 +#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000000 | 0x0198 +#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000000 | 0x0199 +#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC0000000 | 0x019a +#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 0xC0000000 | 0x019b +#define NT_STATUS_FS_DRIVER_REQUIRED 0xC0000000 | 0x019c +#define NT_STATUS_NO_USER_SESSION_KEY 0xC0000000 | 0x0202 +#define NT_STATUS_USER_SESSION_DELETED 0xC0000000 | 0x0203 +#define NT_STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000000 | 0x0204 +#define NT_STATUS_INSUFF_SERVER_RESOURCES 0xC0000000 | 0x0205 +#define NT_STATUS_INVALID_BUFFER_SIZE 0xC0000000 | 0x0206 +#define NT_STATUS_INVALID_ADDRESS_COMPONENT 0xC0000000 | 0x0207 +#define NT_STATUS_INVALID_ADDRESS_WILDCARD 0xC0000000 | 0x0208 +#define NT_STATUS_TOO_MANY_ADDRESSES 0xC0000000 | 0x0209 +#define NT_STATUS_ADDRESS_ALREADY_EXISTS 0xC0000000 | 0x020a +#define NT_STATUS_ADDRESS_CLOSED 0xC0000000 | 0x020b +#define NT_STATUS_CONNECTION_DISCONNECTED 0xC0000000 | 0x020c +#define NT_STATUS_CONNECTION_RESET 0xC0000000 | 0x020d +#define NT_STATUS_TOO_MANY_NODES 0xC0000000 | 0x020e +#define NT_STATUS_TRANSACTION_ABORTED 0xC0000000 | 0x020f +#define NT_STATUS_TRANSACTION_TIMED_OUT 0xC0000000 | 0x0210 +#define NT_STATUS_TRANSACTION_NO_RELEASE 0xC0000000 | 0x0211 +#define NT_STATUS_TRANSACTION_NO_MATCH 0xC0000000 | 0x0212 +#define NT_STATUS_TRANSACTION_RESPONDED 0xC0000000 | 0x0213 +#define NT_STATUS_TRANSACTION_INVALID_ID 0xC0000000 | 0x0214 +#define NT_STATUS_TRANSACTION_INVALID_TYPE 0xC0000000 | 0x0215 +#define NT_STATUS_NOT_SERVER_SESSION 0xC0000000 | 0x0216 +#define NT_STATUS_NOT_CLIENT_SESSION 0xC0000000 | 0x0217 +#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 0xC0000000 | 0x0218 +#define NT_STATUS_DEBUG_ATTACH_FAILED 0xC0000000 | 0x0219 +#define NT_STATUS_SYSTEM_PROCESS_TERMINATED 0xC0000000 | 0x021a +#define NT_STATUS_DATA_NOT_ACCEPTED 0xC0000000 | 0x021b +#define NT_STATUS_NO_BROWSER_SERVERS_FOUND 0xC0000000 | 0x021c +#define NT_STATUS_VDM_HARD_ERROR 0xC0000000 | 0x021d +#define NT_STATUS_DRIVER_CANCEL_TIMEOUT 0xC0000000 | 0x021e +#define NT_STATUS_REPLY_MESSAGE_MISMATCH 0xC0000000 | 0x021f +#define NT_STATUS_MAPPED_ALIGNMENT 0xC0000000 | 0x0220 +#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 0xC0000000 | 0x0221 +#define NT_STATUS_LOST_WRITEBEHIND_DATA 0xC0000000 | 0x0222 +#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0xC0000000 | 0x0223 +#define NT_STATUS_PASSWORD_MUST_CHANGE 0xC0000000 | 0x0224 +#define NT_STATUS_NOT_FOUND 0xC0000000 | 0x0225 +#define NT_STATUS_NOT_TINY_STREAM 0xC0000000 | 0x0226 +#define NT_STATUS_RECOVERY_FAILURE 0xC0000000 | 0x0227 +#define NT_STATUS_STACK_OVERFLOW_READ 0xC0000000 | 0x0228 +#define NT_STATUS_FAIL_CHECK 0xC0000000 | 0x0229 +#define NT_STATUS_DUPLICATE_OBJECTID 0xC0000000 | 0x022a +#define NT_STATUS_OBJECTID_EXISTS 0xC0000000 | 0x022b +#define NT_STATUS_CONVERT_TO_LARGE 0xC0000000 | 0x022c +#define NT_STATUS_RETRY 0xC0000000 | 0x022d +#define NT_STATUS_FOUND_OUT_OF_SCOPE 0xC0000000 | 0x022e +#define NT_STATUS_ALLOCATE_BUCKET 0xC0000000 | 0x022f +#define NT_STATUS_PROPSET_NOT_FOUND 0xC0000000 | 0x0230 +#define NT_STATUS_MARSHALL_OVERFLOW 0xC0000000 | 0x0231 +#define NT_STATUS_INVALID_VARIANT 0xC0000000 | 0x0232 +#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0xC0000000 | 0x0233 +#define NT_STATUS_ACCOUNT_LOCKED_OUT 0xC0000000 | 0x0234 +#define NT_STATUS_HANDLE_NOT_CLOSABLE 0xC0000000 | 0x0235 +#define NT_STATUS_CONNECTION_REFUSED 0xC0000000 | 0x0236 +#define NT_STATUS_GRACEFUL_DISCONNECT 0xC0000000 | 0x0237 +#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 0xC0000000 | 0x0238 +#define NT_STATUS_ADDRESS_NOT_ASSOCIATED 0xC0000000 | 0x0239 +#define NT_STATUS_CONNECTION_INVALID 0xC0000000 | 0x023a +#define NT_STATUS_CONNECTION_ACTIVE 0xC0000000 | 0x023b +#define NT_STATUS_NETWORK_UNREACHABLE 0xC0000000 | 0x023c +#define NT_STATUS_HOST_UNREACHABLE 0xC0000000 | 0x023d +#define NT_STATUS_PROTOCOL_UNREACHABLE 0xC0000000 | 0x023e +#define NT_STATUS_PORT_UNREACHABLE 0xC0000000 | 0x023f +#define NT_STATUS_REQUEST_ABORTED 0xC0000000 | 0x0240 +#define NT_STATUS_CONNECTION_ABORTED 0xC0000000 | 0x0241 +#define NT_STATUS_BAD_COMPRESSION_BUFFER 0xC0000000 | 0x0242 +#define NT_STATUS_USER_MAPPED_FILE 0xC0000000 | 0x0243 +#define NT_STATUS_AUDIT_FAILED 0xC0000000 | 0x0244 +#define NT_STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000000 | 0x0245 +#define NT_STATUS_CONNECTION_COUNT_LIMIT 0xC0000000 | 0x0246 +#define NT_STATUS_LOGIN_TIME_RESTRICTION 0xC0000000 | 0x0247 +#define NT_STATUS_LOGIN_WKSTA_RESTRICTION 0xC0000000 | 0x0248 +#define NT_STATUS_IMAGE_MP_UP_MISMATCH 0xC0000000 | 0x0249 +#define NT_STATUS_INSUFFICIENT_LOGON_INFO 0xC0000000 | 0x0250 +#define NT_STATUS_BAD_DLL_ENTRYPOINT 0xC0000000 | 0x0251 +#define NT_STATUS_BAD_SERVICE_ENTRYPOINT 0xC0000000 | 0x0252 +#define NT_STATUS_LPC_REPLY_LOST 0xC0000000 | 0x0253 +#define NT_STATUS_IP_ADDRESS_CONFLICT1 0xC0000000 | 0x0254 +#define NT_STATUS_IP_ADDRESS_CONFLICT2 0xC0000000 | 0x0255 +#define NT_STATUS_REGISTRY_QUOTA_LIMIT 0xC0000000 | 0x0256 +#define NT_STATUS_PATH_NOT_COVERED 0xC0000000 | 0x0257 +#define NT_STATUS_NO_CALLBACK_ACTIVE 0xC0000000 | 0x0258 +#define NT_STATUS_LICENSE_QUOTA_EXCEEDED 0xC0000000 | 0x0259 +#define NT_STATUS_PWD_TOO_SHORT 0xC0000000 | 0x025a +#define NT_STATUS_PWD_TOO_RECENT 0xC0000000 | 0x025b +#define NT_STATUS_PWD_HISTORY_CONFLICT 0xC0000000 | 0x025c +#define NT_STATUS_PLUGPLAY_NO_DEVICE 0xC0000000 | 0x025e +#define NT_STATUS_UNSUPPORTED_COMPRESSION 0xC0000000 | 0x025f +#define NT_STATUS_INVALID_HW_PROFILE 0xC0000000 | 0x0260 +#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0xC0000000 | 0x0261 +#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 0xC0000000 | 0x0262 +#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0263 +#define NT_STATUS_RESOURCE_NOT_OWNED 0xC0000000 | 0x0264 +#define NT_STATUS_TOO_MANY_LINKS 0xC0000000 | 0x0265 +#define NT_STATUS_QUOTA_LIST_INCONSISTENT 0xC0000000 | 0x0266 +#define NT_STATUS_FILE_IS_OFFLINE 0xC0000000 | 0x0267 +#define NT_STATUS_NO_SUCH_JOB 0xC0000000 | 0xEDE /* scheduler */ + +#endif /* _NTERR_H */ diff -urN linux-2.4.27/fs/cifs/ntlmssp.h linux-2.4.27-cifs-1.20c/fs/cifs/ntlmssp.h --- linux-2.4.27/fs/cifs/ntlmssp.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/ntlmssp.h Wed Jul 14 00:25:05 2004 @@ -0,0 +1,101 @@ +/* + * fs/cifs/ntlmssp.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma pack(1) + +#define NTLMSSP_SIGNATURE "NTLMSSP" +/* Message Types */ +#define NtLmNegotiate 1 +#define NtLmChallenge 2 +#define NtLmAuthenticate 3 +#define UnknownMessage 8 + +/* Negotiate Flags */ +#define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode +#define NTLMSSP_NEGOTIATE_OEM 0x02 // Text strings are in OEM +#define NTLMSSP_REQUEST_TARGET 0x04 // Server return its auth realm +#define NTLMSSP_NEGOTIATE_SIGN 0x0010 // Request signature capability +#define NTLMSSP_NEGOTIATE_SEAL 0x0020 // Request confidentiality +#define NTLMSSP_NEGOTIATE_DGRAM 0x0040 +#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 // Use LM session key for sign/seal +#define NTLMSSP_NEGOTIATE_NTLM 0x0200 // NTLM authentication +#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 +#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 +#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 // client/server on same machine +#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 // Sign for all security levels +#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 +#define NTLMSSP_TARGET_TYPE_SERVER 0x20000 +#define NTLMSSP_TARGET_TYPE_SHARE 0x40000 +#define NTLMSSP_NEGOTIATE_NTLMV2 0x80000 +#define NTLMSSP_REQUEST_INIT_RESP 0x100000 +#define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 +#define NTLMSSP_REQUEST_NOT_NT_KEY 0x400000 +#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 +#define NTLMSSP_NEGOTIATE_128 0x20000000 +#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 +#define NTLMSSP_NEGOTIATE_56 0x80000000 + +/* Although typedefs are not commonly used for structure definitions */ +/* in the Linux kernel, in this particular case they are useful */ +/* to more closely match the standards document for NTLMSSP from */ +/* OpenGroup and to make the code more closely match the standard in */ +/* appearance */ + +typedef struct _SECURITY_BUFFER { + __u16 Length; + __u16 MaximumLength; + __u32 Buffer; /* offset to buffer */ +} SECURITY_BUFFER; + +typedef struct _NEGOTIATE_MESSAGE { + __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; + __u32 MessageType; /* 1 */ + __u32 NegotiateFlags; + SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ + SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ + char DomainString[0]; + /* followed by WorkstationString */ +} NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; + +typedef struct _CHALLENGE_MESSAGE { + __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; + __u32 MessageType; /* 2 */ + SECURITY_BUFFER TargetName; + __u32 NegotiateFlags; + __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; + __u8 Reserved[8]; + SECURITY_BUFFER TargetInfoArray; +} CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; + +typedef struct _AUTHENTICATE_MESSAGE { + __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; + __u32 MessageType; /* 3 */ + SECURITY_BUFFER LmChallengeResponse; + SECURITY_BUFFER NtChallengeResponse; + SECURITY_BUFFER DomainName; + SECURITY_BUFFER UserName; + SECURITY_BUFFER WorkstationName; + SECURITY_BUFFER SessionKey; + __u32 NegotiateFlags; + char UserString[0]; +} AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; + +#pragma pack() /* resume default structure packing */ diff -urN linux-2.4.27/fs/cifs/rfc1002pdu.h linux-2.4.27-cifs-1.20c/fs/cifs/rfc1002pdu.h --- linux-2.4.27/fs/cifs/rfc1002pdu.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/rfc1002pdu.h Wed Jul 14 00:25:05 2004 @@ -0,0 +1,79 @@ +/* + * fs/cifs/rfc1002pdu.h + * + * Protocol Data Unit definitions for RFC 1001/1002 support + * + * Copyright (c) International Business Machines Corp., 2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma pack(1) + +/* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ + + /* RFC 1002 session packet types */ +#define RFC1002_SESSION_MESASAGE 0x00 +#define RFC1002_SESSION_REQUEST 0x81 +#define RFC1002_POSITIVE_SESSION_RESPONSE 0x82 +#define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83 +#define RFC1002_RETARGET_SESSION_RESPONSE 0x83 +#define RFC1002_SESSION_KEEP_ALIVE 0x85 + + /* RFC 1002 flags (only one defined */ +#define RFC1002_LENGTH_EXTEND 0x80 /* high order bit of length (ie +64K) */ + +struct rfc1002_session_packet { + __u8 type; + __u8 flags; + __u16 length; + union { + struct { + __u8 called_len; + __u8 called_name[32]; + __u8 scope1; /* null */ + __u8 calling_len; + __u8 calling_name[32]; + __u8 scope2; /* null */ + } session_req; + struct { + __u32 retarget_ip_addr; + __u16 port; + } retarget_resp; + __u8 neg_ses_resp_error_code; + /* POSITIVE_SESSION_RESPONSE packet does not include trailer. + SESSION_KEEP_ALIVE packet also does not include a trailer. + Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */ + } trailer; +}; + +/* Negative Session Response error codes */ +#define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */ +#define RFC1002_NOT_LISTENING_CALLING 0x81 /* not listening on calling name */ +#define RFC1002_NOT_PRESENT 0x82 /* called name not present */ +#define RFC1002_INSUFFICIENT_RESOURCE 0x83 +#define RFC1002_UNSPECIFIED_ERROR 0x8F + +/* RFC 1002 Datagram service packets are not defined here as they +are not needed for the network filesystem client unless we plan on +implementing broadcast resolution of the server ip address (from +server netbios name). Currently server names are resolved only via DNS +(tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/ + +#define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER " + +#pragma pack() /* resume default structure packing */ + diff -urN linux-2.4.27/fs/cifs/smbdes.c linux-2.4.27-cifs-1.20c/fs/cifs/smbdes.c --- linux-2.4.27/fs/cifs/smbdes.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/smbdes.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,408 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + + a partial implementation of DES designed for use in the + SMB authentication protocol + + Copyright (C) Andrew Tridgell 1998 + Modified by Steve French (sfrench@us.ibm.com) 2002,2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* NOTES: + + This code makes no attempt to be fast! In fact, it is a very + slow implementation + + This code is NOT a complete DES implementation. It implements only + the minimum necessary for SMB authentication, as used by all SMB + products (including every copy of Microsoft Windows95 ever sold) + + In particular, it can only do a unchained forward DES pass. This + means it is not possible to use this code for encryption/decryption + of data, instead it is only useful as a "hash" algorithm. + + There is no entry point into this code that allows normal DES operation. + + I believe this means that this code does not come under ITAR + regulations but this is NOT a legal opinion. If you are concerned + about the applicability of ITAR regulations to this code then you + should confirm it for yourself (and maybe let me know if you come + up with a different answer to the one above) +*/ +#include +#define uchar unsigned char + +static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4 +}; + +static uchar perm2[48] = { 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 +}; + +static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7 +}; + +static uchar perm4[48] = { 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1 +}; + +static uchar perm5[32] = { 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25 +}; + +static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25 +}; + +static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; + +static uchar sbox[8][4][16] = { + {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, + {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, + {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, + {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}}, + + {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, + {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, + {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, + {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}}, + + {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, + {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, + {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, + {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}}, + + {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, + {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, + {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, + {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}}, + + {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, + {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, + {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, + {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}}, + + {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, + {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, + {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, + {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}}, + + {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, + {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, + {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, + {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}}, + + {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, + {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, + {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, + {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}} +}; + +static void +permute(char *out, char *in, uchar * p, int n) +{ + int i; + for (i = 0; i < n; i++) + out[i] = in[p[i] - 1]; +} + +static void +lshift(char *d, int count, int n) +{ + char out[64]; + int i; + for (i = 0; i < n; i++) + out[i] = d[(i + count) % n]; + for (i = 0; i < n; i++) + d[i] = out[i]; +} + +static void +concat(char *out, char *in1, char *in2, int l1, int l2) +{ + while (l1--) + *out++ = *in1++; + while (l2--) + *out++ = *in2++; +} + +static void +xor(char *out, char *in1, char *in2, int n) +{ + int i; + for (i = 0; i < n; i++) + out[i] = in1[i] ^ in2[i]; +} + +static void +dohash(char *out, char *in, char *key, int forw) +{ + int i, j, k; + char *pk1; + char c[28]; + char d[28]; + char *cd; + char ki[16][48]; + char *pd1; + char l[32], r[32]; + char *rl; + + /* Have to reduce stack usage */ + pk1 = kmalloc(56+56+64+64,GFP_KERNEL); + if(pk1 == NULL) + return; + + cd = pk1 + 56; + pd1= cd + 56; + rl = pd1 + 64; + + permute(pk1, key, perm1, 56); + + for (i = 0; i < 28; i++) + c[i] = pk1[i]; + for (i = 0; i < 28; i++) + d[i] = pk1[i + 28]; + + for (i = 0; i < 16; i++) { + lshift(c, sc[i], 28); + lshift(d, sc[i], 28); + + concat(cd, c, d, 28, 28); + permute(ki[i], cd, perm2, 48); + } + + permute(pd1, in, perm3, 64); + + for (j = 0; j < 32; j++) { + l[j] = pd1[j]; + r[j] = pd1[j + 32]; + } + + for (i = 0; i < 16; i++) { + char *er; /* er[48] */ + char *erk; /* erk[48] */ + char b[8][6]; + char *cb; /* cb[32] */ + char *pcb; /* pcb[32] */ + char *r2; /* r2[32] */ + + er = kmalloc(48+48+32+32+32, GFP_KERNEL); + if(er == NULL) { + kfree(pk1); + return; + } + erk = er+48; + cb = erk+48; + pcb = cb+32; + r2 = pcb+32; + + permute(er, r, perm4, 48); + + xor(erk, er, ki[forw ? i : 15 - i], 48); + + for (j = 0; j < 8; j++) + for (k = 0; k < 6; k++) + b[j][k] = erk[j * 6 + k]; + + for (j = 0; j < 8; j++) { + int m, n; + m = (b[j][0] << 1) | b[j][5]; + + n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << + 1) | b[j][4]; + + for (k = 0; k < 4; k++) + b[j][k] = + (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0; + } + + for (j = 0; j < 8; j++) + for (k = 0; k < 4; k++) + cb[j * 4 + k] = b[j][k]; + permute(pcb, cb, perm5, 32); + + xor(r2, l, pcb, 32); + + for (j = 0; j < 32; j++) + l[j] = r[j]; + + for (j = 0; j < 32; j++) + r[j] = r2[j]; + + kfree(er); + } + + concat(rl, r, l, 32, 32); + + permute(out, rl, perm6, 64); + kfree(pk1); +} + +static void +str_to_key(unsigned char *str, unsigned char *key) +{ + int i; + + key[0] = str[0] >> 1; + key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); + key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); + key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); + key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); + key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); + key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); + key[7] = str[6] & 0x7F; + for (i = 0; i < 8; i++) { + key[i] = (key[i] << 1); + } +} + +static void +smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw) +{ + int i; + char *outb; /* outb[64] */ + char *inb; /* inb[64] */ + char *keyb; /* keyb[64] */ + unsigned char key2[8]; + + outb = kmalloc(64 * 3,GFP_KERNEL); + if(outb == NULL) + return; + + inb = outb + 64; + keyb = inb + 64; + + str_to_key(key, key2); + + for (i = 0; i < 64; i++) { + inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; + keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; + outb[i] = 0; + } + + dohash(outb, inb, keyb, forw); + + for (i = 0; i < 8; i++) { + out[i] = 0; + } + + for (i = 0; i < 64; i++) { + if (outb[i]) + out[i / 8] |= (1 << (7 - (i % 8))); + } + kfree(outb); +} + +void +E_P16(unsigned char *p14, unsigned char *p16) +{ + unsigned char sp8[8] = + { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; + smbhash(p16, sp8, p14, 1); + smbhash(p16 + 8, sp8, p14 + 7, 1); +} + +void +E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) +{ + smbhash(p24, c8, p21, 1); + smbhash(p24 + 8, c8, p21 + 7, 1); + smbhash(p24 + 16, c8, p21 + 14, 1); +} + +void +D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) +{ + smbhash(out, in, p14, 0); + smbhash(out + 8, in + 8, p14 + 7, 0); +} + +void +E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) +{ + smbhash(out, in, p14, 1); + smbhash(out + 8, in + 8, p14 + 7, 1); +} + +void +cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key) +{ + unsigned char buf[8]; + + smbhash(buf, in, key, 1); + smbhash(out, buf, key + 9, 1); +} + +void +cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key) +{ + unsigned char buf[8]; + static unsigned char key2[8]; + + smbhash(buf, in, key, 1); + key2[0] = key[7]; + smbhash(out, buf, key2, 1); +} + +void +cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, int forw) +{ + static unsigned char key2[8]; + + smbhash(out, in, key, forw); + key2[0] = key[7]; + smbhash(out + 8, in + 8, key2, forw); +} diff -urN linux-2.4.27/fs/cifs/smbencrypt.c linux-2.4.27-cifs-1.20c/fs/cifs/smbencrypt.c --- linux-2.4.27/fs/cifs/smbencrypt.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/smbencrypt.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,295 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + SMB parameters and setup + Copyright (C) Andrew Tridgell 1992-2000 + Copyright (C) Luke Kenneth Casson Leighton 1996-2000 + Modified by Jeremy Allison 1995. + Copyright (C) Andrew Bartlett 2002-2003 + Modified by Steve French (sfrench@us.ibm.com) 2002-2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include "cifs_unicode.h" +#include "cifspdu.h" +#include "md5.h" +#include "cifs_debug.h" + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +/* following came from the other byteorder.h to avoid include conflicts */ +#define CVAL(buf,pos) (((unsigned char *)(buf))[pos]) +#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) +#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) + +/*The following definitions come from lib/md4.c */ + +void mdfour(unsigned char *out, unsigned char *in, int n); + +/*The following definitions come from libsmb/smbdes.c */ + +void E_P16(unsigned char *p14, unsigned char *p16); +void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24); +void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out); +void E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out); +void cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key); +void cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key); +void cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, + int forw); + +/*The following definitions come from libsmb/smbencrypt.c */ + +void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); +void E_md4hash(const unsigned char *passwd, unsigned char *p16); +void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]); +void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, + unsigned char p24[24]); +void NTLMSSPOWFencrypt(unsigned char passwd[8], + unsigned char *ntlmchalresp, unsigned char p24[24]); +void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); +int decode_pw_buffer(char in_buffer[516], char *new_pwrd, + int new_pwrd_size, __u32 * new_pw_len); + +/* + This implements the X/Open SMB password encryption + It takes a password, a 8 byte "crypt key" and puts 24 bytes of + encrypted password into p24 */ +/* Note that password must be uppercased and null terminated */ +void +SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) +{ + unsigned char p14[15], p21[21]; + + memset(p21, '\0', 21); + memset(p14, '\0', 14); + strncpy((char *) p14, (char *) passwd, 14); + +/* strupper((char *)p14); *//* BB at least uppercase the easy range */ + E_P16(p14, p21); + + SMBOWFencrypt(p21, c8, p24); + + memset(p14,0,15); + memset(p21,0,21); +} + +/* Routines for Windows NT MD4 Hash functions. */ +static int +_my_wcslen(__u16 * str) +{ + int len = 0; + while (*str++ != 0) + len++; + return len; +} + +/* + * Convert a string into an NT UNICODE string. + * Note that regardless of processor type + * this must be in intel (little-endian) + * format. + */ + +static int +_my_mbstowcs(__u16 * dst, const unsigned char *src, int len) +{ /* not a very good conversion routine - change/fix */ + int i; + __u16 val; + + for (i = 0; i < len; i++) { + val = *src; + SSVAL(dst, 0, val); + dst++; + src++; + if (val == 0) + break; + } + return i; +} + +/* + * Creates the MD4 Hash of the users password in NT UNICODE. + */ + +void +E_md4hash(const unsigned char *passwd, unsigned char *p16) +{ + int len; + __u16 wpwd[129]; + + /* Password cannot be longer than 128 characters */ + if(passwd) { + len = strlen((char *) passwd); + if (len > 128) { + len = 128; + } + /* Password must be converted to NT unicode */ + _my_mbstowcs(wpwd, passwd, len); + } else + len = 0; + + wpwd[len] = 0; /* Ensure string is null terminated */ + /* Calculate length in bytes */ + len = _my_wcslen(wpwd) * sizeof (__u16); + + mdfour(p16, (unsigned char *) wpwd, len); + memset(wpwd,0,129 * 2); +} + +/* Does both the NT and LM owfs of a user's password */ +void +nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) +{ + char passwd[514]; + + memset(passwd, '\0', 514); + if (strlen(pwd) < 513) + strcpy(passwd, pwd); + else + memcpy(passwd, pwd, 512); + /* Calculate the MD4 hash (NT compatible) of the password */ + memset(nt_p16, '\0', 16); + E_md4hash(passwd, nt_p16); + + /* Mangle the passwords into Lanman format */ + passwd[14] = '\0'; +/* strupper(passwd); */ + + /* Calculate the SMB (lanman) hash functions of the password */ + + memset(p16, '\0', 16); + E_P16((unsigned char *) passwd, (unsigned char *) p16); + + /* clear out local copy of user's password (just being paranoid). */ + memset(passwd, '\0', sizeof (passwd)); +} + +/* Does the NTLMv2 owfs of a user's password */ +void +ntv2_owf_gen(const unsigned char owf[16], const char *user_n, + const char *domain_n, unsigned char kr_buf[16], + const struct nls_table *nls_codepage) +{ + wchar_t * user_u; + wchar_t * dom_u; + int user_l, domain_l; + struct HMACMD5Context ctx; + + /* might as well do one alloc to hold both (user_u and dom_u) */ + user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL); + if(user_u == NULL) + return; + dom_u = user_u + 1024; + + /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); + push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */ + + /* BB user and domain may need to be uppercased */ + user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage); + domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage); + + user_l++; /* trailing null */ + domain_l++; + + hmac_md5_init_limK_to_64(owf, 16, &ctx); + hmac_md5_update((const unsigned char *) user_u, user_l * 2, &ctx); + hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx); + hmac_md5_final(kr_buf, &ctx); + + kfree(user_u); +} + +/* Does the des encryption from the NT or LM MD4 hash. */ +void +SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, + unsigned char p24[24]) +{ + unsigned char p21[21]; + + memset(p21, '\0', 21); + + memcpy(p21, passwd, 16); + E_P24(p21, c8, p24); +} + +/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ +void +NTLMSSPOWFencrypt(unsigned char passwd[8], + unsigned char *ntlmchalresp, unsigned char p24[24]) +{ + unsigned char p21[21]; + + memset(p21, '\0', 21); + memcpy(p21, passwd, 8); + memset(p21 + 8, 0xbd, 8); + + E_P24(p21, ntlmchalresp, p24); +} + +/* Does the NT MD4 hash then des encryption. */ + +void +SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) +{ + unsigned char p21[21]; + + memset(p21, '\0', 21); + + E_md4hash(passwd, p21); + SMBOWFencrypt(p21, c8, p24); +} + +/* Does the md5 encryption from the NT hash for NTLMv2. */ +void +SMBOWFencrypt_ntv2(const unsigned char kr[16], + const struct data_blob * srv_chal, + const struct data_blob * cli_chal, unsigned char resp_buf[16]) +{ + struct HMACMD5Context ctx; + + hmac_md5_init_limK_to_64(kr, 16, &ctx); + hmac_md5_update(srv_chal->data, srv_chal->length, &ctx); + hmac_md5_update(cli_chal->data, cli_chal->length, &ctx); + hmac_md5_final(resp_buf, &ctx); +} + +void +SMBsesskeygen_ntv2(const unsigned char kr[16], + const unsigned char *nt_resp, __u8 sess_key[16]) +{ + struct HMACMD5Context ctx; + + hmac_md5_init_limK_to_64(kr, 16, &ctx); + hmac_md5_update(nt_resp, 16, &ctx); + hmac_md5_final((unsigned char *) sess_key, &ctx); +} + +void +SMBsesskeygen_ntv1(const unsigned char kr[16], + const unsigned char *nt_resp, __u8 sess_key[16]) +{ + mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16); +} diff -urN linux-2.4.27/fs/cifs/smberr.c linux-2.4.27-cifs-1.20c/fs/cifs/smberr.c --- linux-2.4.27/fs/cifs/smberr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/smberr.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,240 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Steve French (sfrench@us.ibm.com) 2002 + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +include "smberr.h" +#define NO_SYSLOG +/* error code stuff - put together by Merik Karman + merik@blackadder.dsh.oz.au */ + typedef const struct { + char *name; + int code; + char *message; + int posix_code; +} err_code_struct; + +/* Dos Error Messages */ +err_code_struct dos_msgs[] = { + {"ERRbadfunc", ERRbadfunc, "Invalid function.", -EINVAL}, + {"ERRbadfile", ERRbadfile, "File not found.", -ENOENT}, + {"ERRbadpath", ERRbadpath, "Directory invalid.", -ENOENT}, + {"ERRnofids", ERRnofids, "No file descriptors available", -EMFILE}, + {"ERRnoaccess", ERRnoaccess, "Access denied.", -EACCES}, + {"ERRbadfid", ERRbadfid, "Invalid file handle.", -EBADF}, + {"ERRbadmcb", 7, "Memory control blocks destroyed.", -EIO}, + {"ERRnomem", ERRnomem, + "Insufficient server memory to perform the requested function.", + -ENOMEM}, + {"ERRbadmem", ERRbadmem, "Invalid memory block address.", -EFAULT}, + {"ERRbadenv", ERRbadenv, "Invalid environment.", -EFAULT}, + {"ERRbadformat", 11, "Invalid format.", -EINVAL}, + {"ERRbadaccess", ERRbadaccess, "Invalid open mode." - EACCES}, + {"ERRbaddata", ERRbaddata, "Invalid data.", -EIO}, + {"ERR", ERRres, "reserved.", -EIO}, + {"ERRbaddrive", ERRbaddrive, "Invalid drive specified.", -ENXIO}, + {"ERRremcd", ERRremcd, + "A Delete Directory request attempted to remove the server's current directory.", + -EIO}, + {"ERRdiffdevice", ERRdiffdevice, "Not same device.", -EXDEV}, + {"ERRnofiles", ERRnofiles, "A File Search command can find no more files matching the specified criteria.", -ENOENT}, /* Note: must map to zero manually in some places such as readdir */ + {"ERRbadshare", ERRbadshare, + "The sharing mode specified for an Open conflicts with existing FIDs on the file.", + -EXTBSY}, + {"ERRlock", ERRlock, + "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.", + -EACCES}, + {"ERRunsup", ERRunsup, "The operation is unsupported", -EINVAL}, + {"ERRnosuchshare", ERRnosuchshare, + "You specified an invalid share name", -ENXIO}, + {"ERRfilexists", ERRfilexists, + "The file named in a Create Directory, Make New File or Link request already exists.", + -EEXIST}, + {"ERRinvalidname", ERRinvalidname, "Invalid name", -ENOENT}, + {"ERRdiskfull", ERRdiskfull, "Disk full", -ENOSPC} + + {"ERRmoredata", ERRmoredata, + "There is more data to be returned.",}, + {"ERRinvgroup", 2455, "Invalid workgroup (try the -W option)"}, + {NULL, -1, NULL, -EIO} +}; + +/* Server Error Messages */ +err_code_struct server_msgs[] = { + {"ERRerror", 1, "Non-specific error code."}, + {"ERRbadpw", 2, + "Bad password - name/password pair in a Tree Connect or Session Setup are invalid."}, + {"ERRbadtype", 3, "reserved."}, + {"ERRaccess", 4, + "The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."}, + {"ERRinvnid", 5, + "The tree ID (TID) specified in a command was invalid."}, + {"ERRinvnetname", 6, "Invalid network name in tree connect."}, + {"ERRinvdevice", 7, + "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."}, + {"ERRqfull", 49, + "Print queue full (files) -- returned by open print file."}, + {"ERRqtoobig", 50, "Print queue full -- no space."}, + {"ERRqeof", 51, "EOF on print queue dump."}, + {"ERRinvpfid", 52, "Invalid print file FID."}, + {"ERRsmbcmd", 64, + "The server did not recognize the command received."}, + {"ERRsrverror", 65, + "The server encountered an internal error, e.g., system file unavailable."}, + {"ERRfilespecs", 67, + "The file handle (FID) and pathname parameters contained an invalid combination of values."}, + {"ERRreserved", 68, "reserved."}, + {"ERRbadpermits", 69, + "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."}, + {"ERRreserved", 70, "reserved."}, + {"ERRsetattrmode", 71, + "The attribute mode in the Set File Attribute request is invalid."}, + {"ERRpaused", 81, "Server is paused."}, + {"ERRmsgoff", 82, "Not receiving messages."}, + {"ERRnoroom", 83, "No room to buffer message."}, + {"ERRrmuns", 87, "Too many remote user names."}, + {"ERRtimeout", 88, "Operation timed out."}, + {"ERRnoresource", 89, + "No resources currently available for request."}, + {"ERRtoomanyuids", 90, "Too many UIDs active on this session."}, + {"ERRbaduid", 91, + "The UID is not known as a valid ID on this session."}, + {"ERRusempx", 250, "Temp unable to support Raw, use MPX mode."}, + {"ERRusestd", 251, + "Temp unable to support Raw, use standard read/write."}, + {"ERRcontmpx", 252, "Continue in MPX mode."}, + {"ERRreserved", 253, "reserved."}, + {"ERRreserved", 254, "reserved."}, + {"ERRnosupport", 0xFFFF, "Function not supported."}, + {NULL, -1, NULL} +}; + +/* Hard Error Messages */ +err_code_struct hard_msgs[] = { + {"ERRnowrite", 19, + "Attempt to write on write-protected diskette."}, + {"ERRbadunit", 20, "Unknown unit."}, + {"ERRnotready", 21, "Drive not ready."}, + {"ERRbadcmd", 22, "Unknown command."}, + {"ERRdata", 23, "Data error (CRC)."}, + {"ERRbadreq", 24, "Bad request structure length."}, + {"ERRseek", 25, "Seek error."}, + {"ERRbadmedia", 26, "Unknown media type."}, + {"ERRbadsector", 27, "Sector not found."}, + {"ERRnopaper", 28, "Printer out of paper."}, + {"ERRwrite", 29, "Write fault."}, + {"ERRread", 30, "Read fault."}, + {"ERRgeneral", 31, "General failure."}, + {"ERRbadshare", 32, "An open conflicts with an existing open."}, + {"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."}, + {"ERRwrongdisk", 34, "The wrong disk was found in a drive."}, + {"ERRFCBUnavail", 35, "No FCBs are available to process request."}, + {"ERRsharebufexc", 36, "A sharing buffer has been exceeded."}, + {NULL, -1, NULL} +}; + + +const struct { + int code; + char *class; + err_code_struct *err_msgs; +} err_classes[] = { + { + 0, "SUCCESS", NULL}, { + 0x01, "ERRDOS", dos_msgs}, { + 0x02, "ERRSRV", server_msgs}, { + 0x03, "ERRHRD", hard_msgs}, { + 0x04, "ERRXOS", NULL}, { + 0xE1, "ERRRMX1", NULL}, { + 0xE2, "ERRRMX2", NULL}, { + 0xE3, "ERRRMX3", NULL}, { + 0xFF, "ERRCMD", NULL}, { +-1, NULL, NULL}}; + + +/**************************************************************************** +return a SMB error string from a SMB buffer +****************************************************************************/ +char *smb_dos_errstr(char *inbuf) +{ + static pstring ret; + int class = CVAL(inbuf, smb_rcls); + int num = SVAL(inbuf, smb_err); + int i, j; + + for (i = 0; err_classes[i].class; i++) + if (err_classes[i].code == class) { + if (err_classes[i].err_msgs) { + err_code_struct *err = + err_classes[i].err_msgs; + for (j = 0; err[j].name; j++) + if (num == err[j].code) { + if (DEBUGLEVEL > 0) + slprintf(ret, + sizeof + (ret) - 1, + "%s - %s (%s)", + err_classes + [i].class, + err[j]. + name, + err[j]. + message); + else + slprintf(ret, + sizeof + (ret) - 1, + "%s - %s", + err_classes + [i].class, + err[j]. + name); + return ret; + } + } + + slprintf(ret, sizeof(ret) - 1, "%s - %d", + err_classes[i].class, num); + return ret; + } + + slprintf(ret, sizeof(ret) - 1, "Error: Unknown error (%d,%d)", + class, num); + return (ret); +} + + +/***************************************************************************** + returns an WERROR error message. + *****************************************************************************/ +char *werror_str(WERROR status) +{ + static fstring msg; + slprintf(msg, sizeof(msg), "WIN32 code 0x%08x", W_ERROR_V(status)); + return msg; +} + + +/***************************************************************************** +map a unix errno to a win32 error + *****************************************************************************/ +WERROR map_werror_from_unix(int error) +{ + NTSTATUS status = map_nt_error_from_unix(error); + return ntstatus_to_werror(status); +} diff -urN linux-2.4.27/fs/cifs/smberr.h linux-2.4.27-cifs-1.20c/fs/cifs/smberr.h --- linux-2.4.27/fs/cifs/smberr.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/smberr.h Wed Jul 14 00:25:05 2004 @@ -0,0 +1,113 @@ +/* + * fs/cifs/smberr.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * See Error Codes section of the SNIA CIFS Specification + * for more information + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define SUCCESS 0 /* The request was successful. */ +#define ERRDOS 0x01 /* Error is from the core DOS operating system set */ +#define ERRSRV 0x02 /* Error is generated by the file server daemon */ +#define ERRHRD 0x03 /* Error is a hardware error. */ +#define ERRCMD 0xFF /* Command was not in the "SMB" format. */ + +/* The following error codes may be generated with the SUCCESS error class.*/ + +#define SUCCESS 0 /* The request was successful. */ + +/* The following error codes may be generated with the ERRDOS error class.*/ + +#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. */ +#define ERRbadfile 2 /*File not found. The last component of a file's pathname could not be found. */ +#define ERRbadpath 3 /* Directory invalid. A directory component in a pathname could not be found. */ +#define ERRnofids 4 /* Too many open files. The server has no file handles available. */ +#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 */ +#define ERRbadfid 6 /* Invalid file handle. The file handle specified was not recognized by the server. */ +#define ERRbadmcb 7 /* Memory control blocks destroyed. */ +#define ERRnomem 8 /* Insufficient server memory to perform the requested function. */ +#define ERRbadmem 9 /* Invalid memory block address. */ +#define ERRbadenv 10 /* Invalid environment. */ +#define ERRbadformat 11 /* Invalid format. */ +#define ERRbadaccess 12 /* Invalid open mode. */ +#define ERRbaddata 13 /* Invalid data (generated only by IOCTL calls within the server). */ +#define ERRbaddrive 15 /* Invalid drive specified. */ +#define ERRremcd 16 /* A Delete Directory request attempted to remove the server's current directory. */ +#define ERRdiffdevice 17 /* Not same device (e.g., a cross volume rename was attempted */ +#define ERRnofiles 18 /* A File Search command can find no more files matching the specified criteria. */ +#define ERRgeneral 31 +#define ERRbadshare 32 /* The sharing mode specified for an Open conflicts with existing FIDs on the file. */ +#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. */ +#define ERRunsup 50 +#define ERRnosuchshare 67 +#define ERRfilexists 80 /* The file named in the request already exists. */ +#define ERRinvparm 87 +#define ERRdiskfull 112 +#define ERRinvname 123 +#define ERRdirnotempty 145 +#define ERRnotlocked 158 +#define ERRalreadyexists 183 +#define ERRbadpipe 230 +#define ERRpipebusy 231 +#define ERRpipeclosing 232 +#define ERRnotconnected 233 +#define ERRmoredata 234 +#define ErrQuota 0x200 /* The operation would cause a quota limit to be exceeded. */ +#define ErrNotALink 0x201 /* A link operation was performed on a pathname that + was not a link. */ + +/* Following error codes may be generated with the ERRSRV error +class.*/ + +#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. */ +#define ERRbadpw 2 /* Bad password - name/password pair in a TreeConnect or Session Setup are invalid. */ +#define ERRbadtype 3 /* used for indicating DFS referral needed */ +#define ERRaccess 4 /* The client does not have the necessary access rights within the specified context for requested function. */ +#define ERRinvtid 5 /* The Tid specified in a command was invalid. */ +#define ERRinvnetname 6 /* Invalid network name in tree connect. */ +#define ERRinvdevice 7 /* Invalid device - printer request made to non-printer connection or non-printer request made to printer connection. */ +#define ERRqfull 49 /* Print queue full (files) -- returned by open print file. */ +#define ERRqtoobig 50 /* Print queue full -- no space. */ +#define ERRqeof 51 /* EOF on print queue dump */ +#define ERRinvpfid 52 /* Invalid print file FID. */ +#define ERRsmbcmd 64 /* The server did not recognize the command received. */ +#define ERRsrverror 65 /* The server encountered an internal error, e.g., system file unavailable. */ +#define ERRbadBID 66 /* (obsolete) */ +#define ERRfilespecs 67 /* The Fid and pathname parameters contained an invalid combination of values. */ +#define ERRbadLink 68 /* (obsolete) */ +#define ERRbadpermits 69 /* The access permissions specified for a file or directory are not a valid combination. */ +#define ERRbadPID 70 +#define ERRsetattrmode 71 /* attribute (mode) is invalid */ +#define ERRpaused 81 /* Server is paused */ +#define ERRmsgoff 82 /* reserved - messaging off */ +#define ERRnoroom 83 /* reserved - no room for message */ +#define ERRrmuns 87 /* reserved - too many remote names */ +#define ERRtimeout 88 /* operation timed out */ +#define ERRnoresource 89 /* No resources available for request */ +#define ERRtoomanyuids 90 /* Too many UIDs active on this session */ +#define ERRbaduid 91 /* The UID is not known as a valid user */ +#define ERRusempx 250 /* temporarily unable to use raw */ +#define ERRusestd 251 /* temporarily unable to use either raw or mpx */ +#define ERR_NOTIFY_ENUM_DIR 1024 +#define ERRaccountexpired 2239 +#define ERRbadclient 2240 +#define ERRbadLogonTime 2241 +#define ERRpasswordExpired 2242 +#define ERRnetlogonNotStarted 2455 +#define ERRnosupport 0xFFFF diff -urN linux-2.4.27/fs/cifs/transport.c linux-2.4.27-cifs-1.20c/fs/cifs/transport.c --- linux-2.4.27/fs/cifs/transport.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.27-cifs-1.20c/fs/cifs/transport.c Wed Jul 14 00:25:05 2004 @@ -0,0 +1,434 @@ +/* + * fs/cifs/transport.c + * + * Copyright (C) International Business Machines Corp., 2002,2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" + +extern kmem_cache_t *cifs_mid_cachep; +extern kmem_cache_t *cifs_oplock_cachep; + +struct mid_q_entry * +AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) +{ + struct mid_q_entry *temp; + + if (ses == NULL) { + cERROR(1, ("Null session passed in to AllocMidQEntry ")); + return NULL; + } + if (ses->server == NULL) { + cERROR(1, ("Null TCP session in AllocMidQEntry")); + return NULL; + } + + temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep, + SLAB_KERNEL); + if (temp == NULL) + return temp; + else { + memset(temp, 0, sizeof (struct mid_q_entry)); + temp->mid = smb_buffer->Mid; /* always LE */ + temp->pid = current->pid; + temp->command = smb_buffer->Command; + cFYI(1, ("For smb_command %d", temp->command)); + do_gettimeofday(&temp->when_sent); + temp->ses = ses; + temp->tsk = current; + } + + spin_lock(&GlobalMid_Lock); + list_add_tail(&temp->qhead, &ses->server->pending_mid_q); + atomic_inc(&midCount); + temp->midState = MID_REQUEST_ALLOCATED; + spin_unlock(&GlobalMid_Lock); + return temp; +} + +void +DeleteMidQEntry(struct mid_q_entry *midEntry) +{ + spin_lock(&GlobalMid_Lock); + midEntry->midState = MID_FREE; + list_del(&midEntry->qhead); + atomic_dec(&midCount); + spin_unlock(&GlobalMid_Lock); + cifs_buf_release(midEntry->resp_buf); + kmem_cache_free(cifs_mid_cachep, midEntry); +} + +struct oplock_q_entry * +AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon) +{ + struct oplock_q_entry *temp; + if ((pinode== NULL) || (tcon == NULL)) { + cERROR(1, ("Null parms passed to AllocOplockQEntry")); + return NULL; + } + temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep, + SLAB_KERNEL); + if (temp == NULL) + return temp; + else { + temp->pinode = pinode; + temp->tcon = tcon; + temp->netfid = fid; + spin_lock(&GlobalMid_Lock); + list_add_tail(&temp->qhead, &GlobalOplock_Q); + spin_unlock(&GlobalMid_Lock); + } + return temp; + +} + +void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry) +{ + spin_lock(&GlobalMid_Lock); + /* should we check if list empty first? */ + list_del(&oplockEntry->qhead); + spin_unlock(&GlobalMid_Lock); + kmem_cache_free(cifs_oplock_cachep, oplockEntry); +} + +int +smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, + unsigned int smb_buf_length, struct sockaddr *sin) +{ + int rc = 0; + int i = 0; + struct msghdr smb_msg; + struct iovec iov; + mm_segment_t temp_fs; + + if(ssocket == NULL) + return -ENOTSOCK; /* BB eventually add reconnect code here */ + iov.iov_base = smb_buffer; + iov.iov_len = smb_buf_length + 4; + + smb_msg.msg_name = sin; + smb_msg.msg_namelen = sizeof (struct sockaddr); + smb_msg.msg_iov = &iov; + smb_msg.msg_iovlen = 1; + smb_msg.msg_control = NULL; + smb_msg.msg_controllen = 0; + smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ + + /* smb header is converted in header_assemble. bcc and rest of SMB word + area, and byte area if necessary, is converted to littleendian in + cifssmb.c and RFC1001 len is converted to bigendian in smb_send + Flags2 is converted in SendReceive */ + + smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); + cFYI(1, ("Sending smb of length %d ", smb_buf_length)); + dump_smb(smb_buffer, smb_buf_length + 4); + + temp_fs = get_fs(); /* we must turn off socket api parm checking */ + set_fs(get_ds()); + while(iov.iov_len > 0) { + rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4); + if ((rc == -ENOSPC) || (rc == -EAGAIN)) { + i++; + if(i > 60) { + cERROR(1, + ("sends on sock %p stuck for 30 seconds", + ssocket)); + rc = -EAGAIN; + break; + } + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/2); + continue; + } + if (rc < 0) + break; + iov.iov_base += rc; + iov.iov_len -= rc; + } + set_fs(temp_fs); + + if (rc < 0) { + cERROR(1,("Error %d sending data on socket to server.", rc)); + } else { + rc = 0; + } + + return rc; +} + +int +SendReceive(const unsigned int xid, struct cifsSesInfo *ses, + struct smb_hdr *in_buf, struct smb_hdr *out_buf, + int *pbytes_returned, const int long_op) +{ + int rc = 0; + unsigned int receive_len; + long timeout; + struct mid_q_entry *midQ; + + if (ses == NULL) { + cERROR(1,("Null smb session")); + return -EIO; + } + if(ses->server == NULL) { + cERROR(1,("Null tcp session")); + return -EIO; + } + + /* Ensure that we do not send more than 50 overlapping requests + to the same server. We may make this configurable later or + use ses->maxReq */ + if(long_op == -1) { + /* oplock breaks must not be held up */ + atomic_inc(&ses->server->inFlight); + } else { + spin_lock(&GlobalMid_Lock); + while(1) { + if(atomic_read(&ses->server->inFlight) >= CIFS_MAX_REQ){ + spin_unlock(&GlobalMid_Lock); + wait_event(ses->server->request_q, + atomic_read(&ses->server->inFlight) + < CIFS_MAX_REQ); + spin_lock(&GlobalMid_Lock); + } else { + if(ses->server->tcpStatus == CifsExiting) { + spin_unlock(&GlobalMid_Lock); + return -ENOENT; + } + + /* can not count locking commands against total since + they are allowed to block on server */ + + if(long_op < 3) { + /* update # of requests on the wire to server */ + atomic_inc(&ses->server->inFlight); + } + spin_unlock(&GlobalMid_Lock); + break; + } + } + } + /* make sure that we sign in the same order that we send on this socket + and avoid races inside tcp sendmsg code that could cause corruption + of smb data */ + + down(&ses->server->tcpSem); + + if (ses->server->tcpStatus == CifsExiting) { + rc = -ENOENT; + goto out_unlock; + } else if (ses->server->tcpStatus == CifsNeedReconnect) { + cFYI(1,("tcp session dead - return to caller to retry")); + rc = -EAGAIN; + goto out_unlock; + } else if (ses->status != CifsGood) { + /* check if SMB session is bad because we are setting it up */ + if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && + (in_buf->Command != SMB_COM_NEGOTIATE)) { + rc = -EAGAIN; + goto out_unlock; + } /* else ok - we are setting up session */ + } + midQ = AllocMidQEntry(in_buf, ses); + if (midQ == NULL) { + up(&ses->server->tcpSem); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + return -ENOMEM; + } + + if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) { + up(&ses->server->tcpSem); + cERROR(1, + ("Illegal length, greater than maximum frame, %d ", + in_buf->smb_buf_length)); + DeleteMidQEntry(midQ); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + return -EIO; + } + + if (in_buf->smb_buf_length > 12) + in_buf->Flags2 = cpu_to_le16(in_buf->Flags2); + + rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); + + midQ->midState = MID_REQUEST_SUBMITTED; + rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, + (struct sockaddr *) &(ses->server->addr.sockAddr)); + if(rc < 0) { + DeleteMidQEntry(midQ); + up(&ses->server->tcpSem); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + return rc; + } else + up(&ses->server->tcpSem); + if (long_op == -1) + goto cifs_no_response_exit; + else if (long_op == 2) /* writes past end of file can take looooong time */ + timeout = 300 * HZ; + else if (long_op == 1) + timeout = 45 * HZ; /* should be greater than + servers oplock break timeout (about 43 seconds) */ + else if (long_op > 2) { + timeout = MAX_SCHEDULE_TIMEOUT; + } else + timeout = 15 * HZ; + /* wait for 15 seconds or until woken up due to response arriving or + due to last connection to this server being unmounted */ + if (signal_pending(current)) { + /* if signal pending do not hold up user for full smb timeout + but we still give response a change to complete */ + if(midQ->midState & MID_REQUEST_SUBMITTED) { + set_current_state(TASK_UNINTERRUPTIBLE); + timeout = sleep_on_timeout(&ses->server->response_q,2 * HZ); + } + } else { /* using normal timeout */ + /* timeout = wait_event_interruptible_timeout(ses->server->response_q, + (midQ->midState & MID_RESPONSE_RECEIVED) || + ((ses->server->tcpStatus != CifsGood) && + (ses->server->tcpStatus != CifsNew)), + timeout); */ + /* Can not allow user interrupts- wreaks havoc with performance */ + if(midQ->midState & MID_REQUEST_SUBMITTED) { + set_current_state(TASK_UNINTERRUPTIBLE); + timeout = sleep_on_timeout(&ses->server->response_q,timeout); + } + } + + spin_lock(&GlobalMid_Lock); + if (midQ->resp_buf) { + spin_unlock(&GlobalMid_Lock); + receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); + } else { + cERROR(1,("No response buffer")); + if(midQ->midState == MID_REQUEST_SUBMITTED) { + if(ses->server->tcpStatus == CifsExiting) + rc = -EHOSTDOWN; + else { + ses->server->tcpStatus = CifsNeedReconnect; + midQ->midState = MID_RETRY_NEEDED; + } + } + + if (rc != -EHOSTDOWN) { + if(midQ->midState == MID_RETRY_NEEDED) { + rc = -EAGAIN; + cFYI(1,("marking request for retry")); + } else { + rc = -EIO; + } + } + spin_unlock(&GlobalMid_Lock); + DeleteMidQEntry(midQ); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + return rc; + } + + if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) { + cERROR(1, + ("Frame too large received. Length: %d Xid: %d", + receive_len, xid)); + rc = -EIO; + } else { /* rcvd frame is ok */ + + if (midQ->resp_buf && out_buf + && (midQ->midState == MID_RESPONSE_RECEIVED)) { + memcpy(out_buf, midQ->resp_buf, + receive_len + + 4 /* include 4 byte RFC1001 header */ ); + + dump_smb(out_buf, 92); + /* convert the length into a more usable form */ + out_buf->smb_buf_length = + be32_to_cpu(out_buf->smb_buf_length); + if((out_buf->smb_buf_length > 24) && + (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { + rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */ + if(rc) + cFYI(1,("Unexpected signature received from server")); + } + + if (out_buf->smb_buf_length > 12) + out_buf->Flags2 = le16_to_cpu(out_buf->Flags2); + if (out_buf->smb_buf_length > 28) + out_buf->Pid = le16_to_cpu(out_buf->Pid); + if (out_buf->smb_buf_length > 28) + out_buf->PidHigh = + le16_to_cpu(out_buf->PidHigh); + + *pbytes_returned = out_buf->smb_buf_length; + + /* BB special case reconnect tid and reconnect uid here? */ + rc = map_smb_to_linux_error(out_buf); + + /* convert ByteCount if necessary */ + if (receive_len >= + sizeof (struct smb_hdr) - + 4 /* do not count RFC1001 header */ + + (2 * out_buf->WordCount) + 2 /* bcc */ ) + BCC(out_buf) = le16_to_cpu(BCC(out_buf)); + } else { + rc = -EIO; + cFYI(1,("Bad MID state? ")); + } + } +cifs_no_response_exit: + DeleteMidQEntry(midQ); + + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + + return rc; + +out_unlock: + up(&ses->server->tcpSem); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + + return rc; +} diff -urN linux-2.4.27/fs/nls/Config.in linux-2.4.27-cifs-1.20c/fs/nls/Config.in --- linux-2.4.27/fs/nls/Config.in Wed Jul 30 09:18:55 2003 +++ linux-2.4.27-cifs-1.20c/fs/nls/Config.in Fri Aug 13 18:07:33 2004 @@ -11,6 +11,7 @@ # msdos and Joliet want NLS if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \ + -o "$CONFIG_CIFS" != "n" \ -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \ -o "$CONFIG_SMB_NLS" = "y" -o "$CONFIG_JFS_FS" != "n" \ -o "$CONFIG_BEFS_FS" != "n" -o "$CONFIG_HFSPLUS_FS" != "n" ]; then