/*
* 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.dcerpc.server;
import org.alfresco.jlan.netbios.RFCNetBIOSProtocol;
import org.alfresco.jlan.smb.PacketType;
import org.alfresco.jlan.smb.dcerpc.DCECommand;
import org.alfresco.jlan.smb.dcerpc.DCEDataPacker;
import org.alfresco.jlan.smb.server.SMBTransPacket;
import org.alfresco.jlan.util.DataPacker;
/**
* DCE/RPC Server Packet Class
*
* @author gkspencer
*/
public class DCESrvPacket extends SMBTransPacket {
// DCE/RPC header offsets
private static final int VERSIONMAJOR = 0;
private static final int VERSIONMINOR = 1;
private static final int PDUTYPE = 2;
private static final int HEADERFLAGS = 3;
private static final int PACKEDDATAREP = 4;
private static final int FRAGMENTLEN = 8;
private static final int AUTHLEN = 10;
private static final int CALLID = 12;
private static final int DCEDATA = 16;
// DCE/RPC Request offsets
private static final int ALLOCATIONHINT = 16;
private static final int PRESENTIDENT = 20;
private static final int OPERATIONID = 22;
private static final int OPERATIONDATA = 24;
// Header flags
public static final int FLG_FIRSTFRAG = 0x01;
public static final int FLG_LASTFRAG = 0x02;
public static final int FLG_ONLYFRAG = 0x03;
// DCE/RPC header constants
private static final byte HDR_VERSIONMAJOR = 5;
private static final byte HDR_VERSIONMINOR = 0;
private static final int HDR_PACKEDDATAREP = 0x00000010;
// Offset to DCE/RPC header
private int m_offset;
/**
* Construct a DCE/RPC transaction packet
*
* @param buf Buffer that contains the SMB transaction packet.
*/
public DCESrvPacket(byte[] buf) {
super(buf);
// m_offset = getParameterOffset();
}
/**
* Construct a DCE/RPC transaction packet
*
* @param siz Size of packet to allocate.
*/
public DCESrvPacket(int siz) {
super(siz);
// Set the multiplex id for this transaction
setMultiplexId(getNextMultiplexId());
}
/**
* Return the major version number
*
* @return int
*/
public final int getMajorVersion() {
return (getBuffer()[m_offset + VERSIONMAJOR] & 0xFF);
}
/**
* Return the minor version number
*
* @return int
*/
public final int getMinorVersion() {
return (getBuffer()[m_offset + VERSIONMINOR] & 0xFF);
}
/**
* Return the PDU packet type
*
* @return int
*/
public final int getPDUType() {
return (getBuffer()[m_offset + PDUTYPE] & 0xFF);
}
/**
* Return the header flags
*
* @return int
*/
public final int getDCEHeaderFlags() {
return (getBuffer()[m_offset + HEADERFLAGS] & 0xFF);
}
/**
* Return the packed data representation
*
* @return int
*/
public final int getPackedDataRepresentation() {
return DataPacker.getIntelInt(getBuffer(), m_offset + PACKEDDATAREP);
}
/**
* Return the fragment length
*
* @return int
*/
public final int getFragmentLength() {
return DataPacker.getIntelShort(getBuffer(), m_offset + FRAGMENTLEN);
}
/**
* Set the fragment length
*
* @param len int
*/
public final void setFragmentLength(int len) {
// Set the DCE header fragment length
DataPacker.putIntelShort(len, getBuffer(), m_offset + FRAGMENTLEN);
}
/**
* Return the authentication length
*
* @return int
*/
public final int getAuthenticationLength() {
return DataPacker.getIntelShort(getBuffer(), m_offset + AUTHLEN);
}
/**
* Return the call id
*
* @return int
*/
public final int getCallId() {
return DataPacker.getIntelInt(getBuffer(), m_offset + CALLID);
}
/**
* Determine if this is the first fragment
*
* @return boolean
*/
public final boolean isFirstFragment() {
if ( (getDCEHeaderFlags() & FLG_FIRSTFRAG) != 0)
return true;
return false;
}
/**
* Determine if this is the last fragment
*
* @return boolean
*/
public final boolean isLastFragment() {
if ( (getDCEHeaderFlags() & FLG_LASTFRAG) != 0)
return true;
return false;
}
/**
* Determine if this is the only fragment in the request
*
* @return boolean
*/
public final boolean isOnlyFragment() {
if ( (getDCEHeaderFlags() & FLG_ONLYFRAG) == FLG_ONLYFRAG)
return true;
return false;
}
/**
* Get the offset to the DCE/RPC data within the SMB packet
*
* @return int
*/
public final int getDCEDataOffset() {
// Determine the data offset from the DCE/RPC packet type
int dataOff = -1;
switch (getPDUType()) {
// Bind/bind acknowledge
case DCECommand.BIND:
case DCECommand.BINDACK:
dataOff = m_offset + DCEDATA;
break;
// Request/response
case DCECommand.REQUEST:
case DCECommand.RESPONSE:
dataOff = m_offset + OPERATIONDATA;
break;
}
// Return the data offset
return dataOff;
}
/**
* Get the request allocation hint
*
* @return int
*/
public final int getAllocationHint() {
return DataPacker.getIntelInt(getBuffer(), m_offset + ALLOCATIONHINT);
}
/**
* Set the allocation hint
*
* @param alloc int
*/
public final void setAllocationHint(int alloc) {
DataPacker.putIntelInt(alloc, getBuffer(), m_offset + ALLOCATIONHINT);
}
/**
* Get the request presentation identifier
*
* @return int
*/
public final int getPresentationIdentifier() {
return DataPacker.getIntelShort(getBuffer(), m_offset + PRESENTIDENT);
}
/**
* Set the presentation identifier
*
* @param ident int
*/
public final void setPresentationIdentifier(int ident) {
DataPacker.putIntelShort(ident, getBuffer(), m_offset + PRESENTIDENT);
}
/**
* Get the request operation id
*
* @return int
*/
public final int getOperationId() {
return DataPacker.getIntelShort(getBuffer(), m_offset + OPERATIONID);
}
/**
* Initialize the DCE/RPC request. Set the SMB transaction parameter count so that the data
* offset can be calculated.
*
* @param handle int
* @param typ byte
* @param flags int
* @param callId int
*/
public final void initializeDCERequest(int handle, byte typ, int flags, int callId) {
// Initialize the transaction
InitializeTransact(16, null, 0, null, 0);
// Set the parameter byte count/offset for this packet
int bytPos = DCEDataPacker.longwordAlign(getByteOffset());
setParameter(3, 0);
setParameter(4, bytPos - RFCNetBIOSProtocol.HEADER_LEN);
// Set the parameter displacement
setParameter(5, 0);
// Set the data byte count/offset for this packet
setParameter(6, 0);
setParameter(7, bytPos - RFCNetBIOSProtocol.HEADER_LEN);
// Set the data displacement
setParameter(8, 0);
// Set up word count
setParameter(9, 0);
// Set the setup words
setSetupParameter(0, PacketType.TransactNmPipe);
setSetupParameter(1, handle);
// Reset the DCE offset for a DCE reply
m_offset = bytPos;
// Build the DCE/RPC header
byte[] buf = getBuffer();
DataPacker.putZeros(buf, m_offset, 24);
buf[m_offset + VERSIONMAJOR] = HDR_VERSIONMAJOR;
buf[m_offset + VERSIONMINOR] = HDR_VERSIONMINOR;
buf[m_offset + PDUTYPE] = typ;
buf[m_offset + HEADERFLAGS] = (byte) (flags & 0xFF);
DataPacker.putIntelInt(HDR_PACKEDDATAREP, buf, m_offset + PACKEDDATAREP);
DataPacker.putIntelInt(0, buf, m_offset + AUTHLEN);
DataPacker.putIntelInt(callId, buf, m_offset + CALLID);
}
/**
* Initialize the DCE/RPC reply. Set the SMB transaction parameter count so that the data offset
* can be calculated.
*/
public final void initializeDCEReply() {
// Set the total parameter words
setParameterCount(10);
// Set the total parameter/data bytes
setParameter(0, 0);
setParameter(1, 0);
// Set the parameter byte count/offset for this packet
int bytPos = DCEDataPacker.longwordAlign(getByteOffset());
setParameter(3, 0);
setParameter(4, bytPos - RFCNetBIOSProtocol.HEADER_LEN);
// Set the parameter displacement
setParameter(5, 0);
// Set the data byte count/offset for this packet
setParameter(6, 0);
setParameter(7, bytPos - RFCNetBIOSProtocol.HEADER_LEN);
// Set the data displacement
setParameter(8, 0);
// Set up word count
setParameter(9, 0);
}
/**
* Dump the DCE/RPC header details
*/
public final void DumpHeader() {
// Dump the PDU type
System.out.println("** DCE/RPC Header - PDU Type = " + DCECommand.getCommandString(getPDUType()));
System.out.println(" Version : " + getMajorVersion() + "." + getMinorVersion());
System.out.println(" Flags : 0x" + getDCEHeaderFlags());
System.out.println(" Packed Data Rep : 0x" + getPackedDataRepresentation());
System.out.println(" Fragment Length : " + getFragmentLength());
System.out.println(" Auth Length : " + getAuthenticationLength());
System.out.println(" Call ID : " + getCallId());
}
}