/*
* 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 java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
import org.alfresco.jlan.debug.Debug;
import org.alfresco.jlan.server.auth.acl.AccessControlManager;
import org.alfresco.jlan.server.core.ShareType;
import org.alfresco.jlan.server.core.SharedDevice;
import org.alfresco.jlan.server.core.SharedDeviceList;
import org.alfresco.jlan.smb.Dialect;
import org.alfresco.jlan.smb.SMBStatus;
import org.alfresco.jlan.smb.dcerpc.DCEBuffer;
import org.alfresco.jlan.smb.dcerpc.DCEBufferException;
import org.alfresco.jlan.smb.dcerpc.Srvsvc;
import org.alfresco.jlan.smb.dcerpc.info.ServerInfo;
import org.alfresco.jlan.smb.dcerpc.info.ShareInfo;
import org.alfresco.jlan.smb.dcerpc.info.ShareInfoList;
import org.alfresco.jlan.smb.server.CIFSConfigSection;
import org.alfresco.jlan.smb.server.SMBServer;
import org.alfresco.jlan.smb.server.SMBSrvException;
import org.alfresco.jlan.smb.server.SMBSrvPacket;
import org.alfresco.jlan.smb.server.SMBSrvSession;
/**
* Srvsvc DCE/RPC Handler Class
*
* @author gkspencer
*/
public class SrvsvcDCEHandler implements DCEHandler {
/**
* Process a SrvSvc DCE/RPC request
*
* @param sess SMBSrvSession
* @param inBuf DCEBuffer
* @param pipeFile DCEPipeFile
* @paam smbPkt SMBSrvPacket
* @exception IOException
* @exception SMBSrvException
*/
public void processRequest(SMBSrvSession sess, DCEBuffer inBuf, DCEPipeFile pipeFile, SMBSrvPacket smbPkt)
throws IOException, SMBSrvException {
// Get the operation code and move the buffer pointer to the start of the request data
int opNum = inBuf.getHeaderValue(DCEBuffer.HDR_OPCODE);
try {
inBuf.skipBytes(DCEBuffer.OPERATIONDATA);
}
catch (DCEBufferException ex) {
}
// Debug
if ( Debug.EnableInfo && sess.hasDebug(SMBSrvSession.DBG_DCERPC))
sess.debugPrintln("DCE/RPC SrvSvc request=" + Srvsvc.getOpcodeName(opNum));
// Create the output DCE buffer and add the response header
DCEBuffer outBuf = new DCEBuffer();
outBuf.putResponseHeader(inBuf.getHeaderValue(DCEBuffer.HDR_CALLID), 0);
// Process the request
boolean processed = false;
switch (opNum) {
// Enumerate shares
case Srvsvc.NetrShareEnum:
processed = netShareEnum(sess, inBuf, outBuf);
break;
// Enumerate all shares
case Srvsvc.NetrShareEnumSticky:
processed = netShareEnum(sess, inBuf, outBuf);
break;
// Get share information
case Srvsvc.NetrShareGetInfo:
processed = netShareGetInfo(sess, inBuf, outBuf);
break;
// Get server information
case Srvsvc.NetrServerGetInfo:
processed = netServerGetInfo(sess, inBuf, outBuf);
break;
// Unsupported function
default:
break;
}
// Return an error status if the request was not processed
if ( processed == false) {
sess.sendErrorResponseSMB( smbPkt, SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
return;
}
// Set the allocation hint for the response
outBuf.setHeaderValue(DCEBuffer.HDR_ALLOCHINT, outBuf.getLength());
// Attach the output buffer to the pipe file
pipeFile.setBufferedData(outBuf);
}
/**
* Handle a share enumeration request
*
* @param sess SMBSrvSession
* @param inBuf DCEPacket
* @param outBuf DCEPacket
* @return boolean
*/
protected final boolean netShareEnum(SMBSrvSession sess, DCEBuffer inBuf, DCEBuffer outBuf) {
// Decode the request
String srvName = null;
ShareInfoList shrInfo = null;
try {
inBuf.skipPointer();
srvName = inBuf.getString(DCEBuffer.ALIGN_INT);
shrInfo = new ShareInfoList(inBuf);
}
catch (DCEBufferException ex) {
return false;
}
// Debug
if ( Debug.EnableInfo && sess.hasDebug(SMBSrvSession.DBG_DCERPC))
sess.debugPrintln("NetShareEnum srvName=" + srvName + ", shrInfo=" + shrInfo.toString());
// Get the share list from the server
SharedDeviceList shareList = sess.getServer().getShareMapper().getShareList(srvName, sess, false);
// Check if there is an access control manager configured
if ( sess.getServer().hasAccessControlManager()) {
// Filter the list of available shares by applying any access control rules
AccessControlManager aclMgr = sess.getServer().getAccessControlManager();
shareList = aclMgr.filterShareList(sess, shareList);
}
// Create a list of share information objects of the required information level
Vector<ShareInfo> infoList = new Vector<ShareInfo>();
Enumeration<SharedDevice> enm = shareList.enumerateShares();
while (enm.hasMoreElements()) {
// Get the current shared device details
SharedDevice share = enm.nextElement();
// Determine the share type
int shrTyp = ShareInfo.Disk;
if ( share.getType() == ShareType.PRINTER)
shrTyp = ShareInfo.PrintQueue;
else if ( share.getType() == ShareType.NAMEDPIPE)
shrTyp = ShareInfo.IPC;
else if ( share.getType() == ShareType.ADMINPIPE)
shrTyp = ShareInfo.IPC + ShareInfo.Hidden;
// Create a share information object with the basic information
ShareInfo info = new ShareInfo(shrInfo.getInformationLevel(), share.getName(), shrTyp, share.getComment());
infoList.add(info);
// Add additional information
switch (shrInfo.getInformationLevel()) {
// Level 2
case 2:
if ( share.getContext() != null)
info.setPath(share.getContext().getDeviceName());
break;
// Level 502
case 502:
if ( share.getContext() != null)
info.setPath(share.getContext().getDeviceName());
break;
}
}
// Set the share information list in the server share information and write the
// share information to the output DCE buffer.
shrInfo.setShareList(infoList);
try {
shrInfo.writeList(outBuf);
outBuf.putInt(0); // status code
}
catch (DCEBufferException ex) {
}
// Indicate that the request was processed successfully
return true;
}
/**
* Handle a get share information request
*
* @param sess SMBSrvSession
* @param inBuf DCEPacket
* @param outBuf DCEPacket
* @return boolean
*/
protected final boolean netShareGetInfo(SMBSrvSession sess, DCEBuffer inBuf, DCEBuffer outBuf) {
// Decode the request
String srvName = null;
String shrName = null;
int infoLevel = 0;
try {
inBuf.skipPointer();
srvName = inBuf.getString(DCEBuffer.ALIGN_INT);
shrName = inBuf.getString(DCEBuffer.ALIGN_INT);
infoLevel = inBuf.getInt();
}
catch (DCEBufferException ex) {
return false;
}
// Debug
if ( Debug.EnableInfo && sess.hasDebug(SMBSrvSession.DBG_DCERPC))
sess.debugPrintln("netShareGetInfo srvname=" + srvName + ", share=" + shrName + ", infoLevel=" + infoLevel);
// Find the required shared device
SharedDevice share = null;
try {
// Get the shared device details
share = sess.getServer().findShare(srvName, shrName, ShareType.UNKNOWN, sess, false);
}
catch (Exception ex) {
}
// Check if the share details are valid
if ( share == null)
return false;
// Determine the share type
int shrTyp = ShareInfo.Disk;
if ( share.getType() == ShareType.PRINTER)
shrTyp = ShareInfo.PrintQueue;
else if ( share.getType() == ShareType.NAMEDPIPE)
shrTyp = ShareInfo.IPC;
else if ( share.getType() == ShareType.ADMINPIPE)
shrTyp = ShareInfo.IPC + ShareInfo.Hidden;
// Create the share information
ShareInfo shrInfo = new ShareInfo(infoLevel, share.getName(), shrTyp, share.getComment());
// Pack the information level, structure pointer and share information
outBuf.putInt(infoLevel);
outBuf.putPointer(true);
shrInfo.writeObject(outBuf, outBuf);
// Add the status and return a success status
outBuf.putInt(0);
return true;
}
/**
* Handle a get server information request
*
* @param sess SMBSrvSession
* @param inBuf DCEPacket
* @param outBuf DCEPacket
* @return boolean
*/
protected final boolean netServerGetInfo(SMBSrvSession sess, DCEBuffer inBuf, DCEBuffer outBuf) {
// Decode the request
String srvName = null;
int infoLevel = 0;
try {
inBuf.skipPointer();
srvName = inBuf.getString(DCEBuffer.ALIGN_INT);
infoLevel = inBuf.getInt();
}
catch (DCEBufferException ex) {
return false;
}
// Debug
if ( Debug.EnableInfo && sess.hasDebug(SMBSrvSession.DBG_DCERPC))
sess.debugPrintln("netServerGetInfo srvname=" + srvName + ", infoLevel=" + infoLevel);
// Create the server information and set the common values
ServerInfo srvInfo = new ServerInfo(infoLevel);
SMBServer srv = sess.getSMBServer();
srvInfo.setServerName(srv.getServerName());
srvInfo.setComment(srv.getComment());
srvInfo.setServerType(srv.getServerType());
// Determine if the server is using the NT SMB dialect and set the platofmr id accordingly
CIFSConfigSection cifsConfig = srv.getCIFSConfiguration();
if ( cifsConfig != null && cifsConfig.getEnabledDialects().hasDialect(Dialect.NT) == true) {
srvInfo.setPlatformId(ServerInfo.PLATFORM_NT);
srvInfo.setVersion(5, 1);
}
else {
srvInfo.setPlatformId(ServerInfo.PLATFORM_OS2);
srvInfo.setVersion(4, 0);
}
// Write the server information to the DCE response
srvInfo.writeObject(outBuf, outBuf);
outBuf.putInt(0);
// Indicate that the request was processed successfully
return true;
}
}