/* * Copyright (C) 2006-2008 Alfresco Software Limited. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * As a special exception to the terms and conditions of version 2.0 of * the GPL, you may redistribute this Program in connection with Free/Libre * and Open Source Software ("FLOSS") applications as described in Alfresco's * FLOSS exception. You should have recieved a copy of the text describing * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ package org.alfresco.jlan.smb.server; import java.io.IOException; import org.alfresco.jlan.debug.Debug; import org.alfresco.jlan.netbios.RFCNetBIOSProtocol; import org.alfresco.jlan.server.auth.ICifsAuthenticator; import org.alfresco.jlan.server.auth.InvalidUserException; import org.alfresco.jlan.server.core.InvalidDeviceInterfaceException; import org.alfresco.jlan.server.core.ShareType; import org.alfresco.jlan.server.core.SharedDevice; import org.alfresco.jlan.server.filesys.AccessDeniedException; import org.alfresco.jlan.server.filesys.AccessMode; import org.alfresco.jlan.server.filesys.DirectoryNotEmptyException; import org.alfresco.jlan.server.filesys.DiskDeviceContext; import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.FileAccess; import org.alfresco.jlan.server.filesys.FileAction; import org.alfresco.jlan.server.filesys.FileAttribute; import org.alfresco.jlan.server.filesys.FileExistsException; import org.alfresco.jlan.server.filesys.FileInfo; import org.alfresco.jlan.server.filesys.FileName; import org.alfresco.jlan.server.filesys.FileOpenParams; import org.alfresco.jlan.server.filesys.FileSharingException; import org.alfresco.jlan.server.filesys.FileStatus; import org.alfresco.jlan.server.filesys.NetworkFile; import org.alfresco.jlan.server.filesys.SearchContext; import org.alfresco.jlan.server.filesys.SrvDiskInfo; import org.alfresco.jlan.server.filesys.TooManyConnectionsException; import org.alfresco.jlan.server.filesys.TooManyFilesException; import org.alfresco.jlan.server.filesys.TreeConnection; import org.alfresco.jlan.server.filesys.VolumeInfo; import org.alfresco.jlan.smb.Capability; import org.alfresco.jlan.smb.DataType; import org.alfresco.jlan.smb.InvalidUNCPathException; import org.alfresco.jlan.smb.PCShare; import org.alfresco.jlan.smb.PacketType; import org.alfresco.jlan.smb.SMBDate; import org.alfresco.jlan.smb.SMBStatus; import org.alfresco.jlan.util.DataPacker; import org.alfresco.jlan.util.WildCard; /** * Core SMB protocol handler class. * * @author gkspencer */ class CoreProtocolHandler extends ProtocolHandler { // Special resume ids for '.' and '..' pseudo directories private static final int RESUME_START = 0x00008003; private static final int RESUME_DOT = 0x00008002; private static final int RESUME_DOTDOT = 0x00008001; // Maximum value that can be stored in a parameter word private static final int MaxWordValue = 0x0000FFFF; // File attribute mask, for standard attributes only protected static final int StandardAttributes = 0x3F; // Search information per file length protected static final int SearchInfoLen = 43; // Invalid file name characters private static final String InvalidFileNameChars = "\"/:|<>*?"; private static final String InvalidFileNameCharsSearch = "\"/:|<>"; /** * Create a new core SMB protocol handler. */ protected CoreProtocolHandler() { } /** * Class constructor * * @param sess SMBSrvSession */ protected CoreProtocolHandler(SMBSrvSession sess) { super(sess); } /** * Return the protocol name * * @return String */ public String getName() { return "Core Protocol"; } /** * Map a Java exception class to an SMB error code, and return an error response to the caller. * * @param ex java.lang.Exception */ protected final void MapExceptionToSMBError(Exception ex) { } /** * Check if a path contains any illegal characters, for file/create open/create/rename/get info * * @param path String * @return boolean */ protected boolean isValidPath(String path) { // Scan the path for invalid path characters for ( int i = 0; i < InvalidFileNameChars.length(); i++) { if ( path.indexOf( InvalidFileNameChars.charAt( i)) != -1) return false; } // Path looks valid return true; } /** * Check if a path contains any illegal characters, for a folder search * * @param path String * @return boolean */ protected boolean isValidSearchPath(String path) { // Scan the path for invalid path characters for ( int i = 0; i < InvalidFileNameCharsSearch.length(); i++) { if ( path.indexOf( InvalidFileNameCharsSearch.charAt( i)) != -1) return false; } // Path looks valid return true; } /** * Pack file information for a search into the specified buffer. * * @param buf byte[] Buffer to store data. * @param bufPos int Position to start storing data. * @param searchStr Search context string. * @param resumeId int Resume id * @param searchId Search context id * @param info File data to be packed. * @return int Next available buffer position. */ protected final int packSearchInfo(byte[] buf, int bufPos, String searchStr, int resumeId, int searchId, FileInfo info) { // Pack the resume key CoreResumeKey.putResumeKey(buf, bufPos, searchStr, resumeId + (searchId << 16)); bufPos += CoreResumeKey.LENGTH; // Pack the file information buf[bufPos++] = (byte) (info.getFileAttributes() & StandardAttributes); SMBDate dateTime = new SMBDate(info.getModifyDateTime()); if ( dateTime != null) { DataPacker.putIntelShort(dateTime.asSMBTime(), buf, bufPos); DataPacker.putIntelShort(dateTime.asSMBDate(), buf, bufPos + 2); } else { DataPacker.putIntelShort(0, buf, bufPos); DataPacker.putIntelShort(0, buf, bufPos + 2); } bufPos += 4; DataPacker.putIntelInt((int) info.getSize(), buf, bufPos); bufPos += 4; StringBuilder str = new StringBuilder(); str.append(info.getFileName()); while (str.length() < 13) str.append('\0'); if ( str.length() > 12) str.setLength(12); DataPacker.putString( str.toString().toUpperCase(), buf, bufPos, true); bufPos += 13; // Return the new buffer position return bufPos; } /** * Check if the specified path exists, and is a directory. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception SMBSrvException The exception description. */ protected void procCheckDirectory(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid check directory request if ( smbPkt.checkPacketIsValid(0, 2) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the data bytes position and length int dataPos = smbPkt.getByteOffset(); int dataLen = smbPkt.getByteCount(); byte[] buf = smbPkt.getBuffer(); // Extract the directory name String dirName = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, smbPkt.isUnicode()); if ( dirName == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("Directory Check [" + treeId + "] name=" + dirName); // Access the disk interface and check for the directory try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Check that the specified path exists, and it is a directory if ( disk.fileExists(m_sess, conn, dirName) == FileStatus.DirectoryExists) { // The path exists and is a directory, build the valid path response. smbPkt.setParameterCount(0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } else { // The path does not exist, or is not a directory. // // DOS clients depend on the 'Directory Invalid' (SMB_ERR_BAD_PATH) message being // returned. m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSDirectoryInvalid, SMBStatus.ErrDos); } } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { // Failed to delete the directory m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSDirectoryInvalid, SMBStatus.ErrDos); return; } } /** * Close a file that has been opened on the server. * * @param smbPkt Response SMB packet. * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procCloseFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid file close request if ( smbPkt.checkPacketIsValid(3, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the file id from the request int fid = smbPkt.getParameter(0); int ftime = smbPkt.getParameter(1); int fdate = smbPkt.getParameter(2); NetworkFile netFile = conn.findFile(fid); if ( netFile == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("File close [" + treeId + "] fid=" + fid); // Close the file try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Close the file // // The disk interface may be null if the file is a named pipe file if ( disk != null) disk.closeFile(m_sess, conn, netFile); // Indicate that the file has been closed netFile.setClosed(true); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { } // Remove the file from the connections list of open files conn.removeFile(fid, getSession()); // Build the close file response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Create a new directory. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procCreateDirectory(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid create directory request if ( smbPkt.checkPacketIsValid(0, 2) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasWriteAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the data bytes position and length int dataPos = smbPkt.getByteOffset(); int dataLen = smbPkt.getByteCount(); byte[] buf = smbPkt.getBuffer(); // Extract the directory name String dirName = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, smbPkt.isUnicode()); if ( dirName == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Check if the file name is valid if ( isValidPath( dirName) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTObjectNameInvalid, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("Directory Create [" + treeId + "] name=" + dirName); // Access the disk interface and create the new directory try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Directory creation parameters FileOpenParams params = new FileOpenParams(dirName, FileAction.CreateNotExist, AccessMode.ReadWrite, FileAttribute.NTDirectory, smbPkt.getProcessIdFull()); // Create the new directory disk.createDirectory(m_sess, conn, params); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (FileExistsException ex) { // Failed to create the directory m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTObjectNameCollision, SMBStatus.DOSFileAlreadyExists, SMBStatus.ErrDos); return; } catch (AccessDeniedException ex) { // Not allowed to create directory m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTAccessDenied, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { // Failed to create the directory m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSDirectoryInvalid, SMBStatus.ErrDos); return; } // Build the create directory response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Create a new file on the server. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procCreateFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid file create request if ( smbPkt.checkPacketIsValid(3, 2) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasWriteAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the data bytes position and length int dataPos = smbPkt.getByteOffset(); int dataLen = smbPkt.getByteCount(); byte[] buf = smbPkt.getBuffer(); // Extract the file name String fileName = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, smbPkt.isUnicode()); if ( fileName == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Check if the file name is valid if ( isValidPath( fileName) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTObjectNameInvalid, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Get the required file attributes for the new file int attr = smbPkt.getParameter(0); // Create the file parameters to be passed to the disk interface FileOpenParams params = new FileOpenParams(fileName, FileAction.CreateNotExist, AccessMode.ReadWrite, attr, smbPkt.getProcessIdFull()); // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("File Create [" + treeId + "] params=" + params); // Access the disk interface and create the new file int fid; NetworkFile netFile = null; try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Create the new file netFile = disk.createFile(m_sess, conn, params); // Add the file to the list of open files for this tree connection fid = conn.addFile(netFile, getSession()); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (TooManyFilesException ex) { // Too many files are open on this connection, cannot open any more files. m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSTooManyOpenFiles, SMBStatus.ErrDos); return; } catch (FileExistsException ex) { // File with the requested name already exists m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSFileAlreadyExists, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { // Failed to open the file m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos); return; } // Build the create file response smbPkt.setParameterCount(1); smbPkt.setParameter(0, fid); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Create a temporary file. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.server.SMBSrvException The exception description. */ protected void procCreateTemporaryFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { } /** * Delete a directory. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procDeleteDirectory(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid delete directory request if ( smbPkt.checkPacketIsValid(0, 2) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasWriteAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the data bytes position and length int dataPos = smbPkt.getByteOffset(); int dataLen = smbPkt.getByteCount(); byte[] buf = smbPkt.getBuffer(); // Extract the directory name String dirName = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, smbPkt.isUnicode()); if ( dirName == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Check if the file name is valid if ( isValidPath( dirName) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTObjectNameInvalid, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("Directory Delete [" + treeId + "] name=" + dirName); // Access the disk interface and delete the directory try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Delete the directory disk.deleteDirectory(m_sess, conn, dirName); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (AccessDeniedException ex) { // Not allowed to delete the directory m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } catch (DirectoryNotEmptyException ex) { // Directory not empty m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSDirectoryNotEmpty, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { // Failed to delete the directory m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSDirectoryInvalid, SMBStatus.ErrDos); return; } // Build the delete directory response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Delete a file. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procDeleteFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid file delete request if ( smbPkt.checkPacketIsValid(1, 2) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasWriteAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the data bytes position and length int dataPos = smbPkt.getByteOffset(); int dataLen = smbPkt.getByteCount(); byte[] buf = smbPkt.getBuffer(); // Extract the file name String fileName = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, smbPkt.isUnicode()); if ( fileName == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Check if the file name is valid if ( isValidPath( fileName) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTObjectNameInvalid, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("File Delete [" + treeId + "] name=" + fileName); // Access the disk interface and delete the file(s) int fid; NetworkFile netFile = null; try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Delete file(s) disk.deleteFile(m_sess, conn, fileName); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { // Failed to open the file m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos); return; } // Build the delete file response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Get disk attributes processing. * * @param smbPkt Response SMB packet. * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procDiskAttributes(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_INFO)) m_sess.debugPrintln("Get disk attributes"); // Parameter and byte count should be zero if ( smbPkt.getParameterCount() != 0 && smbPkt.getByteCount() != 0) { // Send an error response m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree connection details int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the disk interface from the shared device DiskInterface disk = null; DiskDeviceContext diskCtx = null; try { disk = (DiskInterface) conn.getSharedDevice().getInterface(); diskCtx = (DiskDeviceContext) conn.getContext(); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Create a disk information object and ask the disk interface to fill in the details SrvDiskInfo diskInfo = getDiskInformation(disk, diskCtx); // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_INFO)) m_sess.debugPrintln(" Disk info - total=" + diskInfo.getTotalUnits() + ", free=" + diskInfo.getFreeUnits() + ", blocksPerUnit=" + diskInfo.getBlocksPerAllocationUnit() + ", blockSize=" + diskInfo.getBlockSize()); // Check if the disk size information needs scaling to fit into 16bit values long totUnits = diskInfo.getTotalUnits(); long freeUnits = diskInfo.getFreeUnits(); int blocksUnit = diskInfo.getBlocksPerAllocationUnit(); while (totUnits > MaxWordValue && blocksUnit <= MaxWordValue) { // Increase the blocks per unit and decrease the total/free units blocksUnit *= 2; totUnits = totUnits / 2L; freeUnits = freeUnits / 2L; } // Check if the total/free units fit into a 16bit value if ( totUnits > MaxWordValue || blocksUnit > MaxWordValue) { // Just use dummy values, cannot fit the disk size into 16bits totUnits = MaxWordValue; if ( freeUnits > MaxWordValue) freeUnits = MaxWordValue / 2; if ( blocksUnit > MaxWordValue) blocksUnit = MaxWordValue; } // Build the reply SMB smbPkt.setParameterCount(5); smbPkt.setParameter(0, (int) totUnits); smbPkt.setParameter(1, blocksUnit); smbPkt.setParameter(2, diskInfo.getBlockSize()); smbPkt.setParameter(3, (int) freeUnits); smbPkt.setParameter(4, 0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Echo packet request. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procEcho(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid echo request if ( smbPkt.checkPacketIsValid(1, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the echo count from the request int echoCnt = smbPkt.getParameter(0); // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_ECHO)) m_sess.debugPrintln("Echo - Count = " + echoCnt); // Loop until all echo packets have been sent int echoSeq = 1; while (echoCnt > 0) { // Set the echo response sequence number smbPkt.setParameter(0, echoSeq++); // Echo the received packet m_sess.sendResponseSMB(smbPkt); echoCnt--; // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_ECHO)) m_sess.debugPrintln("Echo Packet, Seq = " + echoSeq); } } /** * Flush the specified file. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procFlushFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid file flush request if ( smbPkt.checkPacketIsValid(1, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasWriteAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the file id from the request int fid = smbPkt.getParameter(0); NetworkFile netFile = conn.findFile(fid); if ( netFile == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("File Flush [" + netFile.getFileId() + "]"); // Flush the file try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Flush the file disk.flushFile(m_sess, conn, netFile); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { // Debug if ( Debug.EnableError && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("File Flush Error [" + netFile.getFileId() + "] : " + ex.toString()); // Failed to read the file m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.HRDWriteFault, SMBStatus.ErrHrd); return; } // Send the flush response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); m_sess.sendResponseSMB(smbPkt); } /** * Get the file attributes for the specified file. * * @param smbPkt Response SMB packet. * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procGetFileAttributes(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid query file information request if ( smbPkt.checkPacketIsValid(0, 2) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the data bytes position and length int dataPos = smbPkt.getByteOffset(); int dataLen = smbPkt.getByteCount(); byte[] buf = smbPkt.getBuffer(); // Extract the file name String fileName = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, smbPkt.isUnicode()); if ( fileName == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("Get File Information [" + treeId + "] name=" + fileName); // Access the disk interface and get the file information try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Get the file information for the specified file/directory FileInfo finfo = disk.getFileInformation(m_sess, conn, fileName); if ( finfo != null) { // Mask the file attributes finfo.setFileAttributes(finfo.getFileAttributes() & StandardAttributes); // Check if the share is read-only, if so then force the read-only flag for the file if ( conn.getSharedDevice().isReadOnly() && finfo.isReadOnly() == false) { // Make sure the read-only attribute is set finfo.setFileAttributes(finfo.getFileAttributes() + FileAttribute.ReadOnly); } // Return the file information smbPkt.setParameterCount(10); smbPkt.setParameter(0, finfo.getFileAttributes()); if ( finfo.getModifyDateTime() != 0L) { SMBDate dateTime = new SMBDate(finfo.getModifyDateTime()); smbPkt.setParameter(1, dateTime.asSMBTime()); smbPkt.setParameter(2, dateTime.asSMBDate()); } else { smbPkt.setParameter(1, 0); smbPkt.setParameter(2, 0); } smbPkt.setParameter(3, (int) finfo.getSize() & 0x0000FFFF); smbPkt.setParameter(4, (int) (finfo.getSize() & 0xFFFF0000) >> 16); for (int i = 5; i < 10; i++) smbPkt.setParameter(i, 0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); return; } } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { } // Failed to get the file information m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos); } /** * Get file information. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procGetFileInformation(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid query file information2 request if ( smbPkt.checkPacketIsValid(1, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the file id from the request int fid = smbPkt.getParameter(0); NetworkFile netFile = conn.findFile(fid); if ( netFile == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("Get File Information 2 [" + netFile.getFileId() + "]"); // Access the disk interface and get the file information try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Get the file information for the specified file/directory FileInfo finfo = disk.getFileInformation(m_sess, conn, netFile.getFullName()); if ( finfo != null) { // Mask the file attributes finfo.setFileAttributes(finfo.getFileAttributes() & StandardAttributes); // Check if the share is read-only, if so then force the read-only flag for the file if ( conn.getSharedDevice().isReadOnly() && finfo.isReadOnly() == false) { // Make sure the read-only attribute is set finfo.setFileAttributes(finfo.getFileAttributes() + FileAttribute.ReadOnly); } // Initialize the return packet, no data bytes smbPkt.setParameterCount(11); smbPkt.setByteCount(0); // Return the file information // // Creation date/time SMBDate dateTime = new SMBDate(0); if ( finfo.getCreationDateTime() != 0L) { dateTime.setTime(finfo.getCreationDateTime()); smbPkt.setParameter(0, dateTime.asSMBDate()); smbPkt.setParameter(1, dateTime.asSMBTime()); } else { smbPkt.setParameter(0, 0); smbPkt.setParameter(1, 0); } // Access date/time if ( finfo.getAccessDateTime() != 0L) { dateTime.setTime(finfo.getAccessDateTime()); smbPkt.setParameter(2, dateTime.asSMBDate()); smbPkt.setParameter(3, dateTime.asSMBTime()); } else { smbPkt.setParameter(2, 0); smbPkt.setParameter(3, 0); } // Modify date/time if ( finfo.getModifyDateTime() != 0L) { dateTime.setTime(finfo.getModifyDateTime()); smbPkt.setParameter(4, dateTime.asSMBDate()); smbPkt.setParameter(5, dateTime.asSMBTime()); } else { smbPkt.setParameter(4, 0); smbPkt.setParameter(5, 0); } // File data size smbPkt.setParameter(6, (int) finfo.getSize() & 0x0000FFFF); smbPkt.setParameter(7, (int) (finfo.getSize() & 0xFFFF0000) >> 16); // File allocation size smbPkt.setParameter(8, (int) finfo.getSize() & 0x0000FFFF); smbPkt.setParameter(9, (int) (finfo.getSize() & 0xFFFF0000) >> 16); // File attributes smbPkt.setParameter(10, finfo.getFileAttributes()); // Send the response packet m_sess.sendResponseSMB(smbPkt); return; } } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { } // Failed to get the file information m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos); } /** * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.server.SMBSrvException The exception description. */ protected void procLockFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid lock file request if ( smbPkt.checkPacketIsValid(5, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the file id from the request int fid = smbPkt.getParameter(0); long lockcnt = smbPkt.getParameterLong(1); long lockoff = smbPkt.getParameterLong(3); NetworkFile netFile = conn.findFile(fid); if ( netFile == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO)) m_sess.debugPrintln("File Lock [" + netFile.getFileId() + "] : Offset=" + lockoff + " ,Count=" + lockcnt); // ***** Always return a success status, simulated locking **** // // Build the lock file response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Open a file on the server. * * @param smbPkt Response SMB packet. * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procOpenFile(SMBSrvPacket smbPkt) throws IOException, SMBSrvException { // Check that the received packet looks like a valid file open request if ( smbPkt.checkPacketIsValid(2, 2) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the data bytes position and length int dataPos = smbPkt.getByteOffset(); int dataLen = smbPkt.getByteCount(); byte[] buf = smbPkt.getBuffer(); // Extract the file name String fileName = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, smbPkt.isUnicode()); if ( fileName == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Get the required access mode and the file attributes int mode = smbPkt.getParameter(0); int attr = smbPkt.getParameter(1); // Create the file open parameters to be passed to the disk interface FileOpenParams params = new FileOpenParams(fileName, mode, AccessMode.ReadWrite, attr, smbPkt.getProcessIdFull()); // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("File Open [" + treeId + "] params=" + params); // Access the disk interface and open the requested file int fid; NetworkFile netFile = null; try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Open the requested file netFile = disk.openFile(m_sess, conn, params); // Add the file to the list of open files for this tree connection fid = conn.addFile(netFile, getSession()); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (TooManyFilesException ex) { // Too many files are open on this connection, cannot open any more files. m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSTooManyOpenFiles, SMBStatus.ErrDos); return; } catch (AccessDeniedException ex) { // File is not accessible, or file is actually a directory m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } catch (FileSharingException ex) { // Return a sharing violation error m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSFileSharingConflict, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { // Failed to open the file m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos); return; } // Build the open file response smbPkt.setParameterCount(7); smbPkt.setParameter(0, fid); smbPkt.setParameter(1, 0); // file attributes if ( netFile.hasModifyDate()) { smbPkt.setParameterLong(2, (int) (netFile.getModifyDate() / 1000L)); } else smbPkt.setParameterLong(2, 0); smbPkt.setParameterLong(4, netFile.getFileSizeInt()); // file size smbPkt.setParameter(6, netFile.getGrantedAccess()); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Process exit, close all open files. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.server.SMBSrvException The exception description. */ protected void procProcessExit(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid process exit request if ( smbPkt.checkPacketIsValid(0, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("Process Exit - Open files = " + conn.openFileCount()); // Close all open files if ( conn.openFileCount() > 0) { // Close all files on the connection conn.closeConnection(getSession()); } // Build the process exit response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Read from a file that has been opened on the server. * * @param smbPkt Response SMB packet. * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procReadFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid file read request if ( smbPkt.checkPacketIsValid(5, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the file id from the request int fid = smbPkt.getParameter(0); int reqcnt = smbPkt.getParameter(1); int reqoff = smbPkt.getParameterLong(2); NetworkFile netFile = conn.findFile(fid); if ( netFile == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO)) m_sess.debugPrintln("File Read [" + netFile.getFileId() + "] : Size=" + reqcnt + " ,Pos=" + reqoff); // Read data from the file SMBSrvPacket respPkt = smbPkt; byte[] buf = respPkt.getBuffer(); int rdlen = 0; try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Calculate the buffer size required for the response int dataOff = smbPkt.getByteOffset() + 3; if ( m_sess.hasClientCapability(Capability.LargeRead) == false) { // Make sure the requested count is not larger than the client maximum buffer size int maxClientCnt = m_sess.getClientMaximumBufferSize() - dataOff; if ( reqcnt > maxClientCnt) reqcnt = maxClientCnt; // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO)) m_sess.debugPrintln("File Read [" + netFile.getFileId() + "] Limited to " + reqcnt); } // Check if the requested data will fit into the current packet if ( reqcnt > ( buf.length - dataOff)) { // Allocate a larger packet for the response respPkt = m_sess.getPacketPool().allocatePacket( reqcnt + dataOff, smbPkt); // Switch to the response buffer buf = respPkt.getBuffer(); } // Read from the file rdlen = disk.readFile(m_sess, conn, netFile, buf, respPkt.getByteOffset() + 3, reqcnt, reqoff); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { // Debug if ( Debug.EnableError && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO)) m_sess.debugPrintln("File Read Error [" + netFile.getFileId() + "] : " + ex.toString()); // Failed to read the file m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.HRDReadFault, SMBStatus.ErrHrd); return; } // Return the data block int bytOff = respPkt.getByteOffset(); buf[bytOff] = (byte) DataType.DataBlock; DataPacker.putIntelShort(rdlen, buf, bytOff + 1); smbPkt.setByteCount(rdlen + 3); // data type + 16bit length smbPkt.setParameter(0, rdlen); smbPkt.setParameter(1, 0); smbPkt.setParameter(2, 0); smbPkt.setParameter(3, 0); smbPkt.setParameter(4, 0); // Send the read response m_sess.sendResponseSMB( respPkt); } /** * Rename a file. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procRenameFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid rename file request if ( smbPkt.checkPacketIsValid(1, 4) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasWriteAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the data bytes position and length int dataPos = smbPkt.getByteOffset(); int dataLen = smbPkt.getByteCount(); byte[] buf = smbPkt.getBuffer(); // Extract the old file name boolean isUni = smbPkt.isUnicode(); String oldName = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, isUni); if ( oldName == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Update the data position if ( isUni) { int len = (oldName.length() * 2) + 2; dataPos = DataPacker.wordAlign(dataPos + 1) + len; dataLen -= len; } else { dataPos += oldName.length() + 2; // string length + null + data type dataLen -= oldName.length() + 2; } // Extract the new file name String newName = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, isUni); if ( newName == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("File Rename [" + treeId + "] old name=" + oldName + ", new name=" + newName); // Access the disk interface and rename the requested file int fid; NetworkFile netFile = null; try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Rename the requested file disk.renameFile(m_sess, conn, oldName, newName); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { // Failed to open the file m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos); return; } // Build the rename file response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Start/continue a directory search operation. * * @param smbPkt Response SMB packet. * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected final void procSearch(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid search request if ( smbPkt.checkPacketIsValid(2, 5) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree connection details int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the maximum number of entries to return and the search file attributes int maxFiles = smbPkt.getParameter(0); int srchAttr = smbPkt.getParameter(1); // Check if this is a volume label request if ( (srchAttr & FileAttribute.Volume) != 0) { // Process the volume label request procSearchVolumeLabel(smbPkt); return; } // Get the data bytes position and length int dataPos = smbPkt.getByteOffset(); int dataLen = smbPkt.getByteCount(); byte[] buf = smbPkt.getBuffer(); // Extract the search file name String srchPath = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, smbPkt.isUnicode()); if ( srchPath == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidFunc, SMBStatus.ErrDos); return; } // Update the received data position dataPos += srchPath.length() + 2; dataLen -= srchPath.length() + 2; int resumeLen = 0; if ( buf[dataPos++] == DataType.VariableBlock) { // Extract the resume key length resumeLen = DataPacker.getIntelShort(buf, dataPos); // Adjust remaining the data length and position dataLen -= 3; // block type + resume key length short dataPos += 2; // resume key length short // Check that we received enough data if ( resumeLen > dataLen) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } } // Access the shared devices disk interface SearchContext ctx = null; DiskInterface disk = null; try { disk = (DiskInterface) conn.getSharedDevice().getInterface(); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Check if this is the start of a new search byte[] resumeKey = null; int searchId = -1; // Default resume point is at the start of the directory, at the '.' directory if // directories are being returned. int resumeId = RESUME_START; if ( resumeLen == 0 && srchPath.length() > 0) { // Allocate a search slot for the new search searchId = vc.allocateSearchSlot(); if ( searchId == -1) { // Try and find any 'leaked' searches, ie. searches that have been started but not // closed. // // Windows Explorer seems to leak searches after a new folder has been created, a // search for '????????.???' is started but never continued. int idx = 0; ctx = vc.getSearchContext(idx); while (ctx != null && searchId == -1) { // Check if the current search context looks like a leaked search. if ( ctx.getSearchString().compareTo("????????.???") == 0) { // Debug if ( Debug.EnableWarn && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH)) m_sess.debugPrintln("Release leaked search [" + idx + "]"); // Deallocate the search context vc.deallocateSearchSlot(idx); // Allocate the slot for the new search searchId = vc.allocateSearchSlot(); } else { // Update the search index and get the next search context ctx = vc.getSearchContext(++idx); } } // Check if we freed up a search slot if ( searchId == -1) { // Failed to allocate a slot for the new search m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVNoResourcesAvailable, SMBStatus.ErrSrv); return; } } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH)) m_sess.debugPrintln("Start search [" + searchId + "] - " + srchPath + ", attr=0x" + Integer.toHexString(srchAttr) + ", maxFiles=" + maxFiles); // Start a new search ctx = disk.startSearch(m_sess, conn, srchPath, srchAttr); if ( ctx != null) { // Store details of the search in the context ctx.setTreeId(treeId); ctx.setMaximumFiles(maxFiles); } // Save the search context vc.setSearchContext(searchId, ctx); } else { // Take a copy of the resume key resumeKey = new byte[CoreResumeKey.LENGTH]; CoreResumeKey.getResumeKey(buf, dataPos, resumeKey); // Get the search context slot id from the resume key, and get the search context. int id = CoreResumeKey.getServerArea(resumeKey, 0); searchId = (id & 0xFFFF0000) >> 16; ctx = vc.getSearchContext(searchId); // Check if the search context is valid if ( ctx == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Get the resume id from the resume key resumeId = id & 0x0000FFFF; // Restart the search at the resume point, check if the resume point is already set, ie. // we are just continuing the search. if ( resumeId < RESUME_DOTDOT && ctx.getResumeId() != resumeId) { // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH)) m_sess.debugPrintln("Search resume at " + resumeId); // Restart the search at the specified point if ( ctx.restartAt(resumeId) == false) { // Debug if ( Debug.EnableError && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH)) m_sess.debugPrintln("Search restart failed"); // Failed to restart the search m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSNoMoreFiles, SMBStatus.ErrDos); // Release the search context vc.deallocateSearchSlot(searchId); return; } } } // Check if the search context is valid if ( ctx == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Check that the search context and tree connection match if ( ctx.getTreeId() != treeId) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv); return; } // Check if this is a wildcard search boolean wildcardSearch = WildCard.containsWildcards( srchPath); // Calculate the response packet length required SMBSrvPacket respPkt = smbPkt; if ( wildcardSearch == true) { // Allocate a response packet large enough to hold the maximum requested file info records int pktSize = SMBSrvPacket.calculateHeaderLength( 1) + ( maxFiles * SearchInfoLen); respPkt = m_sess.getPacketPool().allocatePacket( pktSize, smbPkt); // Switch to using the new packet buffer buf = respPkt.getBuffer(); } // Start building the search response packet respPkt.setParameterCount(1); int bufPos = respPkt.getByteOffset(); buf[bufPos] = (byte) DataType.VariableBlock; bufPos += 3; // save two bytes for the actual block length int fileCnt = 0; // Check if this is the start of a wildcard search and includes directories if ( (srchAttr & FileAttribute.Directory) != 0 && resumeId >= RESUME_DOTDOT && wildcardSearch == true) { // The first entries in the search should be the '.' and '..' entries for the // current/parent directories. // // Remove the file name from the search path, and get the file information for the // search directory. String workDir = FileName.removeFileName(srchPath); FileInfo dirInfo = disk.getFileInformation(m_sess, conn, workDir); // Check if we have valid information for the working directory if ( dirInfo != null) dirInfo = new FileInfo(".", 0, FileAttribute.Directory); // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH)) m_sess.debugPrintln("Search adding . and .. entries: " + dirInfo.toString()); // Reset the file name to '.' and pack the directory information if ( resumeId == RESUME_START) { // Pack the '.' file information dirInfo.setFileName("."); resumeId = RESUME_DOT; bufPos = packSearchInfo(buf, bufPos, ctx.getSearchString(), RESUME_DOT, searchId, dirInfo); // Update the file count fileCnt++; } // Reset the file name to '..' and pack the directory information if ( resumeId == RESUME_DOT) { // Pack the '..' file information dirInfo.setFileName(".."); bufPos = packSearchInfo(buf, bufPos, ctx.getSearchString(), RESUME_DOTDOT, searchId, dirInfo); // Update the file count fileCnt++; } } // Get files from the search and pack into the return packet FileInfo fileInfo = new FileInfo(); while (fileCnt < ctx.getMaximumFiles() && ctx.nextFileInfo(fileInfo) == true) { // Check for . files, ignore them. // // ** Should check for . and .. file names ** if ( fileInfo.getFileName().startsWith(".")) continue; // Get the resume id for the current file/directory resumeId = ctx.getResumeId(); // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH)) m_sess.debugPrintln("Search return file " + fileInfo.toString() + ", resumeId=" + resumeId); // Check if the share is read-only, if so then force the read-only flag for the file if ( conn.getSharedDevice().isReadOnly() && fileInfo.isReadOnly() == false) { // Make sure the read-only attribute is set fileInfo.setFileAttributes(fileInfo.getFileAttributes() + FileAttribute.ReadOnly); } // Pack the file information bufPos = packSearchInfo(buf, bufPos, ctx.getSearchString(), resumeId, searchId, fileInfo); // Update the file count, reset the current file information fileCnt++; fileInfo.resetInfo(); } // Check if any files were found if ( fileCnt == 0) { // Send a repsonse that indicates that the search has finished respPkt.setParameterCount(1); respPkt.setParameter(0, 0); respPkt.setByteCount(0); respPkt.setErrorClass(SMBStatus.ErrDos); respPkt.setErrorCode(SMBStatus.DOSNoMoreFiles); m_sess.sendResponseSMB( respPkt); // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH)) m_sess.debugPrintln("End search [" + searchId + "]"); // Release the search context vc.deallocateSearchSlot(searchId); } else { // Set the actual data length dataLen = bufPos - respPkt.getByteOffset(); respPkt.setByteCount(dataLen); // Set the variable data block length and returned file count parameter bufPos = respPkt.getByteOffset() + 1; DataPacker.putIntelShort(dataLen - 3, buf, bufPos); respPkt.setParameter(0, fileCnt); // Send the search response packet m_sess.sendResponseSMB( respPkt); // Check if the search string contains wildcards and this is the start of a new search, // if not then // release the search context now as the client will not continue the search. if ( fileCnt == 1 && resumeLen == 0 && WildCard.containsWildcards(srchPath) == false) { // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH)) m_sess.debugPrintln("End search [" + searchId + "] (Not wildcard)"); // Release the search context vc.deallocateSearchSlot(searchId); } } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_TXDATA)) m_sess.debugPrintln("Tx " + respPkt.getLength() + " bytes"); } /** * Process a search request that is for the volume label. * * @param smbPkt SMBSrvPacket */ protected final void procSearchVolumeLabel(SMBSrvPacket smbPkt) throws IOException, SMBSrvException { // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree connection details int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH)) m_sess.debugPrintln("Start Search - Volume Label"); // Access the shared devices disk interface DiskInterface disk = null; DiskDeviceContext diskCtx = null; try { disk = (DiskInterface) conn.getSharedDevice().getInterface(); diskCtx = (DiskDeviceContext) conn.getContext(); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Get the volume label VolumeInfo volInfo = diskCtx.getVolumeInformation(); String volLabel = ""; if ( volInfo != null) volLabel = volInfo.getVolumeLabel(); // Start building the search response packet smbPkt.setParameterCount(1); int bufPos = smbPkt.getByteOffset(); byte[] buf = smbPkt.getBuffer(); buf[bufPos++] = (byte) DataType.VariableBlock; // Calculate the data length int dataLen = CoreResumeKey.LENGTH + 22; DataPacker.putIntelShort(dataLen, buf, bufPos); bufPos += 2; // Pack the resume key CoreResumeKey.putResumeKey(buf, bufPos, volLabel, -1); bufPos += CoreResumeKey.LENGTH; // Pack the file information buf[bufPos++] = (byte) (FileAttribute.Volume & 0x00FF); // Zero the date/time and file length fields for (int i = 0; i < 8; i++) buf[bufPos++] = (byte) 0; StringBuffer volBuf = new StringBuffer(); volBuf.append(volLabel); while (volBuf.length() < 13) volBuf.append(" "); if ( volBuf.length() > 12) volBuf.setLength(12); bufPos = DataPacker.putString(volBuf.toString().toUpperCase(), buf, bufPos, true); // Set the actual data length dataLen = bufPos - smbPkt.getByteOffset(); smbPkt.setByteCount(dataLen); // Send the search response packet m_sess.sendResponseSMB(smbPkt); // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH)) m_sess.debugPrintln("Volume label for " + conn.toString() + " is " + volLabel); } /** * Seek to the specified file position within the open file. * * @param smbPkt SMBSrvPacket */ protected final void procSeekFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid file seek request if ( smbPkt.checkPacketIsValid(4, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the file id from the request int fid = smbPkt.getParameter(0); int seekMode = smbPkt.getParameter(1); long seekPos = (long) smbPkt.getParameterLong(2); NetworkFile netFile = conn.findFile(fid); if ( netFile == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("File Seek [" + netFile.getFileId() + "] : Mode = " + seekMode + ", Pos = " + seekPos); // Seek to the specified position within the file byte[] buf = smbPkt.getBuffer(); long pos = 0; try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Seek to the file position pos = disk.seekFile(m_sess, conn, netFile, seekPos, seekMode); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (IOException ex) { // Debug if ( Debug.EnableError && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("File Seek Error [" + netFile.getFileId() + "] : " + ex.toString()); // Failed to seek the file m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.HRDReadFault, SMBStatus.ErrHrd); return; } // Return the new file position smbPkt.setParameterCount(2); smbPkt.setParameterLong(0, (int) (pos & 0x0FFFFFFFFL)); smbPkt.setByteCount(0); // Send the seek response m_sess.sendResponseSMB( smbPkt); } /** * Process the SMB session setup request. * * @param smbPkt Response SMB packet. */ protected void procSessionSetup(SMBSrvPacket smbPkt) throws SMBSrvException, IOException, TooManyConnectionsException { // Return an access denied error, require a logon m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); } /** * Set the file attributes for a file. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procSetFileAttributes(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid set file attributes request if ( smbPkt.checkPacketIsValid(8, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasWriteAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the data bytes position and length int dataPos = smbPkt.getByteOffset(); int dataLen = smbPkt.getByteCount(); byte[] buf = smbPkt.getBuffer(); // Extract the file name String fileName = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, smbPkt.isUnicode()); if ( fileName == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Get the file attributes int fattr = smbPkt.getParameter(0); int setFlags = FileInfo.SetAttributes; FileInfo finfo = new FileInfo(fileName, 0, fattr); int fdate = smbPkt.getParameter(1); int ftime = smbPkt.getParameter(2); if ( fdate != 0 && ftime != 0) { finfo.setModifyDateTime(new SMBDate(fdate, ftime).getTime()); setFlags += FileInfo.SetModifyDate; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("Set File Attributes [" + treeId + "] name=" + fileName + ", attr=0x" + Integer.toHexString(fattr) + ", fdate=" + fdate + ", ftime=" + ftime); // Access the disk interface and set the file attributes try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Get the file information for the specified file/directory finfo.setFileInformationFlags(setFlags); disk.setFileInformation(m_sess, conn, fileName, finfo); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { } // Return the set file attributes response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Set file information. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procSetFileInformation(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid set file information2 request if ( smbPkt.checkPacketIsValid(7, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasWriteAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the file id from the request, and get the network file details. int fid = smbPkt.getParameter(0); NetworkFile netFile = conn.findFile(fid); if ( netFile == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos); return; } // Get the creation date/time from the request int setFlags = 0; FileInfo finfo = new FileInfo(netFile.getName(), 0, 0); int fdate = smbPkt.getParameter(1); int ftime = smbPkt.getParameter(2); if ( fdate != 0 && ftime != 0) { finfo.setCreationDateTime(new SMBDate(fdate, ftime).getTime()); setFlags += FileInfo.SetCreationDate; } // Get the last access date/time from the request fdate = smbPkt.getParameter(3); ftime = smbPkt.getParameter(4); if ( fdate != 0 && ftime != 0) { finfo.setAccessDateTime(new SMBDate(fdate, ftime).getTime()); setFlags += FileInfo.SetAccessDate; } // Get the last write date/time from the request fdate = smbPkt.getParameter(5); ftime = smbPkt.getParameter(6); if ( fdate != 0 && ftime != 0) { finfo.setModifyDateTime(new SMBDate(fdate, ftime).getTime()); setFlags += FileInfo.SetModifyDate; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILE)) m_sess.debugPrintln("Set File Information 2 [" + netFile.getFileId() + "] " + finfo.toString()); // Access the disk interface and set the file information try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Get the file information for the specified file/directory finfo.setFileInformationFlags(setFlags); disk.setFileInformation(m_sess, conn, netFile.getFullName(), finfo); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { } // Return the set file information response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Process the SMB tree connect request. * * @param smbPkt Response SMB packet. * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. * @exception org.alfresco.aifs.smb.TooManyConnectionsException Too many concurrent connections * on this session. */ protected void procTreeConnect(SMBSrvPacket smbPkt) throws SMBSrvException, TooManyConnectionsException, java.io.IOException { // Check that the received packet looks like a valid tree connect request if ( smbPkt.checkPacketIsValid(0, 4) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the data bytes position and length int dataPos = smbPkt.getByteOffset(); int dataLen = smbPkt.getByteCount(); byte[] buf = smbPkt.getBuffer(); // Extract the requested share name, as a UNC path boolean isUni = smbPkt.isUnicode(); String uncPath = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, isUni); if ( uncPath == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Extract the password string if ( isUni) { dataPos = DataPacker.wordAlign(dataPos + 1) + (uncPath.length() * 2) + 2; dataLen -= (uncPath.length() * 2) + 2; } else { dataPos += uncPath.length() + 2; dataLen -= uncPath.length() + 2; } String pwd = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, isUni); if ( pwd == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Extract the service type string if ( isUni) { dataPos = DataPacker.wordAlign(dataPos + 1) + (pwd.length() * 2) + 2; dataLen -= (pwd.length() * 2) + 2; } else { dataPos += pwd.length() + 2; dataLen -= pwd.length() + 2; } String service = DataPacker.getDataString(DataType.ASCII, buf, dataPos, dataLen, isUni); if ( service == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Convert the service type to a shared device type int servType = ShareType.ServiceAsType(service); if ( servType == ShareType.UNKNOWN) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_TREE)) m_sess.debugPrintln("Tree connect - " + uncPath + ", " + service); // Parse the requested share name PCShare share = null; try { share = new PCShare(uncPath); } catch (InvalidUNCPathException ex) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } // Map the IPC$ share to the admin pipe type if ( servType == ShareType.NAMEDPIPE && share.getShareName().compareTo("IPC$") == 0) servType = ShareType.ADMINPIPE; // Find the requested shared device SharedDevice shareDev = null; try { // Get/create the shared device shareDev = m_sess.getSMBServer().findShare(share.getNodeName(), share.getShareName(), servType, getSession(), true); } catch (InvalidUserException ex) { // Return a logon failure status m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } catch (Exception ex) { // Return a general status, bad network name m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVInvalidNetworkName, SMBStatus.ErrSrv); return; } // Check if the share is valid if ( shareDev == null || shareDev.getType() != servType) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Allocate a tree id for the new connection int treeId = vc.addConnection(shareDev); // Authenticate the share connection depending upon the security mode the server is running // under ICifsAuthenticator auth = getSession().getSMBServer().getCifsAuthenticator(); int filePerm = FileAccess.Writeable; if ( auth != null) { // Validate the share connection filePerm = auth.authenticateShareConnect(m_sess.getClientInformation(), shareDev, pwd, m_sess); if ( filePerm < 0) { // Invalid share connection request m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVNoAccessRights, SMBStatus.ErrSrv); return; } } // Set the file permission that this user has been granted for this share TreeConnection tree = vc.findConnection(treeId); tree.setPermission(filePerm); // Build the tree connect response smbPkt.setParameterCount(2); smbPkt.setParameter(0, buf.length - RFCNetBIOSProtocol.HEADER_LEN); smbPkt.setParameter(1, treeId); smbPkt.setByteCount(0); // Clear any chained request smbPkt.setAndXCommand(0xFF); m_sess.sendResponseSMB(smbPkt); // Inform the driver that a connection has been opened if ( tree.getInterface() != null) tree.getInterface().treeOpened(m_sess, tree); } /** * Process the SMB tree disconnect request. * * @param smbPkt Response SMB packet. * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procTreeDisconnect(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid tree disconnect request if ( smbPkt.checkPacketIsValid(0, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_TREE)) m_sess.debugPrintln("Tree disconnect - " + treeId + ", " + conn.toString()); // Remove the specified connection from the session vc.removeConnection(treeId, m_sess); // Check if this is the last tree connection on the virtual circuit and the virtual circuit is logged off if ( vc.getConnectionCount() == 0 && vc.isLoggedOn() == false) { // Remove the virtual circuit m_sess.removeVirtualCircuit( vc.getUID()); // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_TREE)) m_sess.debugPrintln(" Removed virtual circuit " + vc); } // Build the tree disconnect response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); m_sess.sendResponseSMB(smbPkt); // If there are no active virtual circuits then close the session/socket if ( m_sess.numberOfVirtualCircuits() == 0) { // DEBUG if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE)) Debug.println(" Closing session, no more virtual circuits"); // Close the session/socket m_sess.hangupSession( "Tree disconnect"); } // Inform the driver that a connection has been closed if ( conn.getInterface() != null) conn.getInterface().treeClosed(m_sess, conn); } /** * Unlock a byte range in the specified file. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.server.SMBSrvException The exception description. */ protected void procUnLockFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid unlock file request if ( smbPkt.checkPacketIsValid(5, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasReadAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the file id from the request int fid = smbPkt.getParameter(0); long lockcnt = smbPkt.getParameterLong(1); long lockoff = smbPkt.getParameterLong(3); NetworkFile netFile = conn.findFile(fid); if ( netFile == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO)) m_sess.debugPrintln("File UnLock [" + netFile.getFileId() + "] : Offset=" + lockoff + " ,Count=" + lockcnt); // ***** Always return a success status, simulated locking **** // // Build the unlock file response smbPkt.setParameterCount(0); smbPkt.setByteCount(0); // Send the response packet m_sess.sendResponseSMB(smbPkt); } /** * Unsupported SMB procesing. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected final void procUnsupported(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Send an unsupported error response m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVNotSupported, SMBStatus.ErrSrv); } /** * Write to a file. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procWriteFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid file write request if ( smbPkt.checkPacketIsValid(5, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasWriteAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the file id from the request int fid = smbPkt.getParameter(0); int wrtcnt = smbPkt.getParameter(1); long wrtoff = smbPkt.getParameter(2) + ((smbPkt.getParameter(3) << 16) & 0xFFFFFFFFL); NetworkFile netFile = conn.findFile(fid); if ( netFile == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO)) m_sess.debugPrintln("File Write [" + netFile.getFileId() + "] : Size=" + wrtcnt + " ,Pos=" + wrtoff); // Write data to the file byte[] buf = smbPkt.getBuffer(); int pos = smbPkt.getByteOffset(); int wrtlen = 0; // Check that the data block is valid if ( buf[pos] != DataType.DataBlock) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Update the buffer position to the start of the data to be written pos += 3; // Check for a zero length write, this should truncate/extend the file to the write // offset position if ( wrtcnt == 0) { // Truncate/extend the file to the write offset disk.truncateFile(m_sess, conn, netFile, wrtoff); } else { // Write to the file wrtlen = disk.writeFile(m_sess, conn, netFile, buf, pos, wrtcnt, wrtoff); } } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { // Debug if ( Debug.EnableError && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO)) m_sess.debugPrintln("File Write Error [" + netFile.getFileId() + "] : " + ex.toString()); // Failed to read the file m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.HRDWriteFault, SMBStatus.ErrHrd); return; } // Return the count of bytes actually written smbPkt.setParameterCount(1); smbPkt.setParameter(0, wrtlen); smbPkt.setByteCount(0); // Send the write response m_sess.sendResponseSMB(smbPkt); } /** * Write to a file then close the file. * * @param smbPkt SMBSrvPacket * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ protected void procWriteAndCloseFile(SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException { // Check that the received packet looks like a valid file write and close request if ( smbPkt.checkPacketIsValid(6, 0) == false) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv); return; } // Get the virtual circuit for the request VirtualCircuit vc = m_sess.findVirtualCircuit( smbPkt.getUserId()); if ( vc == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv); return; } // Get the tree id from the received packet and validate that it is a valid // connection id. int treeId = smbPkt.getTreeId(); TreeConnection conn = vc.findConnection(treeId); if ( conn == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos); return; } // Check if the user has the required access permission if ( conn.hasWriteAccess() == false) { // User does not have the required access rights m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos); return; } // Get the file id from the request int fid = smbPkt.getParameter(0); int wrtcnt = smbPkt.getParameter(1); int wrtoff = smbPkt.getParameterLong(2); NetworkFile netFile = conn.findFile(fid); if ( netFile == null) { m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos); return; } // Debug if ( Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO)) m_sess.debugPrintln("File Write And Close [" + netFile.getFileId() + "] : Size=" + wrtcnt + " ,Pos=" + wrtoff); // Write data to the file byte[] buf = smbPkt.getBuffer(); int pos = smbPkt.getByteOffset() + 1; // word align int wrtlen = 0; try { // Access the disk interface that is associated with the shared device DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface(); // Write to the file wrtlen = disk.writeFile(m_sess, conn, netFile, buf, pos, wrtcnt, wrtoff); // Close the file // // The disk interface may be null if the file is a named pipe file if ( disk != null) disk.closeFile(m_sess, conn, netFile); // Indicate that the file has been closed netFile.setClosed(true); } catch (InvalidDeviceInterfaceException ex) { // Failed to get/initialize the disk interface m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.DOSInvalidData, SMBStatus.ErrDos); return; } catch (java.io.IOException ex) { // Debug if ( Debug.EnableError && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO)) m_sess.debugPrintln("File Write Error [" + netFile.getFileId() + "] : " + ex.toString()); // Failed to read the file m_sess.sendErrorResponseSMB( smbPkt, SMBStatus.HRDWriteFault, SMBStatus.ErrHrd); return; } // Return the count of bytes actually written smbPkt.setParameterCount(1); smbPkt.setParameter(0, wrtlen); smbPkt.setByteCount(0); smbPkt.setError(0, 0); // Send the write response m_sess.sendResponseSMB(smbPkt); } /** * Run the core SMB protocol handler. * * @param smbPkt SMBSrvPacket * @return boolean true if the packet was processed, else false * @exception IOException * @exception SMBSrvException * @exception TooManyConnectionsException */ public boolean runProtocol( SMBSrvPacket smbPkt) throws java.io.IOException, SMBSrvException, TooManyConnectionsException { // Determine the SMB command type boolean handledOK = true; switch ( smbPkt.getCommand()) { // Session setup case PacketType.SessionSetupAndX: procSessionSetup( smbPkt); break; // Tree connect case PacketType.TreeConnect: procTreeConnect( smbPkt); break; // Tree disconnect case PacketType.TreeDisconnect: procTreeDisconnect( smbPkt); break; // Search case PacketType.Search: procSearch( smbPkt); break; // Get disk attributes case PacketType.DiskInformation: procDiskAttributes( smbPkt); break; // Get file attributes case PacketType.GetFileAttributes: procGetFileAttributes( smbPkt); break; // Set file attributes case PacketType.SetFileAttributes: procSetFileAttributes( smbPkt); break; // Get file information case PacketType.QueryInformation2: procGetFileInformation( smbPkt); break; // Set file information case PacketType.SetInformation2: procSetFileInformation( smbPkt); break; // Open a file case PacketType.OpenFile: procOpenFile( smbPkt); break; // Read from a file case PacketType.ReadFile: procReadFile( smbPkt); break; // Seek file case PacketType.SeekFile: procSeekFile( smbPkt); break; // Close a file case PacketType.CloseFile: procCloseFile( smbPkt); break; // Create a new file case PacketType.CreateFile: case PacketType.CreateNew: procCreateFile( smbPkt); break; // Write to a file case PacketType.WriteFile: procWriteFile( smbPkt); break; // Write to a file, then close the file case PacketType.WriteAndClose: procWriteAndCloseFile( smbPkt); break; // Flush file case PacketType.FlushFile: procFlushFile( smbPkt); break; // Rename a file case PacketType.RenameFile: procRenameFile( smbPkt); break; // Delete a file case PacketType.DeleteFile: procDeleteFile( smbPkt); break; // Create a new directory case PacketType.CreateDirectory: procCreateDirectory( smbPkt); break; // Delete a directory case PacketType.DeleteDirectory: procDeleteDirectory( smbPkt); break; // Check if a directory exists case PacketType.CheckDirectory: procCheckDirectory( smbPkt); break; // Unsupported requests case PacketType.IOCtl: procUnsupported( smbPkt); break; // Echo request case PacketType.Echo: procEcho( smbPkt); break; // Process exit request case PacketType.ProcessExit: procProcessExit( smbPkt); break; // Create temoporary file request case PacketType.CreateTemporary: procCreateTemporaryFile( smbPkt); break; // Lock file request case PacketType.LockFile: procLockFile( smbPkt); break; // Unlock file request case PacketType.UnLockFile: procUnLockFile( smbPkt); break; // Default default: // Indicate that the protocol handler did not process the SMB request if ( Debug.EnableError) Debug.println("<<<<< Unknown SMB type : 0x" + Integer.toHexString( smbPkt.getCommand()) + " >>>>>"); handledOK = false; break; } // Return the handled status return handledOK; } }