/*
* 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;
}
}