KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > filesys > smb > server > LanManProtocolHandler


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.filesys.smb.server;
18
19 import java.io.FileNotFoundException JavaDoc;
20 import java.io.IOException JavaDoc;
21
22 import org.alfresco.filesys.netbios.RFCNetBIOSProtocol;
23 import org.alfresco.filesys.server.auth.ClientInfo;
24 import org.alfresco.filesys.server.auth.InvalidUserException;
25 import org.alfresco.filesys.server.auth.SrvAuthenticator;
26 import org.alfresco.filesys.server.core.InvalidDeviceInterfaceException;
27 import org.alfresco.filesys.server.core.ShareType;
28 import org.alfresco.filesys.server.core.SharedDevice;
29 import org.alfresco.filesys.server.filesys.AccessDeniedException;
30 import org.alfresco.filesys.server.filesys.DiskDeviceContext;
31 import org.alfresco.filesys.server.filesys.DiskInterface;
32 import org.alfresco.filesys.server.filesys.FileAccess;
33 import org.alfresco.filesys.server.filesys.FileAction;
34 import org.alfresco.filesys.server.filesys.FileInfo;
35 import org.alfresco.filesys.server.filesys.FileOfflineException;
36 import org.alfresco.filesys.server.filesys.FileOpenParams;
37 import org.alfresco.filesys.server.filesys.FileSharingException;
38 import org.alfresco.filesys.server.filesys.FileStatus;
39 import org.alfresco.filesys.server.filesys.NetworkFile;
40 import org.alfresco.filesys.server.filesys.SearchContext;
41 import org.alfresco.filesys.server.filesys.SrvDiskInfo;
42 import org.alfresco.filesys.server.filesys.TooManyConnectionsException;
43 import org.alfresco.filesys.server.filesys.TooManyFilesException;
44 import org.alfresco.filesys.server.filesys.TreeConnection;
45 import org.alfresco.filesys.server.filesys.UnsupportedInfoLevelException;
46 import org.alfresco.filesys.server.filesys.VolumeInfo;
47 import org.alfresco.filesys.smb.DataType;
48 import org.alfresco.filesys.smb.FindFirstNext;
49 import org.alfresco.filesys.smb.InvalidUNCPathException;
50 import org.alfresco.filesys.smb.PCShare;
51 import org.alfresco.filesys.smb.PacketType;
52 import org.alfresco.filesys.smb.SMBDate;
53 import org.alfresco.filesys.smb.SMBStatus;
54 import org.alfresco.filesys.util.DataBuffer;
55 import org.alfresco.filesys.util.DataPacker;
56 import org.apache.commons.logging.Log;
57 import org.apache.commons.logging.LogFactory;
58
59 /**
60  * LanMan SMB Protocol Handler Class.
61  * <p>
62  * The LanMan protocol handler processes the additional SMBs that were added to the protocol in the
63  * LanMan1 and LanMan2 SMB dialects.
64  */

65 class LanManProtocolHandler extends CoreProtocolHandler
66 {
67
68     // Debug logging
69

70     private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol");
71
72     // Locking type flags
73

74     protected static final int LockShared = 0x01;
75     protected static final int LockOplockRelease = 0x02;
76     protected static final int LockChangeType = 0x04;
77     protected static final int LockCancel = 0x08;
78     protected static final int LockLargeFiles = 0x10;
79
80     /**
81      * LanManProtocolHandler constructor.
82      */

83     protected LanManProtocolHandler()
84     {
85         super();
86     }
87
88     /**
89      * LanManProtocolHandler constructor.
90      *
91      * @param sess org.alfresco.filesys.smbsrv.SMBSrvSession
92      */

93     protected LanManProtocolHandler(SMBSrvSession sess)
94     {
95         super(sess);
96     }
97
98     /**
99      * Return the protocol name
100      *
101      * @return String
102      */

103     public String JavaDoc getName()
104     {
105         return "LanMan";
106     }
107
108     /**
109      * Process the chained SMB commands (AndX).
110      *
111      * @return New offset to the end of the reply packet
112      * @param outPkt Reply packet.
113      */

114     protected final int procAndXCommands(SMBSrvPacket outPkt)
115     {
116
117         // Get the chained command and command block offset
118

119         int andxCmd = m_smbPkt.getAndXCommand();
120         int andxOff = m_smbPkt.getParameter(1) + RFCNetBIOSProtocol.HEADER_LEN;
121
122         // Set the initial chained command and offset
123

124         outPkt.setAndXCommand(andxCmd);
125         outPkt.setParameter(1, andxOff - RFCNetBIOSProtocol.HEADER_LEN);
126
127         // Pointer to the last parameter block, starts with the main command parameter block
128

129         int paramBlk = SMBSrvPacket.WORDCNT;
130
131         // Get the current end of the reply packet offset
132

133         int endOfPkt = outPkt.getByteOffset() + outPkt.getByteCount();
134         boolean andxErr = false;
135
136         while (andxCmd != SMBSrvPacket.NO_ANDX_CMD && andxErr == false)
137         {
138
139             // Determine the chained command type
140

141             int prevEndOfPkt = endOfPkt;
142
143             switch (andxCmd)
144             {
145
146             // Tree connect
147

148             case PacketType.TreeConnectAndX:
149                 endOfPkt = procChainedTreeConnectAndX(andxOff, outPkt, endOfPkt);
150                 break;
151             }
152
153             // Advance to the next chained command block
154

155             andxCmd = m_smbPkt.getAndXParameter(andxOff, 0) & 0x00FF;
156             andxOff = m_smbPkt.getAndXParameter(andxOff, 1);
157
158             // Set the next chained command details in the current parameter block
159

160             outPkt.setAndXCommand(prevEndOfPkt, andxCmd);
161             outPkt.setAndXParameter(paramBlk, 1, prevEndOfPkt - RFCNetBIOSProtocol.HEADER_LEN);
162
163             // Advance the current parameter block
164

165             paramBlk = prevEndOfPkt;
166
167             // Check if the chained command has generated an error status
168

169             if (outPkt.getErrorCode() != SMBStatus.Success)
170                 andxErr = true;
171         }
172
173         // Return the offset to the end of the reply packet
174

175         return endOfPkt;
176     }
177
178     /**
179      * Process a chained tree connect request.
180      *
181      * @return New end of reply offset.
182      * @param cmdOff int Offset to the chained command within the request packet.
183      * @param outPkt SMBSrvPacket Reply packet.
184      * @param endOff int Offset to the current end of the reply packet.
185      */

186     protected final int procChainedTreeConnectAndX(int cmdOff, SMBSrvPacket outPkt, int endOff)
187     {
188
189         // Extract the parameters
190

191         int flags = m_smbPkt.getAndXParameter(cmdOff, 2);
192         int pwdLen = m_smbPkt.getAndXParameter(cmdOff, 3);
193
194         // Get the data bytes position and length
195

196         int dataPos = m_smbPkt.getAndXByteOffset(cmdOff);
197         int dataLen = m_smbPkt.getAndXByteCount(cmdOff);
198         byte[] buf = m_smbPkt.getBuffer();
199
200         // Extract the password string
201

202         String JavaDoc pwd = null;
203
204         if (pwdLen > 0)
205         {
206             pwd = new String JavaDoc(buf, dataPos, pwdLen);
207             dataPos += pwdLen;
208             dataLen -= pwdLen;
209         }
210
211         // Extract the requested share name, as a UNC path
212

213         String JavaDoc uncPath = DataPacker.getString(buf, dataPos, dataLen);
214         if (uncPath == null)
215         {
216             outPkt.setError(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
217             return endOff;
218         }
219
220         // Extract the service type string
221

222         dataPos += uncPath.length() + 1; // null terminated
223
dataLen -= uncPath.length() + 1; // null terminated
224

225         String JavaDoc service = DataPacker.getString(buf, dataPos, dataLen);
226         if (service == null)
227         {
228             outPkt.setError(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
229             return endOff;
230         }
231
232         // Convert the service type to a shared device type, client may specify '?????' in which
233
// case we ignore the error.
234

235         int servType = ShareType.ServiceAsType(service);
236         if (servType == ShareType.UNKNOWN && service.compareTo("?????") != 0)
237         {
238             outPkt.setError(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
239             return endOff;
240         }
241
242         // Debug
243

244         if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TREE))
245             logger.debug("ANDX Tree Connect AndX - " + uncPath + ", " + service);
246
247         // Parse the requested share name
248

249         PCShare share = null;
250
251         try
252         {
253             share = new PCShare(uncPath);
254         }
255         catch (org.alfresco.filesys.smb.InvalidUNCPathException ex)
256         {
257             outPkt.setError(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
258             return endOff;
259         }
260
261         // Map the IPC$ share to the admin pipe type
262

263         if (servType == ShareType.NAMEDPIPE && share.getShareName().compareTo("IPC$") == 0)
264             servType = ShareType.ADMINPIPE;
265
266         // Find the requested shared device
267

268         SharedDevice shareDev = null;
269
270         try
271         {
272
273             // Get/create the shared device
274

275             shareDev = m_sess.getSMBServer().findShare(share.getNodeName(), share.getShareName(), servType,
276                     getSession(), true);
277         }
278         catch (InvalidUserException ex)
279         {
280
281             // Return a logon failure status
282

283             outPkt.setError(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
284             return endOff;
285         }
286         catch (Exception JavaDoc ex)
287         {
288
289             // Return a general status, bad network name
290

291             outPkt.setError(SMBStatus.SRVInvalidNetworkName, SMBStatus.ErrSrv);
292             return endOff;
293         }
294
295         // Check if the share is valid
296

297         if (shareDev == null || (servType != ShareType.UNKNOWN && shareDev.getType() != servType))
298         {
299             outPkt.setError(SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
300             return endOff;
301         }
302
303         // Authenticate the share connect, if the server is using share mode security
304

305         SrvAuthenticator auth = getSession().getSMBServer().getAuthenticator();
306         int filePerm = FileAccess.Writeable;
307
308         if (auth != null && auth.getAccessMode() == SrvAuthenticator.SHARE_MODE)
309         {
310
311             // Validate the share connection
312

313             filePerm = auth.authenticateShareConnect(m_sess.getClientInformation(), shareDev, pwd, m_sess);
314             if (filePerm < 0)
315             {
316
317                 // Invalid share connection request
318

319                 outPkt.setError(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
320                 return endOff;
321             }
322         }
323
324         // Allocate a tree id for the new connection
325

326         try
327         {
328
329             // Allocate the tree id for this connection
330

331             int treeId = m_sess.addConnection(shareDev);
332             outPkt.setTreeId(treeId);
333
334             // Set the file permission that this user has been granted for this share
335

336             TreeConnection tree = m_sess.findConnection(treeId);
337             tree.setPermission(filePerm);
338
339             // Inform the driver that a connection has been opened
340

341             if (tree.getInterface() != null)
342                 tree.getInterface().treeOpened(m_sess, tree);
343
344             // Debug
345

346             if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TREE))
347                 logger.debug("ANDX Tree Connect AndX - Allocated Tree Id = " + treeId);
348         }
349         catch (TooManyConnectionsException ex)
350         {
351
352             // Too many connections open at the moment
353

354             outPkt.setError(SMBStatus.SRVNoResourcesAvailable, SMBStatus.ErrSrv);
355             return endOff;
356         }
357
358         // Build the tree connect response
359

360         outPkt.setAndXParameterCount(endOff, 2);
361         outPkt.setAndXParameter(endOff, 0, SMBSrvPacket.NO_ANDX_CMD);
362         outPkt.setAndXParameter(endOff, 1, 0);
363
364         // Pack the service type
365

366         int pos = outPkt.getAndXByteOffset(endOff);
367         byte[] outBuf = outPkt.getBuffer();
368         pos = DataPacker.putString(ShareType.TypeAsService(shareDev.getType()), outBuf, pos, true);
369         int bytLen = pos - outPkt.getAndXByteOffset(endOff);
370         outPkt.setAndXByteCount(endOff, bytLen);
371
372         // Return the new end of packet offset
373

374         return pos;
375     }
376
377     /**
378      * Close a search started via the transact2 find first/next command.
379      *
380      * @param outPkt SMBSrvPacket
381      * @exception java.io.IOException If an I/O error occurs
382      * @exception SMBSrvException If an SMB protocol error occurs
383      */

384     protected final void procFindClose(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
385     {
386
387         // Check that the received packet looks like a valid find close request
388

389         if (m_smbPkt.checkPacketIsValid(1, 0) == false)
390         {
391             m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
392             return;
393         }
394
395         // Get the tree connection details
396

397         int treeId = m_smbPkt.getTreeId();
398         TreeConnection conn = m_sess.findConnection(treeId);
399
400         if (conn == null)
401         {
402             m_sess.sendErrorResponseSMB(SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv);
403             return;
404         }
405
406         // Check if the user has the required access permission
407

408         if (conn.hasReadAccess() == false)
409         {
410
411             // User does not have the required access rights
412

413             m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
414             return;
415         }
416
417         // Get the search id
418

419         int searchId = m_smbPkt.getParameter(0);
420
421         // Get the search context
422

423         SearchContext ctx = m_sess.getSearchContext(searchId);
424
425         if (ctx == null)
426         {
427
428             // Invalid search handle
429

430             m_sess.sendSuccessResponseSMB();
431             return;
432         }
433
434         // Debug
435

436         if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
437             logger.debug("Close trans search [" + searchId + "]");
438
439         // Deallocate the search slot, close the search.
440

441         m_sess.deallocateSearchSlot(searchId);
442
443         // Return a success status SMB
444

445         m_sess.sendSuccessResponseSMB();
446     }
447
448     /**
449      * Process the file lock/unlock request.
450      *
451      * @param outPkt SMBSrvPacket
452      */

453     protected final void procLockingAndX(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
454     {
455
456         // Check that the received packet looks like a valid locking andX request
457

458         if (m_smbPkt.checkPacketIsValid(8, 0) == false)
459         {
460             m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
461             return;
462         }
463
464         // Get the tree connection details
465

466         int treeId = m_smbPkt.getTreeId();
467         TreeConnection conn = m_sess.findConnection(treeId);
468
469         if (conn == null)
470         {
471             m_sess.sendErrorResponseSMB(SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv);
472             return;
473         }
474
475         // Check if the user has the required access permission
476

477         if (conn.hasReadAccess() == false)
478         {
479
480             // User does not have the required access rights
481

482             m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
483             return;
484         }
485
486         // Extract the file lock/unlock parameters
487

488         int fid = m_smbPkt.getParameter(2);
489         int lockType = m_smbPkt.getParameter(3);
490         long lockTmo = m_smbPkt.getParameterLong(4);
491         int lockCnt = m_smbPkt.getParameter(6);
492         int unlockCnt = m_smbPkt.getParameter(7);
493
494         NetworkFile netFile = conn.findFile(fid);
495
496         if (netFile == null)
497         {
498             m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos);
499             return;
500         }
501
502         // Debug
503

504         if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_LOCK))
505             logger.debug("File Lock [" + netFile.getFileId() + "] : type=0x" + Integer.toHexString(lockType) + ", tmo="
506                     + lockTmo + ", locks=" + lockCnt + ", unlocks=" + unlockCnt);
507
508         // Return a success status for now
509

510         outPkt.setParameterCount(2);
511         outPkt.setAndXCommand(0xFF);
512         outPkt.setParameter(1, 0);
513         outPkt.setByteCount(0);
514
515         // Send the lock request response
516

517         m_sess.sendResponseSMB(outPkt);
518     }
519
520     /**
521      * Process the logoff request.
522      *
523      * @param outPkt SMBSrvPacket
524      */

525     protected final void procLogoffAndX(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
526     {
527
528         // Check that the received packet looks like a valid logoff andX request
529

530         if (m_smbPkt.checkPacketIsValid(15, 1) == false)
531         {
532             m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
533             return;
534         }
535
536         // Return a success status SMB
537

538         m_sess.sendSuccessResponseSMB();
539     }
540
541     /**
542      * Process the file open request.
543      *
544      * @param outPkt SMBSrvPacket
545      */

546     protected final void procOpenAndX(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
547     {
548
549         // Check that the received packet looks like a valid open andX request
550

551         if (m_smbPkt.checkPacketIsValid(15, 1) == false)
552         {
553             m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
554             return;
555         }
556
557         // Get the tree connection details
558

559         int treeId = m_smbPkt.getTreeId();
560         TreeConnection conn = m_sess.findConnection(treeId);
561
562         if (conn == null)
563         {
564             m_sess.sendErrorResponseSMB(SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv);
565             return;
566         }
567
568         // Check if the user has the required access permission
569

570         if (conn.hasReadAccess() == false)
571         {
572
573             // User does not have the required access rights
574

575             m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
576             return;
577         }
578
579         // If the connection is to the IPC$ remote admin named pipe pass the request to the IPC
580
// handler. If the device is
581
// not a disk type device then return an error.
582

583         if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
584         {
585
586             // Use the IPC$ handler to process the request
587

588             IPCHandler.processIPCRequest(m_sess, outPkt);
589             return;
590         }
591         else if (conn.getSharedDevice().getType() != ShareType.DISK)
592         {
593
594             // Return an access denied error
595

596             // m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
597
// m_sess.sendErrorResponseSMB(SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
598
m_sess.sendErrorResponseSMB(SMBStatus.SRVNoAccessRights, SMBStatus.ErrSrv);
599             return;
600         }
601
602         // Extract the open file parameters
603

604         int flags = m_smbPkt.getParameter(2);
605         int access = m_smbPkt.getParameter(3);
606         int srchAttr = m_smbPkt.getParameter(4);
607         int fileAttr = m_smbPkt.getParameter(5);
608         int crTime = m_smbPkt.getParameter(6);
609         int crDate = m_smbPkt.getParameter(7);
610         int openFunc = m_smbPkt.getParameter(8);
611         int allocSiz = m_smbPkt.getParameterLong(9);
612
613         // Extract the filename string
614

615         String JavaDoc fileName = m_smbPkt.unpackString(m_smbPkt.isUnicode());
616         if (fileName == null)
617         {
618             m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
619             return;
620         }
621
622         // Create the file open parameters
623

624         SMBDate crDateTime = null;
625         if (crTime > 0 && crDate > 0)
626             crDateTime = new SMBDate(crDate, crTime);
627
628         FileOpenParams params = new FileOpenParams(fileName, openFunc, access, srchAttr, fileAttr, allocSiz, crDateTime
629                 .getTime());
630
631         // Debug
632

633         if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
634             logger.debug("File Open AndX [" + treeId + "] params=" + params);
635
636         // Access the disk interface and open the requested file
637

638         int fid;
639         NetworkFile netFile = null;
640         int respAction = 0;
641
642         try
643         {
644
645             // Access the disk interface that is associated with the shared device
646

647             DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
648
649             // Check if the requested file already exists
650

651             int fileSts = disk.fileExists(m_sess, conn, fileName);
652
653             if (fileSts == FileStatus.NotExist)
654             {
655
656                 // Check if the file should be created if it does not exist
657

658                 if (FileAction.createNotExists(openFunc))
659                 {
660
661                     // Check if the session has write access to the filesystem
662

663                     if (conn.hasWriteAccess() == false)
664                     {
665
666                         // User does not have the required access rights
667

668                         m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
669                         return;
670                     }
671
672                     // Create a new file
673

674                     netFile = disk.createFile(m_sess, conn, params);
675
676                     // Indicate that the file did not exist and was created
677

678                     respAction = FileAction.FileCreated;
679                 }
680                 else
681                 {
682
683                     // Check if the path is a directory
684

685                     if (fileSts == FileStatus.DirectoryExists)
686                     {
687
688                         // Return an access denied error
689

690                         m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
691                     }
692                     else
693                     {
694
695                         // Return a file not found error
696

697                         m_sess.sendErrorResponseSMB(SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
698                     }
699                     return;
700                 }
701             }
702             else
703             {
704
705                 // Open the requested file
706

707                 netFile = disk.openFile(m_sess, conn, params);
708
709                 // Set the file action response
710

711                 if (FileAction.truncateExistingFile(openFunc))
712                     respAction = FileAction.FileTruncated;
713                 else
714                     respAction = FileAction.FileExisted;
715             }
716
717             // Add the file to the list of open files for this tree connection
718

719             fid = conn.addFile(netFile, getSession());
720
721         }
722         catch (InvalidDeviceInterfaceException ex)
723         {
724
725             // Failed to get/initialize the disk interface
726

727             m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
728             return;
729         }
730         catch (TooManyFilesException ex)
731         {
732
733             // Too many files are open on this connection, cannot open any more files.
734

735             m_sess.sendErrorResponseSMB(SMBStatus.DOSTooManyOpenFiles, SMBStatus.ErrDos);
736             return;
737         }
738         catch (AccessDeniedException ex)
739         {
740
741             // Return an access denied error
742

743             m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
744             return;
745         }
746         catch (FileSharingException ex)
747         {
748
749             // Return a sharing violation error
750

751             m_sess.sendErrorResponseSMB(SMBStatus.DOSFileSharingConflict, SMBStatus.ErrDos);
752             return;
753         }
754         catch (FileOfflineException ex)
755         {
756
757             // File data is unavailable
758

759             m_sess.sendErrorResponseSMB(SMBStatus.NTFileOffline, SMBStatus.HRDDriveNotReady, SMBStatus.ErrHrd);
760             return;
761         }
762         catch (java.io.IOException JavaDoc ex)
763         {
764
765             // Failed to open the file
766

767             m_sess.sendErrorResponseSMB(SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
768             return;
769         }
770
771         // Build the open file response
772

773         outPkt.setParameterCount(15);
774
775         outPkt.setAndXCommand(0xFF);
776         outPkt.setParameter(1, 0); // AndX offset
777

778         outPkt.setParameter(2, fid);
779         outPkt.setParameter(3, netFile.getFileAttributes()); // file attributes
780

781         SMBDate modDate = null;
782
783         if (netFile.hasModifyDate())
784             modDate = new SMBDate(netFile.getModifyDate());
785
786         outPkt.setParameter(4, modDate != null ? modDate.asSMBTime() : 0); // last write time
787
outPkt.setParameter(5, modDate != null ? modDate.asSMBDate() : 0); // last write date
788
outPkt.setParameterLong(6, netFile.getFileSizeInt()); // file size
789
outPkt.setParameter(8, netFile.getGrantedAccess());
790         outPkt.setParameter(9, OpenAndX.FileTypeDisk);
791         outPkt.setParameter(10, 0); // named pipe state
792
outPkt.setParameter(11, respAction);
793         outPkt.setParameter(12, 0); // server FID (long)
794
outPkt.setParameter(13, 0);
795         outPkt.setParameter(14, 0);
796
797         outPkt.setByteCount(0);
798
799         // Send the response packet
800

801         m_sess.sendResponseSMB(outPkt);
802     }
803
804     /**
805      * Process the file read request.
806      *
807      * @param outPkt SMBSrvPacket
808      */

809     protected final void procReadAndX(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
810     {
811
812         // Check that the received packet looks like a valid read andX request
813

814         if (m_smbPkt.checkPacketIsValid(10, 0) == false)
815         {
816             m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
817             return;
818         }
819
820         // Get the tree connection details
821

822         int treeId = m_smbPkt.getTreeId();
823         TreeConnection conn = m_sess.findConnection(treeId);
824
825         if (conn == null)
826         {
827             m_sess.sendErrorResponseSMB(SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv);
828             return;
829         }
830
831         // Check if the user has the required access permission
832

833         if (conn.hasReadAccess() == false)
834         {
835
836             // User does not have the required access rights
837

838             m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
839             return;
840         }
841
842         // If the connection is to the IPC$ remote admin named pipe pass the request to the IPC
843
// handler.
844

845         if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
846         {
847
848             // Use the IPC$ handler to process the request
849

850             IPCHandler.processIPCRequest(m_sess, outPkt);
851             return;
852         }
853
854         // Extract the read file parameters
855

856         int fid = m_smbPkt.getParameter(2);
857         int offset = m_smbPkt.getParameterLong(3);
858         int maxCount = m_smbPkt.getParameter(5);
859
860         NetworkFile netFile = conn.findFile(fid);
861
862         if (netFile == null)
863         {
864             m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos);
865             return;
866         }
867
868         // Debug
869

870         if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO))
871             logger.debug("File Read AndX [" + netFile.getFileId() + "] : Size=" + maxCount + " ,Pos=" + offset);
872
873         // Read data from the file
874

875         byte[] buf = outPkt.getBuffer();
876         int dataPos = 0;
877         int rdlen = 0;
878
879         try
880         {
881
882             // Access the disk interface that is associated with the shared device
883

884             DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
885
886             // Set the returned parameter count so that the byte offset can be calculated
887

888             outPkt.setParameterCount(12);
889             dataPos = outPkt.getByteOffset();
890             // dataPos = ( dataPos + 3) & 0xFFFFFFFC; // longword align the data
891

892             // Check if the requested data length will fit into the buffer
893

894             int dataLen = buf.length - dataPos;
895             if (dataLen < maxCount)
896                 maxCount = dataLen;
897
898             // Read from the file
899

900             rdlen = disk.readFile(m_sess, conn, netFile, buf, dataPos, maxCount, offset);
901         }
902         catch (InvalidDeviceInterfaceException ex)
903         {
904
905             // Failed to get/initialize the disk interface
906

907             m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
908             return;
909         }
910         catch (AccessDeniedException ex)
911         {
912
913             // No access to file, or file is a directory
914
//
915
// Debug
916

917             if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO))
918                 logger.debug("File Read Error [" + netFile.getFileId() + "] : " + ex.toString());
919
920             // Failed to read the file
921

922             m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
923             return;
924         }
925         catch (java.io.IOException JavaDoc ex)
926         {
927
928             // Debug
929

930             logger.error("File Read Error [" + netFile.getFileId() + "] : ", ex);
931
932             // Failed to read the file
933

934             m_sess.sendErrorResponseSMB(SMBStatus.HRDReadFault, SMBStatus.ErrHrd);
935             return;
936         }
937
938         // Return the data block
939

940         outPkt.setAndXCommand(0xFF); // no chained command
941
outPkt.setParameter(1, 0);
942         outPkt.setParameter(2, 0); // bytes remaining, for pipes only
943
outPkt.setParameter(3, 0); // data compaction mode
944
outPkt.setParameter(4, 0); // reserved
945
outPkt.setParameter(5, rdlen); // data length
946
outPkt.setParameter(6, dataPos - RFCNetBIOSProtocol.HEADER_LEN);
947         // offset to data
948

949         // Clear the reserved parameters
950

951         for (int i = 7; i < 12; i++)
952             outPkt.setParameter(i, 0);
953
954         // Set the byte count
955

956         outPkt.setByteCount((dataPos + rdlen) - outPkt.getByteOffset());
957
958         // Send the read andX response
959

960         m_sess.sendResponseSMB(outPkt);
961     }
962
963     /**
964      * Rename a file.
965      *
966      * @param outPkt SMBSrvPacket
967      * @exception java.io.IOException If an I/O error occurs
968      * @exception SMBSrvException If an SMB protocol error occurs
969      */

970     protected void procRenameFile(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
971     {
972
973         // Check that the received packet looks like a valid rename file request
974

975         if (m_smbPkt.checkPacketIsValid(1, 4) == false)
976         {
977             m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
978             return;
979         }
980
981         // Get the tree id from the received packet and validate that it is a valid
982
// connection id.
983

984         int treeId = m_smbPkt.getTreeId();
985         TreeConnection conn = m_sess.findConnection(treeId);
986
987         if (conn == null)
988         {
989             m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
990             return;
991         }
992
993         // Check if the user has the required access permission
994

995         if (conn.hasWriteAccess() == false)
996         {
997
998             // User does not have the required access rights
999

1000            m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
1001            return;
1002        }
1003
1004        // Get the Unicode flag
1005

1006        boolean isUni = m_smbPkt.isUnicode();
1007
1008        // Read the data block
1009

1010        m_smbPkt.resetBytePointer();
1011
1012        // Extract the old file name
1013

1014        if (m_smbPkt.unpackByte() != DataType.ASCII)
1015        {
1016            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1017            return;
1018        }
1019
1020        String JavaDoc oldName = m_smbPkt.unpackString(isUni);
1021        if (oldName == null)
1022        {
1023            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1024            return;
1025        }
1026
1027        // Extract the new file name
1028

1029        if (m_smbPkt.unpackByte() != DataType.ASCII)
1030        {
1031            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1032            return;
1033        }
1034
1035        String JavaDoc newName = m_smbPkt.unpackString(isUni);
1036        if (oldName == null)
1037        {
1038            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1039            return;
1040        }
1041
1042        // Debug
1043

1044        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
1045            logger.debug("File Rename [" + treeId + "] old name=" + oldName + ", new name=" + newName);
1046
1047        // Access the disk interface and rename the requested file
1048

1049        int fid;
1050        NetworkFile netFile = null;
1051
1052        try
1053        {
1054
1055            // Access the disk interface that is associated with the shared device
1056

1057            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
1058
1059            // Rename the requested file
1060

1061            disk.renameFile(m_sess, conn, oldName, newName);
1062        }
1063        catch (InvalidDeviceInterfaceException ex)
1064        {
1065
1066            // Failed to get/initialize the disk interface
1067

1068            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1069            return;
1070        }
1071        catch (java.io.IOException JavaDoc ex)
1072        {
1073
1074            // Failed to open the file
1075

1076            m_sess.sendErrorResponseSMB(SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
1077            return;
1078        }
1079
1080        // Build the rename file response
1081

1082        outPkt.setParameterCount(0);
1083        outPkt.setByteCount(0);
1084
1085        // Send the response packet
1086

1087        m_sess.sendResponseSMB(outPkt);
1088    }
1089
1090    /**
1091     * Process the SMB session setup request.
1092     *
1093     * @param outPkt Response SMB packet.
1094     */

1095    protected void procSessionSetup(SMBSrvPacket outPkt) throws SMBSrvException, IOException JavaDoc,
1096            TooManyConnectionsException
1097    {
1098
1099        // Extract the client details from the session setup request
1100

1101        int dataPos = m_smbPkt.getByteOffset();
1102        int dataLen = m_smbPkt.getByteCount();
1103        byte[] buf = m_smbPkt.getBuffer();
1104
1105        // Extract the session details
1106

1107        int maxBufSize = m_smbPkt.getParameter(2);
1108        int maxMpx = m_smbPkt.getParameter(3);
1109        int vcNum = m_smbPkt.getParameter(4);
1110
1111        // Extract the password string
1112

1113        byte[] pwd = null;
1114        int pwdLen = m_smbPkt.getParameter(7);
1115
1116        if (pwdLen > 0)
1117        {
1118            pwd = new byte[pwdLen];
1119            for (int i = 0; i < pwdLen; i++)
1120                pwd[i] = buf[dataPos + i];
1121            dataPos += pwdLen;
1122            dataLen -= pwdLen;
1123        }
1124
1125        // Extract the user name string
1126

1127        String JavaDoc user = DataPacker.getString(buf, dataPos, dataLen);
1128        if (user == null)
1129        {
1130            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1131            return;
1132        }
1133        else
1134        {
1135
1136            // Update the buffer pointers
1137

1138            dataLen -= user.length() + 1;
1139            dataPos += user.length() + 1;
1140        }
1141
1142        // Extract the clients primary domain name string
1143

1144        String JavaDoc domain = "";
1145
1146        if (dataLen > 0)
1147        {
1148
1149            // Extract the callers domain name
1150

1151            domain = DataPacker.getString(buf, dataPos, dataLen);
1152            if (domain == null)
1153            {
1154                m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1155                return;
1156            }
1157            else
1158            {
1159
1160                // Update the buffer pointers
1161

1162                dataLen -= domain.length() + 1;
1163                dataPos += domain.length() + 1;
1164            }
1165        }
1166
1167        // Extract the clients native operating system
1168

1169        String JavaDoc clientOS = "";
1170
1171        if (dataLen > 0)
1172        {
1173
1174            // Extract the callers operating system name
1175

1176            clientOS = DataPacker.getString(buf, dataPos, dataLen);
1177            if (clientOS == null)
1178            {
1179                m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1180                return;
1181            }
1182        }
1183
1184        // DEBUG
1185

1186        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
1187            logger.debug("Session setup from user=" + user + ", password=" + pwd + ", domain=" + domain + ", os="
1188                    + clientOS + ", VC=" + vcNum + ", maxBuf=" + maxBufSize + ", maxMpx=" + maxMpx);
1189
1190        // Store the client maximum buffer size and maximum multiplexed requests count
1191

1192        m_sess.setClientMaximumBufferSize(maxBufSize);
1193        m_sess.setClientMaximumMultiplex(maxMpx);
1194
1195        // Create the client information and store in the session
1196

1197        ClientInfo client = new ClientInfo(user, pwd);
1198        client.setDomain(domain);
1199        client.setOperatingSystem(clientOS);
1200        if (m_sess.hasRemoteAddress())
1201            client.setClientAddress(m_sess.getRemoteAddress().getHostAddress());
1202
1203        if (m_sess.getClientInformation() == null)
1204        {
1205
1206            // Set the session client details
1207

1208            m_sess.setClientInformation(client);
1209        }
1210        else
1211        {
1212
1213            // Get the current client details from the session
1214

1215            ClientInfo curClient = m_sess.getClientInformation();
1216
1217            if (curClient.getUserName() == null || curClient.getUserName().length() == 0)
1218            {
1219
1220                // Update the client information
1221

1222                m_sess.setClientInformation(client);
1223            }
1224            else
1225            {
1226
1227                // DEBUG
1228

1229                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
1230                    logger.debug("Session already has client information set");
1231            }
1232        }
1233
1234        // Authenticate the user, if the server is using user mode security
1235

1236        SrvAuthenticator auth = getSession().getSMBServer().getAuthenticator();
1237        boolean isGuest = false;
1238
1239        if (auth != null && auth.getAccessMode() == SrvAuthenticator.USER_MODE)
1240        {
1241
1242            // Validate the user
1243

1244            int sts = auth.authenticateUser(client, m_sess, SrvAuthenticator.LANMAN);
1245            if (sts > 0 && (sts & SrvAuthenticator.AUTH_GUEST) != 0)
1246                isGuest = true;
1247            else if (sts != SrvAuthenticator.AUTH_ALLOW)
1248            {
1249
1250                // Invalid user, reject the session setup request
1251

1252                m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
1253                return;
1254            }
1255        }
1256
1257        // Set the guest flag for the client and logged on status
1258

1259        client.setGuest(isGuest);
1260        getSession().setLoggedOn(true);
1261
1262        // Build the session setup response SMB
1263

1264        outPkt.setParameterCount(3);
1265        outPkt.setParameter(0, 0); // No chained response
1266
outPkt.setParameter(1, 0); // Offset to chained response
1267
outPkt.setParameter(2, isGuest ? 1 : 0);
1268        outPkt.setByteCount(0);
1269
1270        outPkt.setTreeId(0);
1271        outPkt.setUserId(0);
1272
1273        // Set the various flags
1274

1275        // outPkt.setFlags( SMBSrvPacket.FLG_CASELESS);
1276
int flags = outPkt.getFlags();
1277        flags &= ~SMBSrvPacket.FLG_CASELESS;
1278        outPkt.setFlags(flags);
1279        outPkt.setFlags2(SMBSrvPacket.FLG2_LONGFILENAMES);
1280
1281        // Pack the OS, dialect and domain name strings.
1282

1283        int pos = outPkt.getByteOffset();
1284        buf = outPkt.getBuffer();
1285
1286        pos = DataPacker.putString("Java", buf, pos, true);
1287        pos = DataPacker.putString("JLAN Server " + m_sess.getServer().isVersion(), buf, pos, true);
1288        pos = DataPacker.putString(m_sess.getServer().getConfiguration().getDomainName(), buf, pos, true);
1289
1290        outPkt.setByteCount(pos - outPkt.getByteOffset());
1291
1292        // Check if there is a chained command, or commands
1293

1294        if (m_smbPkt.hasAndXCommand() && dataPos < m_smbPkt.getReceivedLength())
1295        {
1296
1297            // Process any chained commands, AndX
1298

1299            pos = procAndXCommands(outPkt);
1300        }
1301        else
1302        {
1303
1304            // Indicate that there are no chained replies
1305

1306            outPkt.setAndXCommand(SMBSrvPacket.NO_ANDX_CMD);
1307        }
1308
1309        // Send the negotiate response
1310

1311        m_sess.sendResponseSMB(outPkt, pos);
1312
1313        // Update the session state
1314

1315        m_sess.setState(SMBSrvSessionState.SMBSESSION);
1316
1317        // Notify listeners that a user has logged onto the session
1318

1319        m_sess.getSMBServer().sessionLoggedOn(m_sess);
1320    }
1321
1322    /**
1323     * Process a transact2 request. The transact2 can contain many different sub-requests.
1324     *
1325     * @param outPkt SMBSrvPacket
1326     * @exception SMBSrvException If an SMB protocol error occurs
1327     */

1328    protected void procTransact2(SMBSrvPacket outPkt) throws IOException JavaDoc, SMBSrvException
1329    {
1330
1331        // Check that we received enough parameters for a transact2 request
1332

1333        if (m_smbPkt.checkPacketIsValid(15, 0) == false)
1334        {
1335
1336            // Not enough parameters for a valid transact2 request
1337

1338            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.NTErr);
1339            return;
1340        }
1341
1342        // Get the tree id from the received packet and validate that it is a valid
1343
// connection id.
1344

1345        int treeId = m_smbPkt.getTreeId();
1346        TreeConnection conn = m_sess.findConnection(treeId);
1347
1348        if (conn == null)
1349        {
1350            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.NTErr);
1351            return;
1352        }
1353
1354        // Check if the user has the required access permission
1355

1356        if (conn.hasReadAccess() == false)
1357        {
1358
1359            // User does not have the required access rights
1360

1361            m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
1362            return;
1363        }
1364
1365        // Create a transact packet using the received SMB packet
1366

1367        SMBSrvTransPacket tranPkt = new SMBSrvTransPacket(m_smbPkt.getBuffer());
1368
1369        // Create a transact buffer to hold the transaction setup, parameter and data blocks
1370

1371        SrvTransactBuffer transBuf = null;
1372        int subCmd = tranPkt.getSubFunction();
1373
1374        if (tranPkt.getTotalParameterCount() == tranPkt.getParameterBlockCount()
1375                && tranPkt.getTotalDataCount() == tranPkt.getDataBlockCount())
1376        {
1377
1378            // Create a transact buffer using the packet buffer, the entire request is contained in
1379
// a single
1380
// packet
1381

1382            transBuf = new SrvTransactBuffer(tranPkt);
1383        }
1384        else
1385        {
1386
1387            // Create a transact buffer to hold the multiple transact request parameter/data blocks
1388

1389            transBuf = new SrvTransactBuffer(tranPkt.getSetupCount(), tranPkt.getTotalParameterCount(), tranPkt
1390                    .getTotalDataCount());
1391            transBuf.setType(tranPkt.getCommand());
1392            transBuf.setFunction(subCmd);
1393
1394            // Append the setup, parameter and data blocks to the transaction data
1395

1396            byte[] buf = tranPkt.getBuffer();
1397
1398            transBuf.appendSetup(buf, tranPkt.getSetupOffset(), tranPkt.getSetupCount() * 2);
1399            transBuf.appendParameter(buf, tranPkt.getParameterBlockOffset(), tranPkt.getParameterBlockCount());
1400            transBuf.appendData(buf, tranPkt.getDataBlockOffset(), tranPkt.getDataBlockCount());
1401        }
1402
1403        // Set the return data limits for the transaction
1404

1405        transBuf.setReturnLimits(tranPkt.getMaximumReturnSetupCount(), tranPkt.getMaximumReturnParameterCount(),
1406                tranPkt.getMaximumReturnDataCount());
1407
1408        // Check for a multi-packet transaction, for a multi-packet transaction we just acknowledge
1409
// the receive with
1410
// an empty response SMB
1411

1412        if (transBuf.isMultiPacket())
1413        {
1414
1415            // Save the partial transaction data
1416

1417            m_sess.setTransaction(transBuf);
1418
1419            // Send an intermediate acknowedgement response
1420

1421            m_sess.sendSuccessResponseSMB();
1422            return;
1423        }
1424
1425        // Check if the transaction is on the IPC$ named pipe, the request requires special
1426
// processing
1427

1428        if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
1429        {
1430            IPCHandler.procTransaction(transBuf, m_sess, outPkt);
1431            return;
1432        }
1433
1434        // DEBUG
1435

1436        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
1437            logger.debug("Transaction [" + treeId + "] tbuf=" + transBuf);
1438
1439        // Process the transaction buffer
1440

1441        processTransactionBuffer(transBuf, outPkt);
1442    }
1443
1444    /**
1445     * Process a transact2 secondary request.
1446     *
1447     * @param outPkt SMBSrvPacket
1448     * @exception SMBSrvException If an SMB protocol error occurs
1449     */

1450    protected void procTransact2Secondary(SMBSrvPacket outPkt) throws IOException JavaDoc, SMBSrvException
1451    {
1452
1453        // Check that we received enough parameters for a transact2 request
1454

1455        if (m_smbPkt.checkPacketIsValid(8, 0) == false)
1456        {
1457
1458            // Not enough parameters for a valid transact2 request
1459

1460            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.NTErr);
1461            return;
1462        }
1463
1464        // Get the tree id from the received packet and validate that it is a valid
1465
// connection id.
1466

1467        int treeId = m_smbPkt.getTreeId();
1468        TreeConnection conn = m_sess.findConnection(treeId);
1469
1470        if (conn == null)
1471        {
1472            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.NTErr);
1473            return;
1474        }
1475
1476        // Check if the user has the required access permission
1477

1478        if (conn.hasReadAccess() == false)
1479        {
1480
1481            // User does not have the required access rights
1482

1483            m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
1484            return;
1485        }
1486
1487        // Check if there is an active transaction, and it is an NT transaction
1488

1489        if (m_sess.hasTransaction() == false
1490                || (m_sess.getTransaction().isType() == PacketType.Transaction && m_smbPkt.getCommand() != PacketType.TransactionSecond)
1491                || (m_sess.getTransaction().isType() == PacketType.Transaction2 && m_smbPkt.getCommand() != PacketType.Transaction2Second))
1492        {
1493
1494            // No transaction to continue, or packet does not match the existing transaction, return
1495
// an error
1496

1497            m_sess.sendErrorResponseSMB(SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
1498            return;
1499        }
1500
1501        // Create an NT transaction using the received packet
1502

1503        SMBSrvTransPacket tpkt = new SMBSrvTransPacket(m_smbPkt.getBuffer());
1504        byte[] buf = tpkt.getBuffer();
1505        SrvTransactBuffer transBuf = m_sess.getTransaction();
1506
1507        // Append the parameter data to the transaction buffer, if any
1508

1509        int plen = tpkt.getSecondaryParameterBlockCount();
1510        if (plen > 0)
1511        {
1512
1513            // Append the data to the parameter buffer
1514

1515            DataBuffer paramBuf = transBuf.getParameterBuffer();
1516            paramBuf.appendData(buf, tpkt.getSecondaryParameterBlockOffset(), plen);
1517        }
1518
1519        // Append the data block to the transaction buffer, if any
1520

1521        int dlen = tpkt.getSecondaryDataBlockCount();
1522        if (dlen > 0)
1523        {
1524
1525            // Append the data to the data buffer
1526

1527            DataBuffer dataBuf = transBuf.getDataBuffer();
1528            dataBuf.appendData(buf, tpkt.getSecondaryDataBlockOffset(), dlen);
1529        }
1530
1531        // Debug
1532

1533        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
1534            logger.debug("Transaction Secondary [" + treeId + "] paramLen=" + plen + ", dataLen=" + dlen);
1535
1536        // Check if the transaction has been received or there are more sections to be received
1537

1538        int totParam = tpkt.getTotalParameterCount();
1539        int totData = tpkt.getTotalDataCount();
1540
1541        int paramDisp = tpkt.getParameterBlockDisplacement();
1542        int dataDisp = tpkt.getDataBlockDisplacement();
1543
1544        if ((paramDisp + plen) == totParam && (dataDisp + dlen) == totData)
1545        {
1546
1547            // Debug
1548

1549            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
1550                logger.debug("Transaction complete, processing ...");
1551
1552            // Clear the in progress transaction
1553

1554            m_sess.setTransaction(null);
1555
1556            // Check if the transaction is on the IPC$ named pipe, the request requires special
1557
// processing
1558

1559            if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
1560            {
1561                IPCHandler.procTransaction(transBuf, m_sess, outPkt);
1562                return;
1563            }
1564
1565            // DEBUG
1566

1567            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
1568                logger.debug("Transaction second [" + treeId + "] tbuf=" + transBuf);
1569
1570            // Process the transaction
1571

1572            processTransactionBuffer(transBuf, outPkt);
1573        }
1574        else
1575        {
1576
1577            // There are more transaction parameter/data sections to be received, return an
1578
// intermediate response
1579

1580            m_sess.sendSuccessResponseSMB();
1581        }
1582    }
1583
1584    /**
1585     * Process a transaction buffer
1586     *
1587     * @param tbuf TransactBuffer
1588     * @param outPkt SMBSrvPacket
1589     * @exception IOException If a network error occurs
1590     * @exception SMBSrvException If an SMB error occurs
1591     */

1592    private final void processTransactionBuffer(SrvTransactBuffer tbuf, SMBSrvPacket outPkt) throws IOException JavaDoc,
1593            SMBSrvException
1594    {
1595
1596        // Get the transaction sub-command code and validate
1597

1598        switch (tbuf.getFunction())
1599        {
1600
1601        // Start a file search
1602

1603        case PacketType.Trans2FindFirst:
1604            procTrans2FindFirst(tbuf, outPkt);
1605            break;
1606
1607        // Continue a file search
1608

1609        case PacketType.Trans2FindNext:
1610            procTrans2FindNext(tbuf, outPkt);
1611            break;
1612
1613        // Query file system information
1614

1615        case PacketType.Trans2QueryFileSys:
1616            procTrans2QueryFileSys(tbuf, outPkt);
1617            break;
1618
1619        // Query path
1620

1621        case PacketType.Trans2QueryPath:
1622            procTrans2QueryPath(tbuf, outPkt);
1623            break;
1624
1625        // Unknown transact2 command
1626

1627        default:
1628
1629            // Return an unrecognized command error
1630

1631            m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
1632            break;
1633        }
1634    }
1635
1636    /**
1637     * Process a transact2 file search request.
1638     *
1639     * @param tbuf Transaction request details
1640     * @param outPkt Packet to use for the reply.
1641     * @exception java.io.IOException If an I/O error occurs
1642     * @exception SMBSrvException If an SMB protocol error occurs
1643     */

1644    protected final void procTrans2FindFirst(SrvTransactBuffer tbuf, SMBSrvPacket outPkt) throws java.io.IOException JavaDoc,
1645            SMBSrvException
1646    {
1647
1648        // Get the tree connection details
1649

1650        int treeId = m_smbPkt.getTreeId();
1651        TreeConnection conn = m_sess.findConnection(treeId);
1652
1653        if (conn == null)
1654        {
1655            m_sess.sendErrorResponseSMB(SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv);
1656            return;
1657        }
1658
1659        // Check if the user has the required access permission
1660

1661        if (conn.hasReadAccess() == false)
1662        {
1663
1664            // User does not have the required access rights
1665

1666            m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
1667            return;
1668        }
1669
1670        // Get the search parameters
1671

1672        DataBuffer paramBuf = tbuf.getParameterBuffer();
1673
1674        int srchAttr = paramBuf.getShort();
1675        int maxFiles = paramBuf.getShort();
1676        int srchFlag = paramBuf.getShort();
1677        int infoLevl = paramBuf.getShort();
1678        paramBuf.skipBytes(4);
1679
1680        String JavaDoc srchPath = paramBuf.getString(tbuf.isUnicode());
1681
1682        // Check if the search path is valid
1683

1684        if (srchPath == null || srchPath.length() == 0)
1685        {
1686
1687            // Invalid search request
1688

1689            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1690            return;
1691        }
1692
1693        // Access the shared device disk interface
1694

1695        SearchContext ctx = null;
1696        DiskInterface disk = null;
1697        int searchId = -1;
1698
1699        try
1700        {
1701
1702            // Access the disk interface
1703

1704            disk = (DiskInterface) conn.getSharedDevice().getInterface();
1705
1706            // Allocate a search slot for the new search
1707

1708            searchId = m_sess.allocateSearchSlot();
1709            if (searchId == -1)
1710            {
1711
1712                // Failed to allocate a slot for the new search
1713

1714                m_sess.sendErrorResponseSMB(SMBStatus.SRVNoResourcesAvailable, SMBStatus.ErrSrv);
1715                return;
1716            }
1717
1718            // Debug
1719

1720            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
1721                logger.debug("Start trans search [" + searchId + "] - " + srchPath + ", attr=0x"
1722                        + Integer.toHexString(srchAttr) + ", maxFiles=" + maxFiles + ", infoLevel=" + infoLevl
1723                        + ", flags=0x" + Integer.toHexString(srchFlag));
1724
1725            // Start a new search
1726

1727            ctx = disk.startSearch(m_sess, conn, srchPath, srchAttr);
1728            if (ctx != null)
1729            {
1730
1731                // Store details of the search in the context
1732

1733                ctx.setTreeId(treeId);
1734                ctx.setMaximumFiles(maxFiles);
1735            }
1736            else
1737            {
1738
1739                // Failed to start the search, return a no more files error
1740

1741                m_sess.sendErrorResponseSMB(SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
1742                return;
1743            }
1744
1745            // Save the search context
1746

1747            m_sess.setSearchContext(searchId, ctx);
1748
1749            // Create the reply transact buffer
1750

1751            SrvTransactBuffer replyBuf = new SrvTransactBuffer(tbuf);
1752            DataBuffer dataBuf = replyBuf.getDataBuffer();
1753
1754            // Determine the maximum return data length
1755

1756            int maxLen = replyBuf.getReturnDataLimit();
1757
1758            // Check if resume keys are required
1759

1760            boolean resumeReq = (srchFlag & FindFirstNext.ReturnResumeKey) != 0 ? true : false;
1761
1762            // Loop until we have filled the return buffer or there are no more files to return
1763

1764            int fileCnt = 0;
1765            int packLen = 0;
1766            int lastNameOff = 0;
1767
1768            boolean pktDone = false;
1769            boolean searchDone = false;
1770
1771            FileInfo info = new FileInfo();
1772
1773            while (pktDone == false && fileCnt < maxFiles)
1774            {
1775
1776                // Get file information from the search
1777

1778                if (ctx.nextFileInfo(info) == false)
1779                {
1780
1781                    // No more files
1782

1783                    pktDone = true;
1784                    searchDone = true;
1785                }
1786
1787                // Check if the file information will fit into the return buffer
1788

1789                else if (FindInfoPacker.calcInfoSize(info, infoLevl, false, true) <= maxLen)
1790                {
1791
1792                    // Pack a dummy resume key, if required
1793

1794                    if (resumeReq)
1795                    {
1796                        dataBuf.putZeros(4);
1797                        maxLen -= 4;
1798                    }
1799
1800                    // Save the offset to the last file information structure
1801

1802                    lastNameOff = dataBuf.getPosition();
1803
1804                    // Pack the file information
1805

1806                    packLen = FindInfoPacker.packInfo(info, dataBuf, infoLevl, tbuf.isUnicode());
1807
1808                    // Update the file count for this packet
1809

1810                    fileCnt++;
1811
1812                    // Recalculate the remaining buffer space
1813

1814                    maxLen -= packLen;
1815                }
1816                else
1817                {
1818
1819                    // Set the search restart point
1820

1821                    ctx.restartAt(info);
1822
1823                    // No more buffer space
1824

1825                    pktDone = true;
1826                }
1827            }
1828
1829            // Pack the parameter block
1830

1831            paramBuf = replyBuf.getParameterBuffer();
1832
1833            paramBuf.putShort(searchId);
1834            paramBuf.putShort(fileCnt);
1835            paramBuf.putShort(ctx.hasMoreFiles() ? 0 : 1);
1836            paramBuf.putShort(0);
1837            paramBuf.putShort(lastNameOff);
1838
1839            // Send the transaction response
1840

1841            SMBSrvTransPacket tpkt = new SMBSrvTransPacket(outPkt.getBuffer());
1842            tpkt.doTransactionResponse(m_sess, replyBuf);
1843
1844            // Debug
1845

1846            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
1847                logger.debug("Search [" + searchId + "] Returned " + fileCnt + " files, moreFiles="
1848                        + ctx.hasMoreFiles());
1849
1850            // Check if the search is complete
1851

1852            if (searchDone == true)
1853            {
1854
1855                // Debug
1856

1857                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
1858                    logger.debug("End start search [" + searchId + "] (Search complete)");
1859
1860                // Release the search context
1861

1862                m_sess.deallocateSearchSlot(searchId);
1863            }
1864        }
1865        catch (FileNotFoundException JavaDoc ex)
1866        {
1867
1868            // Deallocate the search
1869

1870            if (searchId != -1)
1871                m_sess.deallocateSearchSlot(searchId);
1872
1873            // Search path does not exist
1874

1875            m_sess.sendErrorResponseSMB(SMBStatus.DOSNoMoreFiles, SMBStatus.ErrDos);
1876            // m_sess.sendErrorResponseSMB(SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
1877
}
1878        catch (InvalidDeviceInterfaceException ex)
1879        {
1880
1881            // Deallocate the search
1882

1883            if (searchId != -1)
1884                m_sess.deallocateSearchSlot(searchId);
1885
1886            // Failed to get/initialize the disk interface
1887

1888            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1889        }
1890        catch (UnsupportedInfoLevelException ex)
1891        {
1892
1893            // Deallocate the search
1894

1895            if (searchId != -1)
1896                m_sess.deallocateSearchSlot(searchId);
1897
1898            // Requested information level is not supported
1899

1900            m_sess.sendErrorResponseSMB(SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
1901        }
1902    }
1903
1904    /**
1905     * Process a transact2 file search continue request.
1906     *
1907     * @param tbuf Transaction request details
1908     * @param outPkt SMBSrvPacket
1909     * @exception java.io.IOException If an I/O error occurs
1910     * @exception SMBSrvException If an SMB protocol error occurs
1911     */

1912    protected final void procTrans2FindNext(SrvTransactBuffer tbuf, SMBSrvPacket outPkt) throws java.io.IOException JavaDoc,
1913            SMBSrvException
1914    {
1915
1916        // Get the tree connection details
1917

1918        int treeId = m_smbPkt.getTreeId();
1919        TreeConnection conn = m_sess.findConnection(treeId);
1920
1921        if (conn == null)
1922        {
1923            m_sess.sendErrorResponseSMB(SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv);
1924            return;
1925        }
1926
1927        // Check if the user has the required access permission
1928

1929        if (conn.hasReadAccess() == false)
1930        {
1931
1932            // User does not have the required access rights
1933

1934            m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
1935            return;
1936        }
1937
1938        // Get the search parameters
1939

1940        DataBuffer paramBuf = tbuf.getParameterBuffer();
1941
1942        int searchId = paramBuf.getShort();
1943        int maxFiles = paramBuf.getShort();
1944        int infoLevl = paramBuf.getShort();
1945        int reskey = paramBuf.getInt();
1946        int srchFlag = paramBuf.getShort();
1947
1948        String JavaDoc resumeName = paramBuf.getString(tbuf.isUnicode());
1949
1950        // Access the shared device disk interface
1951

1952        SearchContext ctx = null;
1953        DiskInterface disk = null;
1954
1955        try
1956        {
1957
1958            // Access the disk interface
1959

1960            disk = (DiskInterface) conn.getSharedDevice().getInterface();
1961
1962            // Retrieve the search context
1963

1964            ctx = m_sess.getSearchContext(searchId);
1965            if (ctx == null)
1966            {
1967
1968                // DEBUG
1969

1970                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
1971                    logger.debug("Search context null - [" + searchId + "]");
1972
1973                // Invalid search handle
1974

1975                m_sess.sendErrorResponseSMB(SMBStatus.DOSNoMoreFiles, SMBStatus.ErrDos);
1976                return;
1977            }
1978
1979            // Debug
1980

1981            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
1982                logger.debug("Continue search [" + searchId + "] - " + resumeName + ", maxFiles=" + maxFiles
1983                        + ", infoLevel=" + infoLevl + ", flags=0x" + Integer.toHexString(srchFlag));
1984
1985            // Create the reply transaction buffer
1986

1987            SrvTransactBuffer replyBuf = new SrvTransactBuffer(tbuf);
1988            DataBuffer dataBuf = replyBuf.getDataBuffer();
1989
1990            // Determine the maximum return data length
1991

1992            int maxLen = replyBuf.getReturnDataLimit();
1993
1994            // Check if resume keys are required
1995

1996            boolean resumeReq = (srchFlag & FindFirstNext.ReturnResumeKey) != 0 ? true : false;
1997
1998            // Loop until we have filled the return buffer or there are no more files to return
1999

2000            int fileCnt = 0;
2001            int packLen = 0;
2002            int lastNameOff = 0;
2003
2004            boolean pktDone = false;
2005            boolean searchDone = false;
2006
2007            FileInfo info = new FileInfo();
2008
2009            while (pktDone == false && fileCnt < maxFiles)
2010            {
2011
2012                // Get file information from the search
2013

2014                if (ctx.nextFileInfo(info) == false)
2015                {
2016
2017                    // No more files
2018

2019                    pktDone = true;
2020                    searchDone = true;
2021                }
2022
2023                // Check if the file information will fit into the return buffer
2024

2025                else if (FindInfoPacker.calcInfoSize(info, infoLevl, false, true) <= maxLen)
2026                {
2027
2028                    // Pack a dummy resume key, if required
2029

2030                    if (resumeReq)
2031                        dataBuf.putZeros(4);
2032
2033                    // Save the offset to the last file information structure
2034

2035                    lastNameOff = dataBuf.getPosition();
2036
2037                    // Pack the file information
2038

2039                    packLen = FindInfoPacker.packInfo(info, dataBuf, infoLevl, tbuf.isUnicode());
2040
2041                    // Update the file count for this packet
2042

2043                    fileCnt++;
2044
2045                    // Recalculate the remaining buffer space
2046

2047                    maxLen -= packLen;
2048                }
2049                else
2050                {
2051
2052                    // Set the search restart point
2053

2054                    ctx.restartAt(info);
2055
2056                    // No more buffer space
2057

2058                    pktDone = true;
2059                }
2060            }
2061
2062            // Pack the parameter block
2063

2064            paramBuf = replyBuf.getParameterBuffer();
2065
2066            paramBuf.putShort(fileCnt);
2067            paramBuf.putShort(ctx.hasMoreFiles() ? 0 : 1);
2068            paramBuf.putShort(0);
2069            paramBuf.putShort(lastNameOff);
2070
2071            // Send the transaction response
2072

2073            SMBSrvTransPacket tpkt = new SMBSrvTransPacket(outPkt.getBuffer());
2074            tpkt.doTransactionResponse(m_sess, replyBuf);
2075
2076            // Debug
2077

2078            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
2079                logger.debug("Search [" + searchId + "] Returned " + fileCnt + " files, moreFiles="
2080                        + ctx.hasMoreFiles());
2081
2082            // Check if the search is complete
2083

2084            if (searchDone == true)
2085            {
2086
2087                // Debug
2088

2089                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
2090                    logger.debug("End start search [" + searchId + "] (Search complete)");
2091
2092                // Release the search context
2093

2094                m_sess.deallocateSearchSlot(searchId);
2095            }
2096        }
2097        catch (FileNotFoundException JavaDoc ex)
2098        {
2099
2100            // Deallocate the search
2101

2102            if (searchId != -1)
2103                m_sess.deallocateSearchSlot(searchId);
2104
2105            // Search path does not exist
2106

2107            m_sess.sendErrorResponseSMB(SMBStatus.DOSNoMoreFiles, SMBStatus.ErrDos);
2108            // m_sess.sendErrorResponseSMB(SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
2109
}
2110        catch (InvalidDeviceInterfaceException ex)
2111        {
2112
2113            // Deallocate the search
2114

2115            if (searchId != -1)
2116                m_sess.deallocateSearchSlot(searchId);
2117
2118            // Failed to get/initialize the disk interface
2119

2120            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2121        }
2122        catch (UnsupportedInfoLevelException ex)
2123        {
2124
2125            // Deallocate the search
2126

2127            if (searchId != -1)
2128                m_sess.deallocateSearchSlot(searchId);
2129
2130            // Requested information level is not supported
2131

2132            m_sess.sendErrorResponseSMB(SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
2133        }
2134    }
2135
2136    /**
2137     * Process a transact2 file system query request.
2138     *
2139     * @param tbuf Transaction request details
2140     * @param outPkt SMBSrvPacket
2141     * @exception java.io.IOException If an I/O error occurs
2142     * @exception SMBSrvException If an SMB protocol error occurs
2143     */

2144    protected final void procTrans2QueryFileSys(SrvTransactBuffer tbuf, SMBSrvPacket outPkt)
2145            throws java.io.IOException JavaDoc, SMBSrvException
2146    {
2147
2148        // Get the tree connection details
2149

2150        int treeId = m_smbPkt.getTreeId();
2151        TreeConnection conn = m_sess.findConnection(treeId);
2152
2153        if (conn == null)
2154        {
2155            m_sess.sendErrorResponseSMB(SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv);
2156            return;
2157        }
2158
2159        // Check if the user has the required access permission
2160

2161        if (conn.hasReadAccess() == false)
2162        {
2163
2164            // User does not have the required access rights
2165

2166            m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2167            return;
2168        }
2169
2170        // Get the query file system required information level
2171

2172        DataBuffer paramBuf = tbuf.getParameterBuffer();
2173
2174        int infoLevl = paramBuf.getShort();
2175
2176        // Debug
2177

2178        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
2179            logger.debug("Query File System Info - level = 0x" + Integer.toHexString(infoLevl));
2180
2181        // Access the shared device disk interface
2182

2183        try
2184        {
2185
2186            // Access the disk interface and context
2187

2188            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
2189            DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
2190
2191            // Set the return parameter count, so that the data area position can be calculated.
2192

2193            outPkt.setParameterCount(10);
2194
2195            // Pack the disk information into the data area of the transaction reply
2196

2197            byte[] buf = outPkt.getBuffer();
2198            int prmPos = DataPacker.longwordAlign(outPkt.getByteOffset());
2199            int dataPos = prmPos; // no parameters returned
2200

2201            // Create a data buffer using the SMB packet. The response should always fit into a
2202
// single
2203
// reply packet.
2204

2205            DataBuffer replyBuf = new DataBuffer(buf, dataPos, buf.length - dataPos);
2206
2207            // Determine the information level requested
2208

2209            SrvDiskInfo diskInfo = null;
2210            VolumeInfo volInfo = null;
2211
2212            switch (infoLevl)
2213            {
2214
2215            // Standard disk information
2216

2217            case DiskInfoPacker.InfoStandard:
2218
2219                // Get the disk information
2220

2221                diskInfo = getDiskInformation(disk, diskCtx);
2222
2223                // Pack the disk information into the return data packet
2224

2225                DiskInfoPacker.packStandardInfo(diskInfo, replyBuf);
2226                break;
2227
2228            // Volume label information
2229

2230            case DiskInfoPacker.InfoVolume:
2231
2232                // Get the volume label information
2233

2234                volInfo = getVolumeInformation(disk, diskCtx);
2235
2236                // Pack the volume label information
2237

2238                DiskInfoPacker.packVolumeInfo(volInfo, replyBuf, tbuf.isUnicode());
2239                break;
2240
2241            // Full volume information
2242

2243            case DiskInfoPacker.InfoFsVolume:
2244
2245                // Get the volume information
2246

2247                volInfo = getVolumeInformation(disk, diskCtx);
2248
2249                // Pack the volume information
2250

2251                DiskInfoPacker.packFsVolumeInformation(volInfo, replyBuf, tbuf.isUnicode());
2252                break;
2253
2254            // Filesystem size information
2255

2256            case DiskInfoPacker.InfoFsSize:
2257
2258                // Get the disk information
2259

2260                diskInfo = getDiskInformation(disk, diskCtx);
2261
2262                // Pack the disk information into the return data packet
2263

2264                DiskInfoPacker.packFsSizeInformation(diskInfo, replyBuf);
2265                break;
2266
2267            // Filesystem device information
2268

2269            case DiskInfoPacker.InfoFsDevice:
2270                DiskInfoPacker.packFsDevice(0, 0, replyBuf);
2271                break;
2272
2273            // Filesystem attribute information
2274

2275            case DiskInfoPacker.InfoFsAttribute:
2276                DiskInfoPacker.packFsAttribute(0, 255, "JLAN", tbuf.isUnicode(), replyBuf);
2277                break;
2278            }
2279
2280            // Check if any data was packed, if not then the information level is not supported
2281

2282            if (replyBuf.getPosition() == dataPos)
2283            {
2284                m_sess.sendErrorResponseSMB(SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
2285                return;
2286            }
2287
2288            int dataLen = replyBuf.getLength();
2289            SMBSrvTransPacket.initTransactReply(outPkt, 0, prmPos, dataLen, dataPos);
2290            outPkt.setByteCount(replyBuf.getPosition() - outPkt.getByteOffset());
2291
2292            // Send the transact reply
2293

2294            m_sess.sendResponseSMB(outPkt);
2295        }
2296        catch (InvalidDeviceInterfaceException ex)
2297        {
2298
2299            // Failed to get/initialize the disk interface
2300

2301            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2302            return;
2303        }
2304    }
2305
2306    /**
2307     * Process a transact2 query path information request.
2308     *
2309     * @param tbuf Transaction request details
2310     * @param outPkt SMBSrvPacket
2311     * @exception java.io.IOException If an I/O error occurs
2312     * @exception SMBSrvException If an SMB protocol error occurs
2313     */

2314    protected final void procTrans2QueryPath(SrvTransactBuffer tbuf, SMBSrvPacket outPkt) throws java.io.IOException JavaDoc,
2315            SMBSrvException
2316    {
2317
2318        // Get the tree connection details
2319

2320        int treeId = m_smbPkt.getTreeId();
2321        TreeConnection conn = m_sess.findConnection(treeId);
2322
2323        if (conn == null)
2324        {
2325            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.NTErr);
2326            return;
2327        }
2328
2329        // Check if the user has the required access permission
2330

2331        if (conn.hasReadAccess() == false)
2332        {
2333
2334            // User does not have the required access rights
2335

2336            m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2337            return;
2338        }
2339
2340        // Get the query path information level and file/directory name
2341

2342        DataBuffer paramBuf = tbuf.getParameterBuffer();
2343
2344        int infoLevl = paramBuf.getShort();
2345        paramBuf.skipBytes(4);
2346
2347        String JavaDoc path = paramBuf.getString(tbuf.isUnicode());
2348
2349        // Debug
2350

2351        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
2352            logger.debug("Query Path - level = 0x" + Integer.toHexString(infoLevl) + ", path = " + path);
2353
2354        // Access the shared device disk interface
2355

2356        try
2357        {
2358
2359            // Access the disk interface
2360

2361            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
2362
2363            // Set the return parameter count, so that the data area position can be calculated.
2364

2365            outPkt.setParameterCount(10);
2366
2367            // Pack the file information into the data area of the transaction reply
2368

2369            byte[] buf = outPkt.getBuffer();
2370            int prmPos = DataPacker.longwordAlign(outPkt.getByteOffset());
2371            int dataPos = prmPos; // no parameters returned
2372

2373            // Create a data buffer using the SMB packet. The response should always fit into a
2374
// single
2375
// reply packet.
2376

2377            DataBuffer replyBuf = new DataBuffer(buf, dataPos, buf.length - dataPos);
2378
2379            // Get the file information
2380

2381            FileInfo fileInfo = disk.getFileInformation(m_sess, conn, path);
2382
2383            if (fileInfo == null)
2384            {
2385                m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.NTErr);
2386                return;
2387            }
2388
2389            // Pack the file information into the return data packet
2390

2391            int dataLen = QueryInfoPacker.packInfo(fileInfo, replyBuf, infoLevl, true);
2392
2393            // Check if any data was packed, if not then the information level is not supported
2394

2395            if (dataLen == 0)
2396            {
2397                m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.NTErr);
2398                return;
2399            }
2400
2401            SMBSrvTransPacket.initTransactReply(outPkt, 0, prmPos, dataLen, dataPos);
2402            outPkt.setByteCount(replyBuf.getPosition() - outPkt.getByteOffset());
2403
2404            // Send the transact reply
2405

2406            m_sess.sendResponseSMB(outPkt);
2407        }
2408        catch (FileNotFoundException JavaDoc ex)
2409        {
2410
2411            // Requested file does not exist
2412

2413            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.NTErr);
2414            return;
2415        }
2416        catch (InvalidDeviceInterfaceException ex)
2417        {
2418
2419            // Failed to get/initialize the disk interface
2420

2421            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.NTErr);
2422            return;
2423        }
2424        catch (UnsupportedInfoLevelException ex)
2425        {
2426
2427            // Requested information level is not supported
2428

2429            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.NTErr);
2430            return;
2431        }
2432    }
2433
2434    /**
2435     * Process the SMB tree connect request.
2436     *
2437     * @param outPkt Response SMB packet.
2438     * @exception java.io.IOException If an I/O error occurs
2439     * @exception SMBSrvException If an SMB protocol error occurs
2440     * @exception TooManyConnectionsException Too many concurrent connections on this session.
2441     */

2442
2443    protected void procTreeConnectAndX(SMBSrvPacket outPkt) throws SMBSrvException, TooManyConnectionsException,
2444            java.io.IOException JavaDoc
2445    {
2446
2447        // Check that the received packet looks like a valid tree connect request
2448

2449        if (m_smbPkt.checkPacketIsValid(4, 3) == false)
2450        {
2451            m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
2452            return;
2453        }
2454
2455        // Extract the parameters
2456

2457        int flags = m_smbPkt.getParameter(2);
2458        int pwdLen = m_smbPkt.getParameter(3);
2459
2460        // Get the data bytes position and length
2461

2462        int dataPos = m_smbPkt.getByteOffset();
2463        int dataLen = m_smbPkt.getByteCount();
2464        byte[] buf = m_smbPkt.getBuffer();
2465
2466        // Extract the password string
2467

2468        String JavaDoc pwd = null;
2469
2470        if (pwdLen > 0)
2471        {
2472            pwd = new String JavaDoc(buf, dataPos, pwdLen);
2473            dataPos += pwdLen;
2474            dataLen -= pwdLen;
2475        }
2476
2477        // Extract the requested share name, as a UNC path
2478

2479        String JavaDoc uncPath = DataPacker.getString(buf, dataPos, dataLen);
2480        if (uncPath == null)
2481        {
2482            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2483            return;
2484        }
2485
2486        // Extract the service type string
2487

2488        dataPos += uncPath.length() + 1; // null terminated
2489
dataLen -= uncPath.length() + 1; // null terminated
2490

2491        String JavaDoc service = DataPacker.getString(buf, dataPos, dataLen);
2492        if (service == null)
2493        {
2494            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2495            return;
2496        }
2497
2498        // Convert the service type to a shared device type, client may specify '?????' in which
2499
// case we ignore the error.
2500

2501        int servType = ShareType.ServiceAsType(service);
2502        if (servType == ShareType.UNKNOWN && service.compareTo("?????") != 0)
2503        {
2504            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2505            return;
2506        }
2507
2508        // Debug
2509

2510        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TREE))
2511            logger.debug("Tree Connect AndX - " + uncPath + ", " + service);
2512
2513        // Parse the requested share name
2514

2515        PCShare share = null;
2516
2517        try
2518        {
2519            share = new PCShare(uncPath);
2520        }
2521        catch (InvalidUNCPathException ex)
2522        {
2523            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2524            return;
2525        }
2526
2527        // Map the IPC$ share to the admin pipe type
2528

2529        if (servType == ShareType.NAMEDPIPE && share.getShareName().compareTo("IPC$") == 0)
2530            servType = ShareType.ADMINPIPE;
2531
2532        // Find the requested shared device
2533

2534        SharedDevice shareDev = null;
2535
2536        try
2537        {
2538
2539            // Get/create the shared device
2540

2541            shareDev = m_sess.getSMBServer().findShare(share.getNodeName(), share.getShareName(), servType,
2542                    getSession(), true);
2543        }
2544        catch (InvalidUserException ex)
2545        {
2546
2547            // Return a logon failure status
2548

2549            m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2550            return;
2551        }
2552        catch (Exception JavaDoc ex)
2553        {
2554
2555            // Return a general status, bad network name
2556

2557            m_sess.sendErrorResponseSMB(SMBStatus.SRVInvalidNetworkName, SMBStatus.ErrSrv);
2558            return;
2559        }
2560
2561        // Check if the share is valid
2562

2563        if (shareDev == null || (servType != ShareType.UNKNOWN && shareDev.getType() != servType))
2564        {
2565            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
2566            return;
2567        }
2568
2569        // Authenticate the share connection depending upon the security mode the server is running
2570
// under
2571

2572        SrvAuthenticator auth = getSession().getSMBServer().getAuthenticator();
2573        int filePerm = FileAccess.Writeable;
2574
2575        if (auth != null)
2576        {
2577
2578            // Validate the share connection
2579

2580            filePerm = auth.authenticateShareConnect(m_sess.getClientInformation(), shareDev, pwd, m_sess);
2581            if (filePerm < 0)
2582            {
2583
2584                // Invalid share connection request
2585

2586                m_sess.sendErrorResponseSMB(SMBStatus.SRVNoAccessRights, SMBStatus.ErrSrv);
2587                return;
2588            }
2589        }
2590
2591        // Allocate a tree id for the new connection
2592

2593        int treeId = m_sess.addConnection(shareDev);
2594        outPkt.setTreeId(treeId);
2595
2596        // Set the file permission that this user has been granted for this share
2597

2598        TreeConnection tree = m_sess.findConnection(treeId);
2599        tree.setPermission(filePerm);
2600
2601        // Debug
2602

2603        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TREE))
2604            logger.debug("Tree Connect AndX - Allocated Tree Id = " + treeId + ", Permission = "
2605                    + FileAccess.asString(filePerm));
2606
2607        // Build the tree connect response
2608

2609        outPkt.setParameterCount(3);
2610        outPkt.setAndXCommand(0xFF); // no chained reply
2611
outPkt.setParameter(1, 0);
2612        outPkt.setParameter(2, 0);
2613
2614        // Pack the service type
2615

2616        int pos = outPkt.getByteOffset();
2617        pos = DataPacker.putString(ShareType.TypeAsService(shareDev.getType()), buf, pos, true);
2618        outPkt.setByteCount(pos - outPkt.getByteOffset());
2619
2620        // Send the response
2621

2622        m_sess.sendResponseSMB(outPkt);
2623
2624        // Inform the driver that a connection has been opened
2625

2626        if (tree.getInterface() != null)
2627            tree.getInterface().treeOpened(m_sess, tree);
2628    }
2629
2630    /**
2631     * Process the file write request.
2632     *
2633     * @param outPkt SMBSrvPacket
2634     */

2635    protected final void procWriteAndX(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
2636    {
2637
2638        // Check that the received packet looks like a valid write andX request
2639

2640        if (m_smbPkt.checkPacketIsValid(12, 0) == false)
2641        {
2642            m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
2643            return;
2644        }
2645
2646        // Get the tree connection details
2647

2648        int treeId = m_smbPkt.getTreeId();
2649        TreeConnection conn = m_sess.findConnection(treeId);
2650
2651        if (conn == null)
2652        {
2653            m_sess.sendErrorResponseSMB(SMBStatus.SRVInvalidTID, SMBStatus.ErrSrv);
2654            return;
2655        }
2656
2657        // Check if the user has the required access permission
2658

2659        if (conn.hasWriteAccess() == false)
2660        {
2661
2662            // User does not have the required access rights
2663

2664            m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2665            return;
2666        }
2667
2668        // If the connection is to the IPC$ remote admin named pipe pass the request to the IPC
2669
// handler.
2670

2671        if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
2672        {
2673
2674            // Use the IPC$ handler to process the request
2675

2676            IPCHandler.processIPCRequest(m_sess, outPkt);
2677            return;
2678        }
2679
2680        // Extract the write file parameters
2681

2682        int fid = m_smbPkt.getParameter(2);
2683        int offset = m_smbPkt.getParameterLong(3);
2684        int dataLen = m_smbPkt.getParameter(10);
2685        int dataPos = m_smbPkt.getParameter(11) + RFCNetBIOSProtocol.HEADER_LEN;
2686
2687        NetworkFile netFile = conn.findFile(fid);
2688
2689        if (netFile == null)
2690        {
2691            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos);
2692            return;
2693        }
2694
2695        // Debug
2696

2697        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO))
2698            logger.debug("File Write AndX [" + netFile.getFileId() + "] : Size=" + dataLen + " ,Pos=" + offset);
2699
2700        // Write data to the file
2701

2702        byte[] buf = m_smbPkt.getBuffer();
2703        int wrtlen = 0;
2704
2705        // Access the disk interface and write to the file
2706

2707        try
2708        {
2709
2710            // Access the disk interface that is associated with the shared device
2711

2712            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
2713
2714            // Write to the file
2715

2716            wrtlen = disk.writeFile(m_sess, conn, netFile, buf, dataPos, dataLen, offset);
2717        }
2718        catch (InvalidDeviceInterfaceException ex)
2719        {
2720
2721            // Failed to get/initialize the disk interface
2722

2723            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2724            return;
2725        }
2726        catch (java.io.IOException JavaDoc ex)
2727        {
2728
2729            // Debug
2730

2731            logger.error("File Write Error [" + netFile.getFileId() + "] : ", ex);
2732
2733            // Failed to read the file
2734

2735            m_sess.sendErrorResponseSMB(SMBStatus.HRDWriteFault, SMBStatus.ErrHrd);
2736            return;
2737        }
2738
2739        // Return the count of bytes actually written
2740

2741        outPkt.setParameterCount(6);
2742        outPkt.setAndXCommand(0xFF);
2743        outPkt.setParameter(1, 0);
2744        outPkt.setParameter(2, wrtlen);
2745        outPkt.setParameter(3, 0); // remaining byte count for pipes only
2746
outPkt.setParameter(4, 0); // reserved
2747
outPkt.setParameter(5, 0); // "
2748
outPkt.setByteCount(0);
2749
2750        // Send the write response
2751

2752        m_sess.sendResponseSMB(outPkt);
2753    }
2754
2755    /**
2756     * runProtocol method comment.
2757     */

2758    public boolean runProtocol() throws java.io.IOException JavaDoc, SMBSrvException, TooManyConnectionsException
2759    {
2760
2761        // Check if the SMB packet is initialized
2762

2763        if (m_smbPkt == null)
2764            m_smbPkt = m_sess.getReceivePacket();
2765
2766        // Check if the received packet has a valid SMB signature
2767

2768        if (m_smbPkt.checkPacketSignature() == false)
2769            throw new IOException JavaDoc("Invalid SMB signature");
2770
2771        // Determine if the request has a chained command, if so then we will copy the incoming
2772
// request so that
2773
// a chained reply can be built.
2774

2775        SMBSrvPacket outPkt = m_smbPkt;
2776        boolean chainedCmd = hasChainedCommand(m_smbPkt);
2777
2778        if (chainedCmd)
2779        {
2780
2781            // Debug
2782

2783            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_STATE))
2784                logger.debug("AndX Command = 0x" + Integer.toHexString(m_smbPkt.getAndXCommand()));
2785
2786            // Copy the request packet into a new packet for the reply
2787

2788            outPkt = new SMBSrvPacket(m_smbPkt);
2789        }
2790
2791        // Reset the byte unpack offset
2792

2793        m_smbPkt.resetBytePointer();
2794
2795        // Determine the SMB command type
2796

2797        boolean handledOK = true;
2798
2799        switch (m_smbPkt.getCommand())
2800        {
2801
2802        // Session setup
2803

2804        case PacketType.SessionSetupAndX:
2805            procSessionSetup(outPkt);
2806            break;
2807
2808        // Tree connect
2809

2810        case PacketType.TreeConnectAndX:
2811            procTreeConnectAndX(outPkt);
2812            break;
2813
2814        // Transaction2
2815

2816        case PacketType.Transaction2:
2817        case PacketType.Transaction:
2818            procTransact2(outPkt);
2819            break;
2820
2821        // Transaction/transaction2 secondary
2822

2823        case PacketType.TransactionSecond:
2824        case PacketType.Transaction2Second:
2825            procTransact2Secondary(outPkt);
2826            break;
2827
2828        // Close a search started via the FindFirst transaction2 command
2829

2830        case PacketType.FindClose2:
2831            procFindClose(outPkt);
2832            break;
2833
2834        // Open a file
2835

2836        case PacketType.OpenAndX:
2837            procOpenAndX(outPkt);
2838            break;
2839
2840        // Read a file
2841

2842        case PacketType.ReadAndX:
2843            procReadAndX(outPkt);
2844            break;
2845
2846        // Write to a file
2847

2848        case PacketType.WriteAndX:
2849            procWriteAndX(outPkt);
2850            break;
2851
2852        // Tree disconnect
2853

2854        case PacketType.TreeDisconnect:
2855            procTreeDisconnect(outPkt);
2856            break;
2857
2858        // Lock/unlock regions of a file
2859

2860        case PacketType.LockingAndX:
2861            procLockingAndX(outPkt);
2862            break;
2863
2864        // Logoff a user
2865

2866        case PacketType.LogoffAndX:
2867            procLogoffAndX(outPkt);
2868            break;
2869
2870        // Tree connection (without AndX batching)
2871

2872        case PacketType.TreeConnect:
2873            super.runProtocol();
2874            break;
2875
2876        // Rename file
2877

2878        case PacketType.RenameFile:
2879            procRenameFile(outPkt);
2880            break;
2881
2882        // Echo request
2883

2884        case PacketType.Echo:
2885            super.procEcho(outPkt);
2886            break;
2887
2888        // Default
2889

2890        default:
2891
2892            // Get the tree connection details, if it is a disk or printer type connection then pass
2893
// the request to the
2894
// core protocol handler
2895

2896            int treeId = m_smbPkt.getTreeId();
2897            TreeConnection conn = null;
2898            if (treeId != -1)
2899                conn = m_sess.findConnection(treeId);
2900
2901            if (conn != null)
2902            {
2903
2904                // Check if this is a disk or print connection, if so then send the request to the
2905
// core protocol handler
2906

2907                if (conn.getSharedDevice().getType() == ShareType.DISK
2908                        || conn.getSharedDevice().getType() == ShareType.PRINTER)
2909                {
2910
2911                    // Chain to the core protocol handler
2912

2913                    handledOK = super.runProtocol();
2914                }
2915                else if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
2916                {
2917
2918                    // Send the request to IPC$ remote admin handler
2919

2920                    IPCHandler.processIPCRequest(m_sess, outPkt);
2921                    handledOK = true;
2922                }
2923            }
2924            break;
2925        }
2926
2927        // Return the handled status
2928

2929        return handledOK;
2930    }
2931}
Popular Tags