KickJava   Java API By Example, From Geeks To Geeks.

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


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.locking.FileLock;
23 import org.alfresco.filesys.locking.LockConflictException;
24 import org.alfresco.filesys.locking.NotLockedException;
25 import org.alfresco.filesys.netbios.RFCNetBIOSProtocol;
26 import org.alfresco.filesys.server.auth.ClientInfo;
27 import org.alfresco.filesys.server.auth.InvalidUserException;
28 import org.alfresco.filesys.server.auth.SrvAuthenticator;
29 import org.alfresco.filesys.server.auth.acl.AccessControl;
30 import org.alfresco.filesys.server.auth.acl.AccessControlManager;
31 import org.alfresco.filesys.server.core.InvalidDeviceInterfaceException;
32 import org.alfresco.filesys.server.core.ShareType;
33 import org.alfresco.filesys.server.core.SharedDevice;
34 import org.alfresco.filesys.server.filesys.AccessDeniedException;
35 import org.alfresco.filesys.server.filesys.DirectoryNotEmptyException;
36 import org.alfresco.filesys.server.filesys.DiskDeviceContext;
37 import org.alfresco.filesys.server.filesys.DiskFullException;
38 import org.alfresco.filesys.server.filesys.DiskInterface;
39 import org.alfresco.filesys.server.filesys.FileAccess;
40 import org.alfresco.filesys.server.filesys.FileAction;
41 import org.alfresco.filesys.server.filesys.FileAttribute;
42 import org.alfresco.filesys.server.filesys.FileExistsException;
43 import org.alfresco.filesys.server.filesys.FileInfo;
44 import org.alfresco.filesys.server.filesys.FileName;
45 import org.alfresco.filesys.server.filesys.FileOfflineException;
46 import org.alfresco.filesys.server.filesys.FileOpenParams;
47 import org.alfresco.filesys.server.filesys.FileSharingException;
48 import org.alfresco.filesys.server.filesys.FileStatus;
49 import org.alfresco.filesys.server.filesys.FileSystem;
50 import org.alfresco.filesys.server.filesys.IOControlNotImplementedException;
51 import org.alfresco.filesys.server.filesys.IOCtlInterface;
52 import org.alfresco.filesys.server.filesys.NetworkFile;
53 import org.alfresco.filesys.server.filesys.NotifyChange;
54 import org.alfresco.filesys.server.filesys.PathNotFoundException;
55 import org.alfresco.filesys.server.filesys.SearchContext;
56 import org.alfresco.filesys.server.filesys.SrvDiskInfo;
57 import org.alfresco.filesys.server.filesys.TooManyConnectionsException;
58 import org.alfresco.filesys.server.filesys.TooManyFilesException;
59 import org.alfresco.filesys.server.filesys.TreeConnection;
60 import org.alfresco.filesys.server.filesys.UnsupportedInfoLevelException;
61 import org.alfresco.filesys.server.filesys.VolumeInfo;
62 import org.alfresco.filesys.server.locking.FileLockingInterface;
63 import org.alfresco.filesys.server.locking.LockManager;
64 import org.alfresco.filesys.smb.DataType;
65 import org.alfresco.filesys.smb.FileInfoLevel;
66 import org.alfresco.filesys.smb.FindFirstNext;
67 import org.alfresco.filesys.smb.InvalidUNCPathException;
68 import org.alfresco.filesys.smb.LockingAndX;
69 import org.alfresco.filesys.smb.NTIOCtl;
70 import org.alfresco.filesys.smb.NTTime;
71 import org.alfresco.filesys.smb.PCShare;
72 import org.alfresco.filesys.smb.PacketType;
73 import org.alfresco.filesys.smb.SMBDate;
74 import org.alfresco.filesys.smb.SMBException;
75 import org.alfresco.filesys.smb.SMBStatus;
76 import org.alfresco.filesys.smb.WinNT;
77 import org.alfresco.filesys.smb.server.notify.NotifyChangeEventList;
78 import org.alfresco.filesys.smb.server.notify.NotifyChangeHandler;
79 import org.alfresco.filesys.smb.server.notify.NotifyRequest;
80 import org.alfresco.filesys.smb.server.ntfs.NTFSStreamsInterface;
81 import org.alfresco.filesys.smb.server.ntfs.StreamInfoList;
82 import org.alfresco.filesys.util.DataBuffer;
83 import org.alfresco.filesys.util.DataPacker;
84 import org.alfresco.filesys.util.HexDump;
85 import org.alfresco.filesys.util.WildCard;
86 import org.apache.commons.logging.Log;
87 import org.apache.commons.logging.LogFactory;
88
89 /**
90  * NT SMB Protocol Handler Class
91  * <p>
92  * The NT protocol handler processes the additional SMBs that were added to the protocol in the NT
93  * SMB dialect.
94  */

95 public class NTProtocolHandler extends CoreProtocolHandler
96 {
97     private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol");
98
99     // Constants
100
//
101
// Flag to enable returning of '.' and '..' directory information in FindFirst request
102

103     public static final boolean ReturnDotFiles = true;
104
105     // Flag to enable faking of oplock requests when opening files
106

107     public static final boolean FakeOpLocks = false;
108
109     // Number of write requests per file to report file size change notifications
110

111     public static final int FileSizeChangeRate = 10;
112
113     // Security descriptor to allow Everyone access, returned by the QuerySecurityDescrptor NT
114
// transaction
115
// when NTFS streams are enabled for a virtual filesystem.
116

117     private static byte[] _sdEveryOne = { 0x01, 0x00, 0x04, (byte) 0x80, 0x14, 0x00, 0x00, 0x00,
118                                           0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119                                           0x2c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
120                                           0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
121                                           0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
122                                           0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1c, 0x00,
123                                           0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
124                                           (byte) 0xff, 0x01, 0x1f, 0x00, 0x01, 0x01, 0x00, 0x00,
125                                           0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
126     };
127
128     /**
129      * Class constructor.
130      */

131     protected NTProtocolHandler()
132     {
133         super();
134     }
135
136     /**
137      * Class constructor
138      *
139      * @param sess SMBSrvSession
140      */

141     protected NTProtocolHandler(SMBSrvSession sess)
142     {
143         super(sess);
144     }
145
146     /**
147      * Return the protocol name
148      *
149      * @return String
150      */

151     public String JavaDoc getName()
152     {
153         return "NT";
154     }
155
156     /**
157      * Run the NT SMB protocol handler to process the received SMB packet
158      *
159      * @exception IOException
160      * @exception SMBSrvException
161      * @exception TooManyConnectionsException
162      */

163     public boolean runProtocol() throws java.io.IOException JavaDoc, SMBSrvException, TooManyConnectionsException
164     {
165
166         // Check if the SMB packet is initialized
167

168         if (m_smbPkt == null)
169             m_smbPkt = m_sess.getReceivePacket();
170
171         // Check if the received packet has a valid SMB signature
172

173         if (m_smbPkt.checkPacketSignature() == false)
174             throw new IOException JavaDoc("Invalid SMB signature");
175
176         // Determine if the request has a chained command, if so then we will copy the incoming
177
// request so that
178
// a chained reply can be built.
179

180         SMBSrvPacket outPkt = m_smbPkt;
181         boolean chainedCmd = hasChainedCommand(m_smbPkt);
182
183         if (chainedCmd)
184         {
185
186             // Debug
187

188             if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_STATE))
189                 logger.debug("AndX Command = 0x" + Integer.toHexString(m_smbPkt.getAndXCommand()));
190
191             // Copy the request packet into a new packet for the reply
192

193             outPkt = new SMBSrvPacket(m_smbPkt, m_smbPkt.getPacketLength());
194         }
195
196         // Reset the byte unpack offset
197

198         m_smbPkt.resetBytePointer();
199
200         // Set the process id from the received packet, this can change for the same session and
201
// needs to be set
202
// for lock ownership checking
203

204         m_sess.setProcessId(m_smbPkt.getProcessId());
205
206         // Determine the SMB command type
207

208         boolean handledOK = true;
209
210         switch (m_smbPkt.getCommand())
211         {
212
213         // NT Session setup
214

215         case PacketType.SessionSetupAndX:
216             procSessionSetup(outPkt);
217             break;
218
219         // Tree connect
220

221         case PacketType.TreeConnectAndX:
222             procTreeConnectAndX(outPkt);
223             break;
224
225         // Transaction/transaction2
226

227         case PacketType.Transaction:
228         case PacketType.Transaction2:
229             procTransact2(outPkt);
230             break;
231
232         // Transaction/transaction2 secondary
233

234         case PacketType.TransactionSecond:
235         case PacketType.Transaction2Second:
236             procTransact2Secondary(outPkt);
237             break;
238
239         // Close a search started via the FindFirst transaction2 command
240

241         case PacketType.FindClose2:
242             procFindClose(outPkt);
243             break;
244
245         // Open a file
246

247         case PacketType.OpenAndX:
248             procOpenAndX(outPkt);
249             break;
250
251         // Close a file
252

253         case PacketType.CloseFile:
254             procCloseFile(outPkt);
255             break;
256
257         // Read a file
258

259         case PacketType.ReadAndX:
260             procReadAndX(outPkt);
261             break;
262
263         // Write to a file
264

265         case PacketType.WriteAndX:
266             procWriteAndX(outPkt);
267             break;
268
269         // Rename file
270

271         case PacketType.RenameFile:
272             procRenameFile(outPkt);
273             break;
274
275         // Delete file
276

277         case PacketType.DeleteFile:
278             procDeleteFile(outPkt);
279             break;
280
281         // Delete directory
282

283         case PacketType.DeleteDirectory:
284             procDeleteDirectory(outPkt);
285             break;
286
287         // Tree disconnect
288

289         case PacketType.TreeDisconnect:
290             procTreeDisconnect(outPkt);
291             break;
292
293         // Lock/unlock regions of a file
294

295         case PacketType.LockingAndX:
296             procLockingAndX(outPkt);
297             break;
298
299         // Logoff a user
300

301         case PacketType.LogoffAndX:
302             procLogoffAndX(outPkt);
303             break;
304
305         // NT Create/open file
306

307         case PacketType.NTCreateAndX:
308             procNTCreateAndX(outPkt);
309             break;
310
311         // Tree connection (without AndX batching)
312

313         case PacketType.TreeConnect:
314             super.runProtocol();
315             break;
316
317         // NT cancel
318

319         case PacketType.NTCancel:
320             procNTCancel(outPkt);
321             break;
322
323         // NT transaction
324

325         case PacketType.NTTransact:
326             procNTTransaction(outPkt);
327             break;
328
329         // NT transaction secondary
330

331         case PacketType.NTTransactSecond:
332             procNTTransactionSecondary(outPkt);
333             break;
334
335         // Echo request
336

337         case PacketType.Echo:
338             super.procEcho(outPkt);
339             break;
340
341         // Default
342

343         default:
344
345             // Get the tree connection details, if it is a disk or printer type connection then pass
346
// the request to the
347
// core protocol handler
348

349             int treeId = m_smbPkt.getTreeId();
350             TreeConnection conn = null;
351             if (treeId != -1)
352                 conn = m_sess.findConnection(treeId);
353
354             if (conn != null)
355             {
356
357                 // Check if this is a disk or print connection, if so then send the request to the
358
// core protocol handler
359

360                 if (conn.getSharedDevice().getType() == ShareType.DISK
361                         || conn.getSharedDevice().getType() == ShareType.PRINTER)
362                 {
363
364                     // Chain to the core protocol handler
365

366                     handledOK = super.runProtocol();
367                 }
368                 else if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
369                 {
370
371                     // Send the request to IPC$ remote admin handler
372

373                     IPCHandler.processIPCRequest(m_sess, outPkt);
374                     handledOK = true;
375                 }
376             }
377             break;
378         }
379
380         // Return the handled status
381

382         return handledOK;
383     }
384
385     /**
386      * Process the NT SMB session setup request.
387      *
388      * @param outPkt Response SMB packet.
389      */

390     protected void procSessionSetup(SMBSrvPacket outPkt) throws SMBSrvException, IOException JavaDoc,
391             TooManyConnectionsException
392     {
393
394         // Check that the received packet looks like a valid NT session setup andX request
395

396         if (m_smbPkt.checkPacketIsValid(13, 0) == false)
397         {
398             m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
399             return;
400         }
401
402         // Extract the session details
403

404         int maxBufSize = m_smbPkt.getParameter(2);
405         int maxMpx = m_smbPkt.getParameter(3);
406         int vcNum = m_smbPkt.getParameter(4);
407         int sessKey = m_smbPkt.getParameterLong(5);
408         int ascPwdLen = m_smbPkt.getParameter(7);
409         int uniPwdLen = m_smbPkt.getParameter(8);
410         int capabs = m_smbPkt.getParameter(11);
411
412         // Extract the client details from the session setup request
413

414         int dataPos = m_smbPkt.getByteOffset();
415         int dataLen = m_smbPkt.getByteCount();
416         byte[] buf = m_smbPkt.getBuffer();
417
418         // Determine if ASCII or unicode strings are being used
419

420         boolean isUni = m_smbPkt.isUnicode();
421
422         // Extract the password strings
423

424         byte[] ascPwd = m_smbPkt.unpackBytes(ascPwdLen);
425         byte[] uniPwd = m_smbPkt.unpackBytes(uniPwdLen);
426
427         // Extract the user name string
428

429         String JavaDoc user = m_smbPkt.unpackString(isUni);
430
431         if (user == null)
432         {
433             m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
434             return;
435         }
436
437         // Extract the clients primary domain name string
438

439         String JavaDoc domain = "";
440
441         if (m_smbPkt.hasMoreData())
442         {
443
444             // Extract the callers domain name
445

446             domain = m_smbPkt.unpackString(isUni);
447
448             if (domain == null)
449             {
450                 m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError,
451                         SMBStatus.ErrSrv);
452                 return;
453             }
454         }
455
456         // Extract the clients native operating system
457

458         String JavaDoc clientOS = "";
459
460         if (m_smbPkt.hasMoreData())
461         {
462
463             // Extract the callers operating system name
464

465             clientOS = m_smbPkt.unpackString(isUni);
466
467             if (clientOS == null)
468             {
469                 m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError,
470                         SMBStatus.ErrSrv);
471                 return;
472             }
473         }
474
475         // DEBUG
476

477         if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
478         {
479             logger.debug("NT Session setup from user=" + user + ", password="
480                     + (uniPwd != null ? HexDump.hexString(uniPwd) : "none") + ", ANSIpwd="
481                     + (ascPwd != null ? HexDump.hexString(ascPwd) : "none") + ", domain=" + domain + ", os=" + clientOS
482                     + ", VC=" + vcNum + ", maxBuf=" + maxBufSize + ", maxMpx=" + maxMpx
483                     + ", challenge=" + HexDump.hexString(m_sess.getChallengeKey()));
484             logger.debug(" MID=" + m_smbPkt.getMultiplexId() + ", UID=" + m_smbPkt.getUserId() + ", PID="
485                     + m_smbPkt.getProcessId());
486         }
487
488         // Store the client maximum buffer size, maximum multiplexed requests count and client
489
// capability flags
490

491         m_sess.setClientMaximumBufferSize(maxBufSize);
492         m_sess.setClientMaximumMultiplex(maxMpx);
493         m_sess.setClientCapabilities(capabs);
494
495         // Create the client information and store in the session
496

497         ClientInfo client = new ClientInfo(user, uniPwd);
498         client.setANSIPassword(ascPwd);
499         client.setDomain(domain);
500         client.setOperatingSystem(clientOS);
501
502         if (m_sess.hasRemoteAddress())
503             client.setClientAddress(m_sess.getRemoteAddress().getHostAddress());
504
505         // Check if this is a null session logon
506

507         if (user.length() == 0 && domain.length() == 0 && uniPwdLen == 0 && ascPwdLen == 1)
508             client.setLogonType(ClientInfo.LogonNull);
509
510         // Authenticate the user, if the server is using user mode security
511

512         SrvAuthenticator auth = getSession().getSMBServer().getAuthenticator();
513         boolean isGuest = false;
514
515         if (auth != null && auth.getAccessMode() == SrvAuthenticator.USER_MODE)
516         {
517
518             // Validate the user
519

520             int sts = auth.authenticateUser(client, m_sess, SrvAuthenticator.NTLM1);
521
522             if (sts > 0 && (sts & SrvAuthenticator.AUTH_GUEST) != 0)
523             {
524
525                 // Guest logon
526

527                 isGuest = true;
528
529                 // DEBUG
530

531                 if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
532                     logger.debug("User " + user + ", logged on as guest");
533             }
534             else if (sts != SrvAuthenticator.AUTH_ALLOW)
535             {
536
537                 // Check if the session already has valid client details and the new client details
538
// have null username/password
539
// values
540

541                 if (getSession().getClientInformation() != null && client.getUserName().length() == 0)
542                 {
543
544                     // Use the existing client information details
545

546                     client = getSession().getClientInformation();
547
548                     // DEBUG
549

550                     if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
551                         logger.debug("Null client information, reusing existing client=" + client);
552                 }
553                 else
554                 {
555
556                     // Invalid user, reject the session setup request
557

558                     m_sess.sendErrorResponseSMB(SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
559
560                     // DEBUG
561

562                     if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
563                         logger.debug("User " + user + ", access denied");
564                     return;
565                 }
566             }
567             else if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NEGOTIATE))
568             {
569
570                 // DEBUG
571

572                 logger.debug("User " + user + " logged on "
573                         + (client != null ? " (type " + client.getLogonTypeString() + ")" : ""));
574             }
575         }
576
577         // Update the client information if not already set
578

579         if (getSession().getClientInformation() == null
580                 || getSession().getClientInformation().getUserName().length() == 0)
581         {
582
583             // Set the client details for the session
584

585             getSession().setClientInformation(client);
586         }
587
588         // Set the guest flag for the client, indicate that the session is logged on
589

590         client.setGuest(isGuest);
591         getSession().setLoggedOn(true);
592
593         // Build the session setup response SMB
594

595         outPkt.setParameterCount(3);
596         outPkt.setParameter(0, 0); // No chained response
597
outPkt.setParameter(1, 0); // Offset to chained response
598
outPkt.setParameter(2, isGuest ? 1 : 0);
599         outPkt.setByteCount(0);
600
601         outPkt.setTreeId(0);
602         outPkt.setUserId(0);
603
604         // Set the various flags
605

606         int flags = outPkt.getFlags();
607         flags &= ~SMBSrvPacket.FLG_CASELESS;
608         outPkt.setFlags(flags);
609
610         int flags2 = SMBSrvPacket.FLG2_LONGFILENAMES;
611         if (isUni)
612             flags2 += SMBSrvPacket.FLG2_UNICODE;
613         outPkt.setFlags2(flags2);
614
615         // Pack the OS, dialect and domain name strings.
616

617         int pos = outPkt.getByteOffset();
618         buf = outPkt.getBuffer();
619
620         if (isUni)
621             pos = DataPacker.wordAlign(pos);
622
623         pos = DataPacker.putString("Java", buf, pos, true, isUni);
624         pos = DataPacker.putString("Alfresco CIFS Server " + m_sess.getServer().isVersion(), buf, pos, true, isUni);
625         pos = DataPacker.putString(m_sess.getServer().getConfiguration().getDomainName(), buf, pos, true, isUni);
626
627         outPkt.setByteCount(pos - outPkt.getByteOffset());
628
629         // Check if there is a chained command, or commands
630

631         if (m_smbPkt.hasAndXCommand() && dataPos < m_smbPkt.getReceivedLength())
632         {
633
634             // Process any chained commands, AndX
635

636             pos = procAndXCommands(outPkt);
637             pos -= RFCNetBIOSProtocol.HEADER_LEN;
638         }
639         else
640         {
641
642             // Indicate that there are no chained replies
643

644             outPkt.setAndXCommand(SMBSrvPacket.NO_ANDX_CMD);
645         }
646
647         // Send the negotiate response
648

649         m_sess.sendResponseSMB(outPkt, pos);
650
651         // Update the session state
652

653         m_sess.setState(SMBSrvSessionState.SMBSESSION);
654
655         // Notify listeners that a user has logged onto the session
656

657         m_sess.getSMBServer().sessionLoggedOn(m_sess);
658     }
659
660     /**
661      * Process the chained SMB commands (AndX).
662      *
663      * @param outPkt Reply packet.
664      * @return New offset to the end of the reply packet
665      */

666     protected final int procAndXCommands(SMBSrvPacket outPkt)
667     {
668
669         // Use the byte offset plus length to calculate the current output packet end position
670

671         return procAndXCommands(outPkt, outPkt.getByteOffset() + outPkt.getByteCount(), null);
672     }
673
674     /**
675      * Process the chained SMB commands (AndX).
676      *
677      * @param outPkt Reply packet.
678      * @param endPos Current end of packet position
679      * @param file Current file , or null if no file context in chain
680      * @return New offset to the end of the reply packet
681      */

682     protected final int procAndXCommands(SMBSrvPacket outPkt, int endPos, NetworkFile file)
683     {
684
685         // Get the chained command and command block offset
686

687         int andxCmd = m_smbPkt.getAndXCommand();
688         int andxOff = m_smbPkt.getParameter(1) + RFCNetBIOSProtocol.HEADER_LEN;
689
690         // Set the initial chained command and offset
691

692         outPkt.setAndXCommand(andxCmd);
693         outPkt.setParameter(1, andxOff - RFCNetBIOSProtocol.HEADER_LEN);
694
695         // Pointer to the last parameter block, starts with the main command parameter block
696

697         int paramBlk = SMBSrvPacket.WORDCNT;
698
699         // Get the current end of the reply packet offset
700

701         int endOfPkt = endPos;
702         boolean andxErr = false;
703
704         while (andxCmd != SMBSrvPacket.NO_ANDX_CMD && andxErr == false)
705         {
706
707             // Determine the chained command type
708

709             int prevEndOfPkt = endOfPkt;
710             boolean endOfChain = false;
711
712             switch (andxCmd)
713             {
714
715             // Tree connect
716

717             case PacketType.TreeConnectAndX:
718                 endOfPkt = procChainedTreeConnectAndX(andxOff, outPkt, endOfPkt);
719                 break;
720
721             // Close file
722

723             case PacketType.CloseFile:
724                 endOfPkt = procChainedClose(andxOff, outPkt, endOfPkt);
725                 endOfChain = true;
726                 break;
727
728             // Read file
729

730             case PacketType.ReadAndX:
731                 endOfPkt = procChainedReadAndX(andxOff, outPkt, endOfPkt, file);
732                 break;
733
734             // Chained command was not handled
735

736             default:
737                 break;
738             }
739
740             // Set the next chained command details in the current parameter block
741

742             outPkt.setAndXCommand(paramBlk, andxCmd);
743             outPkt.setAndXParameter(paramBlk, 1, prevEndOfPkt - RFCNetBIOSProtocol.HEADER_LEN);
744
745             // Check if the end of chain has been reached, if not then look for the next
746
// chained command in the request. End of chain might be set if the current command
747
// is not an AndX SMB command.
748

749             if (endOfChain == false)
750             {
751
752                 // Advance to the next chained command block
753

754                 andxCmd = m_smbPkt.getAndXParameter(andxOff, 0) & 0x00FF;
755                 andxOff = m_smbPkt.getAndXParameter(andxOff, 1);
756
757                 // Advance the current parameter block
758

759                 paramBlk = prevEndOfPkt;
760             }
761             else
762             {
763
764                 // Indicate that the end of the command chain has been reached
765

766                 andxCmd = SMBSrvPacket.NO_ANDX_CMD;
767             }
768
769             // Check if the chained command has generated an error status
770

771             if (outPkt.getErrorCode() != SMBStatus.Success)
772                 andxErr = true;
773         }
774
775         // Return the offset to the end of the reply packet
776

777         return endOfPkt;
778     }
779
780     /**
781      * Process a chained tree connect request.
782      *
783      * @return New end of reply offset.
784      * @param cmdOff int Offset to the chained command within the request packet.
785      * @param outPkt SMBSrvPacket Reply packet.
786      * @param endOff int Offset to the current end of the reply packet.
787      */

788     protected final int procChainedTreeConnectAndX(int cmdOff, SMBSrvPacket outPkt, int endOff)
789     {
790
791         // Extract the parameters
792

793         int flags = m_smbPkt.getAndXParameter(cmdOff, 2);
794         int pwdLen = m_smbPkt.getAndXParameter(cmdOff, 3);
795
796         // Reset the byte pointer for data unpacking
797

798         m_smbPkt.setBytePointer(m_smbPkt.getAndXByteOffset(cmdOff), m_smbPkt.getAndXByteCount(cmdOff));
799
800         // Extract the password string
801

802         String JavaDoc pwd = null;
803
804         if (pwdLen > 0)
805         {
806             byte[] pwdByt = m_smbPkt.unpackBytes(pwdLen);
807             pwd = new String JavaDoc(pwdByt);
808         }
809
810         // Extract the requested share name, as a UNC path
811

812         boolean unicode = m_smbPkt.isUnicode();
813
814         String JavaDoc uncPath = m_smbPkt.unpackString(unicode);
815         if (uncPath == null)
816         {
817             outPkt.setError(m_smbPkt.isLongErrorCode(), SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError,
818                     SMBStatus.ErrSrv);
819             return endOff;
820         }
821
822         // Extract the service type string
823

824         String JavaDoc service = m_smbPkt.unpackString(false);
825         if (service == null)
826         {
827             outPkt.setError(m_smbPkt.isLongErrorCode(), SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError,
828                     SMBStatus.ErrSrv);
829             return endOff;
830         }
831
832         // Convert the service type to a shared device type, client may specify '?????' in which
833
// case we ignore the error.
834

835         int servType = ShareType.ServiceAsType(service);
836         if (servType == ShareType.UNKNOWN && service.compareTo("?????") != 0)
837         {
838             outPkt.setError(m_smbPkt.isLongErrorCode(), SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError,
839                     SMBStatus.ErrSrv);
840             return endOff;
841         }
842
843         // Debug
844

845         if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TREE))
846             logger.debug("NT ANDX Tree Connect AndX - " + uncPath + ", " + service);
847
848         // Parse the requested share name
849

850         PCShare share = null;
851
852         try
853         {
854             share = new PCShare(uncPath);
855         }
856         catch (InvalidUNCPathException ex)
857         {
858             outPkt.setError(m_smbPkt.isLongErrorCode(), SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError,
859                     SMBStatus.ErrSrv);
860             return endOff;
861         }
862
863         // Map the IPC$ share to the admin pipe type
864

865         if (servType == ShareType.NAMEDPIPE && share.getShareName().compareTo("IPC$") == 0)
866             servType = ShareType.ADMINPIPE;
867
868         // Check if the session is a null session, only allow access to the IPC$ named pipe share
869

870         if (m_sess.hasClientInformation() && m_sess.getClientInformation().isNullSession()
871                 && servType != ShareType.ADMINPIPE)
872         {
873
874             // Return an error status
875

876             outPkt.setError(m_smbPkt.isLongErrorCode(), SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied,
877                     SMBStatus.ErrDos);
878             return endOff;
879         }
880
881         // Find the requested shared device
882

883         SharedDevice shareDev = null;
884
885         try
886         {
887
888             // Get/create the shared device
889

890             shareDev = m_sess.getSMBServer().findShare(share.getNodeName(), share.getShareName(), servType, m_sess,
891                     true);
892         }
893         catch (InvalidUserException ex)
894         {
895
896             // Return a logon failure status
897

898             outPkt.setError(m_smbPkt.isLongErrorCode(), SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied,
899                     SMBStatus.ErrDos);
900             return endOff;
901         }
902         catch (Exception JavaDoc ex)
903         {
904
905             // Log the generic error
906

907             logger.error("Exception in TreeConnectAndX", ex);
908
909             // Return a general status, bad network name
910

911             outPkt.setError(m_smbPkt.isLongErrorCode(), SMBStatus.NTBadNetName, SMBStatus.SRVInvalidNetworkName,
912                     SMBStatus.ErrSrv);
913             return endOff;
914         }
915
916         // Check if the share is valid
917

918         if (shareDev == null || (servType != ShareType.UNKNOWN && shareDev.getType() != servType))
919         {
920
921             // Set the error status
922

923             outPkt.setError(m_smbPkt.isLongErrorCode(), SMBStatus.NTBadNetName, SMBStatus.SRVInvalidNetworkName,
924                     SMBStatus.ErrSrv);
925             return endOff;
926         }
927
928         // Authenticate the share connect, if the server is using share mode security
929

930         SrvAuthenticator auth = getSession().getSMBServer().getAuthenticator();
931         int sharePerm = FileAccess.Writeable;
932
933         if (auth != null && auth.getAccessMode() == SrvAuthenticator.SHARE_MODE)
934         {
935
936             // Validate the share connection
937

938             sharePerm = auth.authenticateShareConnect(m_sess.getClientInformation(), shareDev, pwd, m_sess);
939             if (sharePerm < 0)
940             {
941
942                 // Invalid share connection request
943

944                 outPkt.setError(m_smbPkt.isLongErrorCode(), SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied,
945                         SMBStatus.ErrDos);
946                 return endOff;
947             }
948         }
949
950         // Check if there is an access control manager, if so then run any access controls to
951
// determine the
952
// sessions access to the share.
953

954         if (getSession().getServer().hasAccessControlManager() && shareDev.hasAccessControls())
955         {
956
957             // Get the access control manager
958

959             AccessControlManager aclMgr = getSession().getServer().getAccessControlManager();
960
961             // Update the access permission for this session by processing the access control list
962
// for the
963
// shared device
964

965             int aclPerm = aclMgr.checkAccessControl(getSession(), shareDev);
966
967             if (aclPerm == FileAccess.NoAccess)
968             {
969
970                 // Invalid share connection request
971

972                 outPkt.setError(m_smbPkt.isLongErrorCode(), SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied,
973                         SMBStatus.ErrDos);
974                 return endOff;
975             }
976
977             // If the access controls returned a new access type update the main permission
978

979             if (aclPerm != AccessControl.Default)
980                 sharePerm = aclPerm;
981         }
982
983         // Allocate a tree id for the new connection
984

985         TreeConnection tree = null;
986         
987         try
988         {
989
990             // Allocate the tree id for this connection
991

992             int treeId = m_sess.addConnection(shareDev);
993             outPkt.setTreeId(treeId);
994
995             // Set the file permission that this user has been granted for this share
996

997             tree = m_sess.findConnection(treeId);
998             tree.setPermission(sharePerm);
999
1000            // Inform the driver that a connection has been opened
1001

1002            if (tree.getInterface() != null)
1003                tree.getInterface().treeOpened(m_sess, tree);
1004
1005            // Debug
1006

1007            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TREE))
1008                logger.debug("ANDX Tree Connect AndX - Allocated Tree Id = " + treeId);
1009        }
1010        catch (TooManyConnectionsException ex)
1011        {
1012
1013            // Too many connections open at the moment
1014

1015            outPkt.setError(SMBStatus.SRVNoResourcesAvailable, SMBStatus.ErrSrv);
1016            return endOff;
1017        }
1018
1019        // Build the tree connect response
1020

1021        outPkt.setAndXParameterCount(endOff, 2);
1022        outPkt.setAndXParameter(endOff, 0, SMBSrvPacket.NO_ANDX_CMD);
1023        outPkt.setAndXParameter(endOff, 1, 0);
1024
1025        // Pack the service type
1026

1027        int pos = outPkt.getAndXByteOffset(endOff);
1028        byte[] outBuf = outPkt.getBuffer();
1029        pos = DataPacker.putString(ShareType.TypeAsService(shareDev.getType()), outBuf, pos, true);
1030
1031        // Determine the filesystem type, for disk shares
1032

1033        String JavaDoc devType = "";
1034
1035        try
1036        {
1037            // Check if this is a disk shared device
1038

1039            if ( shareDev.getType() == ShareType.DISK)
1040            {
1041                // Check if the filesystem driver implements the NTFS streams interface, and streams are
1042
// enabled
1043

1044                if (shareDev.getInterface() instanceof NTFSStreamsInterface)
1045                {
1046    
1047                    // Check if NTFS streams are enabled
1048

1049                    NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) shareDev.getInterface();
1050                    if (ntfsStreams.hasStreamsEnabled(m_sess, tree))
1051                        devType = FileSystem.TypeNTFS;
1052                }
1053                else
1054                {
1055                    // Get the filesystem type from the context
1056

1057                    DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext();
1058                    devType = diskCtx.getFilesystemType();
1059                }
1060            }
1061        }
1062        catch (InvalidDeviceInterfaceException ex)
1063        {
1064
1065            // Log the error
1066

1067            logger.error("TreeConnectAndX error", ex);
1068        }
1069
1070        // Pack the filesystem type
1071

1072        pos = DataPacker.putString(devType, outBuf, pos, true, outPkt.isUnicode());
1073        
1074        int bytLen = pos - outPkt.getAndXByteOffset(endOff);
1075        outPkt.setAndXByteCount(endOff, bytLen);
1076
1077        // Return the new end of packet offset
1078

1079        return pos;
1080    }
1081
1082    /**
1083     * Process a chained read file request
1084     *
1085     * @param cmdOff Offset to the chained command within the request packet.
1086     * @param outPkt Reply packet.
1087     * @param endOff Offset to the current end of the reply packet.
1088     * @param netFile File to be read, passed down the chained requests
1089     * @return New end of reply offset.
1090     */

1091    protected final int procChainedReadAndX(int cmdOff, SMBSrvPacket outPkt, int endOff, NetworkFile netFile)
1092    {
1093
1094        // Get the tree id from the received packet and validate that it is a valid
1095
// connection id.
1096

1097        int treeId = m_smbPkt.getTreeId();
1098        TreeConnection conn = m_sess.findConnection(treeId);
1099
1100        if (conn == null)
1101        {
1102            outPkt.setError(SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
1103            return endOff;
1104        }
1105
1106        // Extract the read file parameters
1107

1108        long offset = (long) m_smbPkt.getAndXParameterLong(cmdOff, 3); // bottom 32bits of read
1109
// offset
1110
offset &= 0xFFFFFFFFL;
1111        int maxCount = m_smbPkt.getAndXParameter(cmdOff, 5);
1112
1113        // Check for the NT format request that has the top 32bits of the file offset
1114

1115        if (m_smbPkt.getAndXParameterCount(cmdOff) == 12)
1116        {
1117            long topOff = (long) m_smbPkt.getAndXParameterLong(cmdOff, 10);
1118            offset += topOff << 32;
1119        }
1120
1121        // Debug
1122

1123        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
1124            logger.debug("Chained File Read AndX : Size=" + maxCount + " ,Pos=" + offset);
1125
1126        // Read data from the file
1127

1128        byte[] buf = outPkt.getBuffer();
1129        int dataPos = 0;
1130        int rdlen = 0;
1131
1132        try
1133        {
1134
1135            // Access the disk interface that is associated with the shared device
1136

1137            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
1138
1139            // Set the returned parameter count so that the byte offset can be calculated
1140

1141            outPkt.setAndXParameterCount(endOff, 12);
1142            dataPos = outPkt.getAndXByteOffset(endOff);
1143            dataPos = DataPacker.wordAlign(dataPos); // align the data buffer
1144

1145            // Check if the requested data length will fit into the buffer
1146

1147            int dataLen = buf.length - dataPos;
1148            if (dataLen < maxCount)
1149                maxCount = dataLen;
1150
1151            // Read from the file
1152

1153            rdlen = disk.readFile(m_sess, conn, netFile, buf, dataPos, maxCount, offset);
1154
1155            // Return the data block
1156

1157            outPkt.setAndXParameter(endOff, 0, SMBSrvPacket.NO_ANDX_CMD);
1158            outPkt.setAndXParameter(endOff, 1, 0);
1159
1160            outPkt.setAndXParameter(endOff, 2, 0); // bytes remaining, for pipes only
1161
outPkt.setAndXParameter(endOff, 3, 0); // data compaction mode
1162
outPkt.setAndXParameter(endOff, 4, 0); // reserved
1163
outPkt.setAndXParameter(endOff, 5, rdlen); // data length
1164
outPkt.setAndXParameter(endOff, 6, dataPos - RFCNetBIOSProtocol.HEADER_LEN); // offset
1165
// to
1166
// data
1167

1168            // Clear the reserved parameters
1169

1170            for (int i = 7; i < 12; i++)
1171                outPkt.setAndXParameter(endOff, i, 0);
1172
1173            // Set the byte count
1174

1175            outPkt.setAndXByteCount(endOff, (dataPos + rdlen) - outPkt.getAndXByteOffset(endOff));
1176
1177            // Update the end offset for the new end of packet
1178

1179            endOff = dataPos + rdlen;
1180        }
1181        catch (InvalidDeviceInterfaceException ex)
1182        {
1183
1184            // Failed to get/initialize the disk interface
1185

1186            outPkt.setError(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1187            return endOff;
1188        }
1189        catch (java.io.IOException JavaDoc ex)
1190        {
1191        }
1192
1193        // Return the new end of packet offset
1194

1195        return endOff;
1196    }
1197
1198    /**
1199     * Process a chained close file request
1200     *
1201     * @param cmdOff int Offset to the chained command within the request packet.
1202     * @param outPkt SMBSrvPacket Reply packet.
1203     * @param endOff int Offset to the current end of the reply packet.
1204     * @return New end of reply offset.
1205     */

1206    protected final int procChainedClose(int cmdOff, SMBSrvPacket outPkt, int endOff)
1207    {
1208
1209        // Get the tree id from the received packet and validate that it is a valid
1210
// connection id.
1211

1212        int treeId = m_smbPkt.getTreeId();
1213        TreeConnection conn = m_sess.findConnection(treeId);
1214
1215        if (conn == null)
1216        {
1217            outPkt.setError(SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
1218            return endOff;
1219        }
1220
1221        // Get the file id from the request
1222

1223        int fid = m_smbPkt.getAndXParameter(cmdOff, 0);
1224        int ftime = m_smbPkt.getAndXParameter(cmdOff, 1);
1225        int fdate = m_smbPkt.getAndXParameter(cmdOff, 2);
1226
1227        NetworkFile netFile = conn.findFile(fid);
1228
1229        if (netFile == null)
1230        {
1231            outPkt.setError(SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
1232            return endOff;
1233        }
1234
1235        // Debug
1236

1237        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
1238            logger.debug("Chained File Close [" + treeId + "] fid=" + fid);
1239
1240        // Close the file
1241

1242        try
1243        {
1244
1245            // Access the disk interface that is associated with the shared device
1246

1247            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
1248
1249            // Close the file
1250
//
1251
// The disk interface may be null if the file is a named pipe file
1252

1253            if (disk != null)
1254                disk.closeFile(m_sess, conn, netFile);
1255
1256            // Indicate that the file has been closed
1257

1258            netFile.setClosed(true);
1259        }
1260        catch (InvalidDeviceInterfaceException ex)
1261        {
1262
1263            // Failed to get/initialize the disk interface
1264

1265            outPkt.setError(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1266            return endOff;
1267        }
1268        catch (java.io.IOException JavaDoc ex)
1269        {
1270        }
1271
1272        // Clear the returned parameter count and byte count
1273

1274        outPkt.setAndXParameterCount(endOff, 0);
1275        outPkt.setAndXByteCount(endOff, 0);
1276
1277        endOff = outPkt.getAndXByteOffset(endOff) - RFCNetBIOSProtocol.HEADER_LEN;
1278
1279        // Remove the file from the connections list of open files
1280

1281        conn.removeFile(fid, getSession());
1282
1283        // Return the new end of packet offset
1284

1285        return endOff;
1286    }
1287
1288    /**
1289     * Process the SMB tree connect request.
1290     *
1291     * @param outPkt Response SMB packet.
1292     * @exception java.io.IOException If an I/O error occurs
1293     * @exception SMBSrvException If an SMB protocol error occurs
1294     * @exception TooManyConnectionsException Too many concurrent connections on this session.
1295     */

1296
1297    protected void procTreeConnectAndX(SMBSrvPacket outPkt) throws SMBSrvException, TooManyConnectionsException,
1298            java.io.IOException JavaDoc
1299    {
1300
1301        // Check that the received packet looks like a valid tree connect request
1302

1303        if (m_smbPkt.checkPacketIsValid(4, 3) == false)
1304        {
1305            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
1306            return;
1307        }
1308
1309        // Extract the parameters
1310

1311        int flags = m_smbPkt.getParameter(2);
1312        int pwdLen = m_smbPkt.getParameter(3);
1313
1314        // Initialize the byte area pointer
1315

1316        m_smbPkt.resetBytePointer();
1317
1318        // Determine if ASCII or unicode strings are being used
1319

1320        boolean unicode = m_smbPkt.isUnicode();
1321
1322        // Extract the password string
1323

1324        String JavaDoc pwd = null;
1325
1326        if (pwdLen > 0)
1327        {
1328            byte[] pwdByts = m_smbPkt.unpackBytes(pwdLen);
1329            pwd = new String JavaDoc(pwdByts);
1330        }
1331
1332        // Extract the requested share name, as a UNC path
1333

1334        String JavaDoc uncPath = m_smbPkt.unpackString(unicode);
1335        if (uncPath == null)
1336        {
1337            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
1338            return;
1339        }
1340
1341        // Extract the service type string, always seems to be ASCII
1342

1343        String JavaDoc service = m_smbPkt.unpackString(false);
1344        if (service == null)
1345        {
1346            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
1347            return;
1348        }
1349
1350        // Convert the service type to a shared device type, client may specify '?????' in which
1351
// case we ignore the error.
1352

1353        int servType = ShareType.ServiceAsType(service);
1354        if (servType == ShareType.UNKNOWN && service.compareTo("?????") != 0)
1355        {
1356            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
1357            return;
1358        }
1359
1360        // Debug
1361

1362        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TREE))
1363            logger.debug("NT Tree Connect AndX - " + uncPath + ", " + service);
1364
1365        // Parse the requested share name
1366

1367        String JavaDoc shareName = null;
1368        String JavaDoc hostName = null;
1369
1370        if (uncPath.startsWith("\\"))
1371        {
1372
1373            try
1374            {
1375                PCShare share = new PCShare(uncPath);
1376                shareName = share.getShareName();
1377                hostName = share.getNodeName();
1378            }
1379            catch (InvalidUNCPathException ex)
1380            {
1381                m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError,
1382                        SMBStatus.ErrSrv);
1383                return;
1384            }
1385        }
1386        else
1387            shareName = uncPath;
1388
1389        // Map the IPC$ share to the admin pipe type
1390

1391        if (servType == ShareType.NAMEDPIPE && shareName.compareTo("IPC$") == 0)
1392            servType = ShareType.ADMINPIPE;
1393
1394        // Check if the session is a null session, only allow access to the IPC$ named pipe share
1395

1396        if (m_sess.hasClientInformation() && m_sess.getClientInformation().isNullSession()
1397                && servType != ShareType.ADMINPIPE)
1398        {
1399
1400            // Return an error status
1401

1402            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
1403            return;
1404        }
1405
1406        // Find the requested shared device
1407

1408        SharedDevice shareDev = null;
1409
1410        try
1411        {
1412
1413            // Get/create the shared device
1414

1415            shareDev = m_sess.getSMBServer().findShare(hostName, shareName, servType, m_sess, true);
1416        }
1417        catch (InvalidUserException ex)
1418        {
1419
1420            // Return a logon failure status
1421

1422            m_sess.sendErrorResponseSMB(SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
1423            return;
1424        }
1425        catch (Exception JavaDoc ex)
1426        {
1427
1428            // Log the generic error
1429

1430            logger.error("TreeConnectAndX error", ex);
1431
1432            // Return a general status, bad network name
1433

1434            m_sess.sendErrorResponseSMB(SMBStatus.NTBadNetName, SMBStatus.SRVInvalidNetworkName, SMBStatus.ErrSrv);
1435            return;
1436        }
1437
1438        // Check if the share is valid
1439

1440        if (shareDev == null || (servType != ShareType.UNKNOWN && shareDev.getType() != servType))
1441        {
1442            m_sess.sendErrorResponseSMB(SMBStatus.NTBadNetName, SMBStatus.SRVInvalidNetworkName, SMBStatus.ErrSrv);
1443            return;
1444        }
1445
1446        // Authenticate the share connection depending upon the security mode the server is running
1447
// under
1448

1449        SrvAuthenticator auth = getSession().getSMBServer().getAuthenticator();
1450        int sharePerm = FileAccess.Writeable;
1451
1452        if (auth != null)
1453        {
1454
1455            // Validate the share connection
1456

1457            sharePerm = auth.authenticateShareConnect(m_sess.getClientInformation(), shareDev, pwd, m_sess);
1458            if (sharePerm < 0)
1459            {
1460
1461                // DEBUG
1462

1463                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TREE))
1464                    logger.debug("Tree connect to " + shareName + ", access denied");
1465
1466                // Invalid share connection request
1467

1468                m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
1469                return;
1470            }
1471        }
1472
1473        // Check if there is an access control manager, if so then run any access controls to
1474
// determine the
1475
// sessions access to the share.
1476

1477        if (getSession().getServer().hasAccessControlManager() && shareDev.hasAccessControls())
1478        {
1479
1480            // Get the access control manager
1481

1482            AccessControlManager aclMgr = getSession().getServer().getAccessControlManager();
1483
1484            // Update the access permission for this session by processing the access control list
1485
// for the
1486
// shared device
1487

1488            int aclPerm = aclMgr.checkAccessControl(getSession(), shareDev);
1489
1490            if (aclPerm == FileAccess.NoAccess)
1491            {
1492
1493                // Invalid share connection request
1494

1495                m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
1496                return;
1497            }
1498
1499            // If the access controls returned a new access type update the main permission
1500

1501            if (aclPerm != AccessControl.Default)
1502                sharePerm = aclPerm;
1503        }
1504
1505        // Allocate a tree id for the new connection
1506

1507        int treeId = m_sess.addConnection(shareDev);
1508        outPkt.setTreeId(treeId);
1509
1510        // Set the file permission that this user has been granted for this share
1511

1512        TreeConnection tree = m_sess.findConnection(treeId);
1513        tree.setPermission(sharePerm);
1514
1515        // Debug
1516

1517        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TREE))
1518            logger.debug("Tree Connect AndX - Allocated Tree Id = " + treeId + ", Permission = "
1519                    + FileAccess.asString(sharePerm));
1520
1521        // Build the tree connect response
1522

1523        outPkt.setParameterCount(3);
1524        outPkt.setAndXCommand(0xFF); // no chained reply
1525
outPkt.setParameter(1, 0);
1526        outPkt.setParameter(2, 0);
1527
1528        // Pack the service type
1529

1530        int pos = outPkt.getByteOffset();
1531        pos = DataPacker.putString(ShareType.TypeAsService(shareDev.getType()), m_smbPkt.getBuffer(), pos, true);
1532
1533        // Determine the filesystem type, for disk shares
1534

1535        String JavaDoc devType = "";
1536
1537        try
1538        {
1539            // Check if this is a disk shared device
1540

1541            if ( shareDev.getType() == ShareType.DISK)
1542            {
1543                // Check if the filesystem driver implements the NTFS streams interface, and streams are
1544
// enabled
1545

1546                if (shareDev.getInterface() instanceof NTFSStreamsInterface)
1547                {
1548    
1549                    // Check if NTFS streams are enabled
1550

1551                    NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) shareDev.getInterface();
1552                    if (ntfsStreams.hasStreamsEnabled(m_sess, tree))
1553                        devType = FileSystem.TypeNTFS;
1554                }
1555                else
1556                {
1557                    // Get the filesystem type from the context
1558

1559                    DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext();
1560                    devType = diskCtx.getFilesystemType();
1561                }
1562            }
1563        }
1564        catch (InvalidDeviceInterfaceException ex)
1565        {
1566
1567            // Log the error
1568

1569            logger.error("TreeConnectAndX error", ex);
1570        }
1571
1572        // Pack the filesystem type
1573

1574        pos = DataPacker.putString(devType, m_smbPkt.getBuffer(), pos, true, outPkt.isUnicode());
1575        outPkt.setByteCount(pos - outPkt.getByteOffset());
1576
1577        // Send the response
1578

1579        m_sess.sendResponseSMB(outPkt);
1580
1581        // Inform the driver that a connection has been opened
1582

1583        if (tree.getInterface() != null)
1584            tree.getInterface().treeOpened(m_sess, tree);
1585    }
1586
1587    /**
1588     * Close a file that has been opened on the server.
1589     *
1590     * @param outPkt Response SMB packet.
1591     * @exception java.io.IOException If an I/O error occurs
1592     * @exception SMBSrvException If an SMB protocol error occurs
1593     */

1594    protected void procCloseFile(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
1595    {
1596
1597        // Check that the received packet looks like a valid file close request
1598

1599        if (m_smbPkt.checkPacketIsValid(3, 0) == false)
1600        {
1601            m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
1602            return;
1603        }
1604
1605        // Get the tree id from the received packet and validate that it is a valid
1606
// connection id.
1607

1608        int treeId = m_smbPkt.getTreeId();
1609        TreeConnection conn = m_sess.findConnection(treeId);
1610
1611        if (conn == null)
1612        {
1613            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
1614            return;
1615        }
1616
1617        // Check if the user has the required access permission
1618

1619        if (conn.hasReadAccess() == false)
1620        {
1621
1622            // User does not have the required access rights
1623

1624            m_sess.sendErrorResponseSMB(SMBStatus.SRVNoAccessRights, SMBStatus.ErrSrv);
1625            return;
1626        }
1627
1628        // Get the file id from the request
1629

1630        int fid = m_smbPkt.getParameter(0);
1631        int ftime = m_smbPkt.getParameter(1);
1632        int fdate = m_smbPkt.getParameter(2);
1633
1634        NetworkFile netFile = conn.findFile(fid);
1635
1636        if (netFile == null)
1637        {
1638            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos);
1639            return;
1640        }
1641
1642        // Debug
1643

1644        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
1645            logger.debug("File close [" + treeId + "] fid=" + fid);
1646
1647        // Close the file
1648

1649        try
1650        {
1651
1652            // Access the disk interface that is associated with the shared device
1653

1654            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
1655
1656            // Close the file
1657
//
1658
// The disk interface may be null if the file is a named pipe file
1659

1660            if (disk != null)
1661                disk.closeFile(m_sess, conn, netFile);
1662
1663            // Indicate that the file has been closed
1664

1665            netFile.setClosed(true);
1666        }
1667        catch (AccessDeniedException ex)
1668        {
1669            // Not allowed to delete the file, when delete on close flag is set
1670

1671            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
1672            return;
1673        }
1674        catch (InvalidDeviceInterfaceException ex)
1675        {
1676
1677            // Failed to get/initialize the disk interface
1678

1679            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
1680            return;
1681        }
1682        catch (java.io.IOException JavaDoc ex)
1683        {
1684        }
1685
1686        // Remove the file from the connections list of open files
1687

1688        conn.removeFile(fid, getSession());
1689
1690        // Build the close file response
1691

1692        outPkt.setParameterCount(0);
1693        outPkt.setByteCount(0);
1694
1695        // Send the response packet
1696

1697        m_sess.sendResponseSMB(outPkt);
1698
1699        // Check if there are any file/directory change notify requests active
1700

1701        DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
1702        if (netFile.getWriteCount() > 0 && diskCtx.hasChangeHandler())
1703            diskCtx.getChangeHandler().notifyFileSizeChanged(netFile.getFullName());
1704
1705        if (netFile.hasDeleteOnClose() && diskCtx.hasChangeHandler())
1706            diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionRemoved, netFile.getFullName());
1707    }
1708
1709    /**
1710     * Process a transact2 request. The transact2 can contain many different sub-requests.
1711     *
1712     * @param outPkt SMBSrvPacket
1713     * @exception SMBSrvException If an SMB protocol error occurs
1714     */

1715    protected void procTransact2(SMBSrvPacket outPkt) throws IOException JavaDoc, SMBSrvException
1716    {
1717
1718        // Check that we received enough parameters for a transact2 request
1719

1720        if (m_smbPkt.checkPacketIsValid(14, 0) == false)
1721        {
1722
1723            // Not enough parameters for a valid transact2 request
1724

1725            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
1726            return;
1727        }
1728
1729        // Get the tree id from the received packet and validate that it is a valid
1730
// connection id.
1731

1732        int treeId = m_smbPkt.getTreeId();
1733        TreeConnection conn = m_sess.findConnection(treeId);
1734
1735        if (conn == null)
1736        {
1737            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
1738            return;
1739        }
1740
1741        // Check if the user has the required access permission
1742

1743        if (conn.hasReadAccess() == false)
1744        {
1745
1746            // User does not have the required access rights
1747

1748            m_sess.sendErrorResponseSMB(SMBStatus.SRVNoAccessRights, SMBStatus.ErrSrv);
1749            return;
1750        }
1751
1752        // Create a transact packet using the received SMB packet
1753

1754        SMBSrvTransPacket tranPkt = new SMBSrvTransPacket(m_smbPkt.getBuffer());
1755
1756        // Create a transact buffer to hold the transaction setup, parameter and data blocks
1757

1758        SrvTransactBuffer transBuf = null;
1759        int subCmd = tranPkt.getSubFunction();
1760
1761        if (tranPkt.getTotalParameterCount() == tranPkt.getRxParameterBlockLength()
1762                && tranPkt.getTotalDataCount() == tranPkt.getRxDataBlockLength())
1763        {
1764
1765            // Create a transact buffer using the packet buffer, the entire request is contained in
1766
// a single
1767
// packet
1768

1769            transBuf = new SrvTransactBuffer(tranPkt);
1770        }
1771        else
1772        {
1773
1774            // Create a transact buffer to hold the multiple transact request parameter/data blocks
1775

1776            transBuf = new SrvTransactBuffer(tranPkt.getSetupCount(), tranPkt.getTotalParameterCount(), tranPkt
1777                    .getTotalDataCount());
1778            transBuf.setType(tranPkt.getCommand());
1779            transBuf.setFunction(subCmd);
1780
1781            // Append the setup, parameter and data blocks to the transaction data
1782

1783            byte[] buf = tranPkt.getBuffer();
1784
1785            transBuf.appendSetup(buf, tranPkt.getSetupOffset(), tranPkt.getSetupCount() * 2);
1786            transBuf.appendParameter(buf, tranPkt.getRxParameterBlock(), tranPkt.getRxParameterBlockLength());
1787            transBuf.appendData(buf, tranPkt.getRxDataBlock(), tranPkt.getRxDataBlockLength());
1788        }
1789
1790        // Set the return data limits for the transaction
1791

1792        transBuf.setReturnLimits(tranPkt.getMaximumReturnSetupCount(), tranPkt.getMaximumReturnParameterCount(),
1793                tranPkt.getMaximumReturnDataCount());
1794
1795        // Check for a multi-packet transaction, for a multi-packet transaction we just acknowledge
1796
// the receive with
1797
// an empty response SMB
1798

1799        if (transBuf.isMultiPacket())
1800        {
1801
1802            // Save the partial transaction data
1803

1804            m_sess.setTransaction(transBuf);
1805
1806            // Send an intermediate acknowedgement response
1807

1808            m_sess.sendSuccessResponseSMB();
1809            return;
1810        }
1811
1812        // Check if the transaction is on the IPC$ named pipe, the request requires special
1813
// processing
1814

1815        if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
1816        {
1817            IPCHandler.procTransaction(transBuf, m_sess, outPkt);
1818            return;
1819        }
1820
1821        // DEBUG
1822

1823        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
1824            logger.debug("Transaction [" + treeId + "] tbuf=" + transBuf);
1825
1826        // Process the transaction buffer
1827

1828        processTransactionBuffer(transBuf, outPkt);
1829    }
1830
1831    /**
1832     * Process a transact2 secondary request.
1833     *
1834     * @param outPkt SMBSrvPacket
1835     * @exception SMBSrvException If an SMB protocol error occurs
1836     */

1837    protected void procTransact2Secondary(SMBSrvPacket outPkt) throws IOException JavaDoc, SMBSrvException
1838    {
1839
1840        // Check that we received enough parameters for a transact2 request
1841

1842        if (m_smbPkt.checkPacketIsValid(8, 0) == false)
1843        {
1844
1845            // Not enough parameters for a valid transact2 request
1846

1847            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
1848            return;
1849        }
1850
1851        // Get the tree id from the received packet and validate that it is a valid
1852
// connection id.
1853

1854        int treeId = m_smbPkt.getTreeId();
1855        TreeConnection conn = m_sess.findConnection(treeId);
1856
1857        if (conn == null)
1858        {
1859            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
1860            return;
1861        }
1862
1863        // Check if the user has the required access permission
1864

1865        if (conn.hasReadAccess() == false)
1866        {
1867
1868            // User does not have the required access rights
1869

1870            m_sess.sendErrorResponseSMB(SMBStatus.SRVNoAccessRights, SMBStatus.ErrSrv);
1871            return;
1872        }
1873
1874        // Check if there is an active transaction, and it is an NT transaction
1875

1876        if (m_sess.hasTransaction() == false
1877                || (m_sess.getTransaction().isType() == PacketType.Transaction && m_smbPkt.getCommand() != PacketType.TransactionSecond)
1878                || (m_sess.getTransaction().isType() == PacketType.Transaction2 && m_smbPkt.getCommand() != PacketType.Transaction2Second))
1879        {
1880
1881            // No transaction to continue, or packet does not match the existing transaction, return
1882
// an error
1883

1884            m_sess.sendErrorResponseSMB(SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
1885            return;
1886        }
1887
1888        // Create an NT transaction using the received packet
1889

1890        SMBSrvTransPacket tpkt = new SMBSrvTransPacket(m_smbPkt.getBuffer());
1891        byte[] buf = tpkt.getBuffer();
1892        SrvTransactBuffer transBuf = m_sess.getTransaction();
1893
1894        // Append the parameter data to the transaction buffer, if any
1895

1896        int plen = tpkt.getSecondaryParameterBlockCount();
1897        if (plen > 0)
1898        {
1899
1900            // Append the data to the parameter buffer
1901

1902            DataBuffer paramBuf = transBuf.getParameterBuffer();
1903            paramBuf.appendData(buf, tpkt.getSecondaryParameterBlockOffset(), plen);
1904        }
1905
1906        // Append the data block to the transaction buffer, if any
1907

1908        int dlen = tpkt.getSecondaryDataBlockCount();
1909        if (dlen > 0)
1910        {
1911
1912            // Append the data to the data buffer
1913

1914            DataBuffer dataBuf = transBuf.getDataBuffer();
1915            dataBuf.appendData(buf, tpkt.getSecondaryDataBlockOffset(), dlen);
1916        }
1917
1918        // Debug
1919

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

1925        int totParam = tpkt.getTotalParameterCount();
1926        int totData = tpkt.getTotalDataCount();
1927
1928        int paramDisp = tpkt.getParameterBlockDisplacement();
1929        int dataDisp = tpkt.getDataBlockDisplacement();
1930
1931        if ((paramDisp + plen) == totParam && (dataDisp + dlen) == totData)
1932        {
1933
1934            // Debug
1935

1936            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
1937                logger.debug("Transaction complete, processing ...");
1938
1939            // Clear the in progress transaction
1940

1941            m_sess.setTransaction(null);
1942
1943            // Check if the transaction is on the IPC$ named pipe, the request requires special
1944
// processing
1945

1946            if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
1947            {
1948                IPCHandler.procTransaction(transBuf, m_sess, outPkt);
1949                return;
1950            }
1951
1952            // DEBUG
1953

1954            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
1955                logger.debug("Transaction second [" + treeId + "] tbuf=" + transBuf);
1956
1957            // Process the transaction
1958

1959            processTransactionBuffer(transBuf, outPkt);
1960        }
1961        else
1962        {
1963
1964            // There are more transaction parameter/data sections to be received, return an
1965
// intermediate response
1966

1967            m_sess.sendSuccessResponseSMB();
1968        }
1969    }
1970
1971    /**
1972     * Process a transaction buffer
1973     *
1974     * @param tbuf TransactBuffer
1975     * @param outPkt SMBSrvPacket
1976     * @exception IOException If a network error occurs
1977     * @exception SMBSrvException If an SMB error occurs
1978     */

1979    private final void processTransactionBuffer(SrvTransactBuffer tbuf, SMBSrvPacket outPkt) throws IOException JavaDoc,
1980            SMBSrvException
1981    {
1982
1983        // Get the transact2 sub-command code and process the request
1984

1985        switch (tbuf.getFunction())
1986        {
1987
1988        // Start a file search
1989

1990        case PacketType.Trans2FindFirst:
1991            procTrans2FindFirst(tbuf, outPkt);
1992            break;
1993
1994        // Continue a file search
1995

1996        case PacketType.Trans2FindNext:
1997            procTrans2FindNext(tbuf, outPkt);
1998            break;
1999
2000        // Query file system information
2001

2002        case PacketType.Trans2QueryFileSys:
2003            procTrans2QueryFileSys(tbuf, outPkt);
2004            break;
2005
2006        // Query path
2007

2008        case PacketType.Trans2QueryPath:
2009            procTrans2QueryPath(tbuf, outPkt);
2010            break;
2011
2012        // Query file information via handle
2013

2014        case PacketType.Trans2QueryFile:
2015            procTrans2QueryFile(tbuf, outPkt);
2016            break;
2017
2018        // Set file information via handle
2019

2020        case PacketType.Trans2SetFile:
2021            procTrans2SetFile(tbuf, outPkt);
2022            break;
2023
2024        // Set file information via path
2025

2026        case PacketType.Trans2SetPath:
2027            procTrans2SetPath(tbuf, outPkt);
2028            break;
2029
2030        // Unknown transact2 command
2031

2032        default:
2033
2034            // Return an unrecognized command error
2035

2036            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
2037            break;
2038        }
2039    }
2040
2041    /**
2042     * Close a search started via the transact2 find first/next command.
2043     *
2044     * @param outPkt SMBSrvPacket
2045     * @exception java.io.IOException If an I/O error occurs
2046     * @exception SMBSrvException If an SMB protocol error occurs
2047     */

2048    protected final void procFindClose(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
2049    {
2050
2051        // Check that the received packet looks like a valid find close request
2052

2053        if (m_smbPkt.checkPacketIsValid(1, 0) == false)
2054        {
2055            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
2056            return;
2057        }
2058
2059        // Get the tree connection details
2060

2061        int treeId = m_smbPkt.getTreeId();
2062        TreeConnection conn = m_sess.findConnection(treeId);
2063
2064        if (conn == null)
2065        {
2066            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
2067            return;
2068        }
2069
2070        // Check if the user has the required access permission
2071

2072        if (conn.hasReadAccess() == false)
2073        {
2074
2075            // User does not have the required access rights
2076

2077            m_sess.sendErrorResponseSMB(SMBStatus.SRVNoAccessRights, SMBStatus.ErrSrv);
2078            return;
2079        }
2080
2081        // Get the search id
2082

2083        int searchId = m_smbPkt.getParameter(0);
2084
2085        // Get the search context
2086

2087        SearchContext ctx = m_sess.getSearchContext(searchId);
2088
2089        if (ctx == null)
2090        {
2091
2092            // Invalid search handle
2093

2094            m_sess.sendSuccessResponseSMB();
2095            return;
2096        }
2097
2098        // Debug
2099

2100        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
2101            logger.debug("Close trans search [" + searchId + "]");
2102
2103        // Deallocate the search slot, close the search.
2104

2105        m_sess.deallocateSearchSlot(searchId);
2106
2107        // Return a success status SMB
2108

2109        m_sess.sendSuccessResponseSMB();
2110    }
2111
2112    /**
2113     * Process the file lock/unlock request.
2114     *
2115     * @param outPkt SMBSrvPacket
2116     */

2117    protected final void procLockingAndX(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
2118    {
2119
2120        // Check that the received packet looks like a valid locking andX request
2121

2122        if (m_smbPkt.checkPacketIsValid(8, 0) == false)
2123        {
2124            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
2125            return;
2126        }
2127
2128        // Get the tree connection details
2129

2130        int treeId = m_smbPkt.getTreeId();
2131        TreeConnection conn = m_sess.findConnection(treeId);
2132
2133        if (conn == null)
2134        {
2135            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
2136            return;
2137        }
2138
2139        // Check if the user has the required access permission
2140

2141        if (conn.hasReadAccess() == false)
2142        {
2143
2144            // User does not have the required access rights
2145

2146            m_sess.sendErrorResponseSMB(SMBStatus.SRVNoAccessRights, SMBStatus.ErrSrv);
2147            return;
2148        }
2149
2150        // Extract the file lock/unlock parameters
2151

2152        int fid = m_smbPkt.getParameter(2);
2153        int lockType = m_smbPkt.getParameter(3);
2154        long lockTmo = m_smbPkt.getParameterLong(4);
2155        int unlockCnt = m_smbPkt.getParameter(6);
2156        int lockCnt = m_smbPkt.getParameter(7);
2157
2158        NetworkFile netFile = conn.findFile(fid);
2159
2160        if (netFile == null)
2161        {
2162            m_sess.sendErrorResponseSMB(SMBStatus.Win32InvalidHandle, SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos);
2163            return;
2164        }
2165
2166        // Debug
2167

2168        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_LOCK))
2169            logger.debug("File Lock [" + netFile.getFileId() + "] : type=0x" + Integer.toHexString(lockType) + ", tmo="
2170                    + lockTmo + ", locks=" + lockCnt + ", unlocks=" + unlockCnt);
2171
2172        DiskInterface disk = null;
2173        try
2174        {
2175
2176            // Get the disk interface for the share
2177

2178            disk = (DiskInterface) conn.getSharedDevice().getInterface();
2179        }
2180        catch (InvalidDeviceInterfaceException ex)
2181        {
2182
2183            // Failed to get/initialize the disk interface
2184

2185            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2186            return;
2187        }
2188
2189        // Check if the virtual filesystem supports file locking
2190

2191        if (disk instanceof FileLockingInterface)
2192        {
2193
2194            // Get the lock manager
2195

2196            FileLockingInterface lockInterface = (FileLockingInterface) disk;
2197            LockManager lockMgr = lockInterface.getLockManager(m_sess, conn);
2198
2199            // Unpack the lock/unlock structures
2200

2201            m_smbPkt.resetBytePointer();
2202            boolean largeFileLock = LockingAndX.hasLargeFiles(lockType);
2203
2204            // Optimize for a single lock/unlock structure
2205

2206            if ((unlockCnt + lockCnt) == 1)
2207            {
2208
2209                // Get the unlock/lock structure
2210

2211                int pid = m_smbPkt.unpackWord();
2212                long offset = -1;
2213                long length = -1;
2214
2215                if (largeFileLock == false)
2216                {
2217
2218                    // Get the lock offset and length, short format
2219

2220                    offset = m_smbPkt.unpackInt();
2221                    length = m_smbPkt.unpackInt();
2222                }
2223                else
2224                {
2225
2226                    // Get the lock offset and length, large format
2227

2228                    m_smbPkt.skipBytes(2);
2229
2230                    offset = ((long) m_smbPkt.unpackInt()) << 32;
2231                    offset += (long) m_smbPkt.unpackInt();
2232
2233                    length = ((long) m_smbPkt.unpackInt()) << 32;
2234                    length += (long) m_smbPkt.unpackInt();
2235                }
2236
2237                // Create the lock/unlock details
2238

2239                FileLock fLock = lockMgr.createLockObject(m_sess, conn, netFile, offset, length, pid);
2240
2241                // Debug
2242

2243                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_LOCK))
2244                    logger.debug(" Single " + (lockCnt == 1 ? "Lock" : "UnLock") + " lock=" + fLock.toString());
2245
2246                // Perform the lock/unlock request
2247

2248                try
2249                {
2250
2251                    // Check if the request is an unlock
2252

2253                    if (unlockCnt > 0)
2254                    {
2255
2256                        // Unlock the file
2257

2258                        lockMgr.unlockFile(m_sess, conn, netFile, fLock);
2259                    }
2260                    else
2261                    {
2262
2263                        // Lock the file
2264

2265                        lockMgr.lockFile(m_sess, conn, netFile, fLock);
2266                    }
2267                }
2268                catch (NotLockedException ex)
2269                {
2270
2271                    // Return an error status
2272

2273                    m_sess.sendErrorResponseSMB(SMBStatus.DOSNotLocked, SMBStatus.ErrDos);
2274                    return;
2275                }
2276                catch (LockConflictException ex)
2277                {
2278
2279                    // Return an error status
2280

2281                    m_sess
2282                            .sendErrorResponseSMB(SMBStatus.NTLockNotGranted, SMBStatus.DOSLockConflict,
2283                                    SMBStatus.ErrDos);
2284                    return;
2285                }
2286                catch (IOException JavaDoc ex)
2287                {
2288
2289                    // Return an error status
2290

2291                    m_sess.sendErrorResponseSMB(SMBStatus.SRVInternalServerError, SMBStatus.ErrSrv);
2292                    return;
2293                }
2294            }
2295            else
2296            {
2297
2298                // Unpack the lock/unlock structures
2299

2300            }
2301        }
2302        else
2303        {
2304
2305            // Return a 'not locked' status if there are unlocks in the request else return a
2306
// success status
2307

2308            if (unlockCnt > 0)
2309            {
2310
2311                // Return an error status
2312

2313                m_sess.sendErrorResponseSMB(SMBStatus.DOSNotLocked, SMBStatus.ErrDos);
2314                return;
2315            }
2316        }
2317
2318        // Return a success response
2319

2320        outPkt.setParameterCount(2);
2321        outPkt.setAndXCommand(0xFF);
2322        outPkt.setParameter(1, 0);
2323        outPkt.setByteCount(0);
2324
2325        // Send the lock request response
2326

2327        m_sess.sendResponseSMB(outPkt);
2328    }
2329
2330    /**
2331     * Process the logoff request.
2332     *
2333     * @param outPkt SMBSrvPacket
2334     */

2335    protected final void procLogoffAndX(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
2336    {
2337
2338        // Check that the received packet looks like a valid logoff andX request
2339

2340        if (m_smbPkt.checkPacketIsValid(15, 1) == false)
2341        {
2342            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
2343            return;
2344        }
2345
2346        // Return a success status SMB
2347

2348        m_sess.sendSuccessResponseSMB();
2349    }
2350
2351    /**
2352     * Process the file open request.
2353     *
2354     * @param outPkt SMBSrvPacket
2355     */

2356    protected final void procOpenAndX(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
2357    {
2358
2359        // Check that the received packet looks like a valid open andX request
2360

2361        if (m_smbPkt.checkPacketIsValid(15, 1) == false)
2362        {
2363            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
2364            return;
2365        }
2366
2367        // Get the tree connection details
2368

2369        int treeId = m_smbPkt.getTreeId();
2370        TreeConnection conn = m_sess.findConnection(treeId);
2371
2372        if (conn == null)
2373        {
2374            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
2375            return;
2376        }
2377
2378        // Check if the user has the required access permission
2379

2380        if (conn.hasReadAccess() == false)
2381        {
2382
2383            // User does not have the required access rights
2384

2385            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2386            return;
2387        }
2388
2389        // If the connection is to the IPC$ remote admin named pipe pass the request to the IPC
2390
// handler. If the device is
2391
// not a disk type device then return an error.
2392

2393        if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
2394        {
2395
2396            // Use the IPC$ handler to process the request
2397

2398            IPCHandler.processIPCRequest(m_sess, outPkt);
2399            return;
2400        }
2401        else if (conn.getSharedDevice().getType() != ShareType.DISK)
2402        {
2403
2404            // Return an access denied error
2405

2406            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2407            return;
2408        }
2409
2410        // Extract the open file parameters
2411

2412        int flags = m_smbPkt.getParameter(2);
2413        int access = m_smbPkt.getParameter(3);
2414        int srchAttr = m_smbPkt.getParameter(4);
2415        int fileAttr = m_smbPkt.getParameter(5);
2416        int crTime = m_smbPkt.getParameter(6);
2417        int crDate = m_smbPkt.getParameter(7);
2418        int openFunc = m_smbPkt.getParameter(8);
2419        int allocSiz = m_smbPkt.getParameterLong(9);
2420
2421        // Extract the filename string
2422

2423        String JavaDoc fileName = m_smbPkt.unpackString(m_smbPkt.isUnicode());
2424        if (fileName == null)
2425        {
2426            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2427            return;
2428        }
2429
2430        // Create the file open parameters
2431

2432        long crDateTime = 0L;
2433        if (crTime > 0 && crDate > 0)
2434            crDateTime = new SMBDate(crDate, crTime).getTime();
2435
2436        FileOpenParams params = new FileOpenParams(fileName, openFunc, access, srchAttr, fileAttr, allocSiz, crDateTime);
2437
2438        // Debug
2439

2440        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
2441            logger.debug("File Open AndX [" + treeId + "] params=" + params);
2442
2443        // Access the disk interface and open the requested file
2444

2445        int fid;
2446        NetworkFile netFile = null;
2447        int respAction = 0;
2448
2449        try
2450        {
2451
2452            // Access the disk interface that is associated with the shared device
2453

2454            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
2455
2456            // Check if the requested file already exists
2457

2458            int fileSts = disk.fileExists(m_sess, conn, fileName);
2459
2460            if (fileSts == FileStatus.NotExist)
2461            {
2462
2463                // Check if the file should be created if it does not exist
2464

2465                if (FileAction.createNotExists(openFunc))
2466                {
2467
2468                    // Create a new file
2469

2470                    netFile = disk.createFile(m_sess, conn, params);
2471
2472                    // Indicate that the file did not exist and was created
2473

2474                    respAction = FileAction.FileCreated;
2475                }
2476                else
2477                {
2478
2479                    // Check if the path is a directory
2480

2481                    if (fileSts == FileStatus.DirectoryExists)
2482                    {
2483
2484                        // Return an access denied error
2485

2486                        m_sess.sendErrorResponseSMB(SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2487                    }
2488                    else
2489                    {
2490
2491                        // Return a file not found error
2492

2493                        m_sess.sendErrorResponseSMB(SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
2494                    }
2495                    return;
2496                }
2497            }
2498            else
2499            {
2500
2501                // Open the requested file
2502

2503                netFile = disk.openFile(m_sess, conn, params);
2504
2505                // Set the file action response
2506

2507                if (FileAction.truncateExistingFile(openFunc))
2508                    respAction = FileAction.FileTruncated;
2509                else
2510                    respAction = FileAction.FileExisted;
2511            }
2512
2513            // Add the file to the list of open files for this tree connection
2514

2515            fid = conn.addFile(netFile, getSession());
2516
2517        }
2518        catch (InvalidDeviceInterfaceException ex)
2519        {
2520
2521            // Failed to get/initialize the disk interface
2522

2523            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2524            return;
2525        }
2526        catch (TooManyFilesException ex)
2527        {
2528
2529            // Too many files are open on this connection, cannot open any more files.
2530

2531            m_sess.sendErrorResponseSMB(SMBStatus.DOSTooManyOpenFiles, SMBStatus.ErrDos);
2532            return;
2533        }
2534        catch (AccessDeniedException ex)
2535        {
2536
2537            // Return an access denied error
2538

2539            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2540            return;
2541        }
2542        catch (FileSharingException ex)
2543        {
2544
2545            // Return a sharing violation error
2546

2547            m_sess.sendErrorResponseSMB(SMBStatus.NTSharingViolation, SMBStatus.DOSFileSharingConflict,
2548                    SMBStatus.ErrDos);
2549            return;
2550        }
2551        catch (FileOfflineException ex)
2552        {
2553
2554            // File data is unavailable
2555

2556            m_sess.sendErrorResponseSMB(SMBStatus.NTFileOffline, SMBStatus.HRDDriveNotReady, SMBStatus.ErrHrd);
2557            return;
2558        }
2559        catch (java.io.IOException JavaDoc ex)
2560        {
2561
2562            // Failed to open the file
2563

2564            m_sess.sendErrorResponseSMB(SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
2565            return;
2566        }
2567
2568        // Build the open file response
2569

2570        outPkt.setParameterCount(15);
2571
2572        outPkt.setAndXCommand(0xFF);
2573        outPkt.setParameter(1, 0); // AndX offset
2574

2575        outPkt.setParameter(2, fid);
2576        outPkt.setParameter(3, netFile.getFileAttributes()); // file attributes
2577

2578        SMBDate modDate = null;
2579
2580        if (netFile.hasModifyDate())
2581            modDate = new SMBDate(netFile.getModifyDate());
2582
2583        outPkt.setParameter(4, modDate != null ? modDate.asSMBTime() : 0); // last write time
2584
outPkt.setParameter(5, modDate != null ? modDate.asSMBDate() : 0); // last write date
2585
outPkt.setParameterLong(6, netFile.getFileSizeInt()); // file size
2586
outPkt.setParameter(8, netFile.getGrantedAccess());
2587        outPkt.setParameter(9, OpenAndX.FileTypeDisk);
2588        outPkt.setParameter(10, 0); // named pipe state
2589
outPkt.setParameter(11, respAction);
2590        outPkt.setParameter(12, 0); // server FID (long)
2591
outPkt.setParameter(13, 0);
2592        outPkt.setParameter(14, 0);
2593
2594        outPkt.setByteCount(0);
2595
2596        // Send the response packet
2597

2598        m_sess.sendResponseSMB(outPkt);
2599    }
2600
2601    /**
2602     * Process the file read request.
2603     *
2604     * @param outPkt SMBSrvPacket
2605     */

2606    protected final void procReadAndX(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
2607    {
2608
2609        // Check that the received packet looks like a valid read andX request
2610

2611        if (m_smbPkt.checkPacketIsValid(10, 0) == false)
2612        {
2613            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
2614            return;
2615        }
2616
2617        // Get the tree connection details
2618

2619        int treeId = m_smbPkt.getTreeId();
2620        TreeConnection conn = m_sess.findConnection(treeId);
2621
2622        if (conn == null)
2623        {
2624            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
2625            return;
2626        }
2627
2628        // Check if the user has the required access permission
2629

2630        if (conn.hasReadAccess() == false)
2631        {
2632
2633            // User does not have the required access rights
2634

2635            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2636            return;
2637        }
2638
2639        // If the connection is to the IPC$ remote admin named pipe pass the request to the IPC
2640
// handler.
2641

2642        if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
2643        {
2644
2645            // Use the IPC$ handler to process the request
2646

2647            IPCHandler.processIPCRequest(m_sess, outPkt);
2648            return;
2649        }
2650
2651        // Extract the read file parameters
2652

2653        int fid = m_smbPkt.getParameter(2);
2654        long offset = (long) m_smbPkt.getParameterLong(3); // bottom 32bits of read offset
2655
offset &= 0xFFFFFFFFL;
2656        int maxCount = m_smbPkt.getParameter(5);
2657
2658        // Check for the NT format request that has the top 32bits of the file offset
2659

2660        if (m_smbPkt.getParameterCount() == 12)
2661        {
2662            long topOff = (long) m_smbPkt.getParameterLong(10);
2663            offset += topOff << 32;
2664        }
2665
2666        NetworkFile netFile = conn.findFile(fid);
2667
2668        if (netFile == null)
2669        {
2670            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos);
2671            return;
2672        }
2673
2674        // Debug
2675

2676        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO))
2677            logger.debug("File Read AndX [" + netFile.getFileId() + "] : Size=" + maxCount + " ,Pos=" + offset);
2678
2679        // Read data from the file
2680

2681        byte[] buf = outPkt.getBuffer();
2682        int dataPos = 0;
2683        int rdlen = 0;
2684
2685        try
2686        {
2687
2688            // Access the disk interface that is associated with the shared device
2689

2690            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
2691
2692            // Set the returned parameter count so that the byte offset can be calculated
2693

2694            outPkt.setParameterCount(12);
2695            dataPos = outPkt.getByteOffset();
2696            dataPos = DataPacker.wordAlign(dataPos); // align the data buffer
2697

2698            // Check if the requested data length will fit into the buffer
2699

2700            int dataLen = buf.length - dataPos;
2701            if (dataLen < maxCount)
2702                maxCount = dataLen;
2703
2704            // Read from the file
2705

2706            rdlen = disk.readFile(m_sess, conn, netFile, buf, dataPos, maxCount, offset);
2707        }
2708        catch (InvalidDeviceInterfaceException ex)
2709        {
2710
2711            // Failed to get/initialize the disk interface
2712

2713            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2714            return;
2715        }
2716        catch (FileOfflineException ex)
2717        {
2718
2719            // File data is unavailable
2720

2721            m_sess.sendErrorResponseSMB(SMBStatus.NTFileOffline, SMBStatus.HRDReadFault, SMBStatus.ErrHrd);
2722            return;
2723        }
2724        catch (LockConflictException ex)
2725        {
2726
2727            // Debug
2728

2729            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_LOCK))
2730                logger.debug("Read Lock Error [" + netFile.getFileId() + "] : Size=" + maxCount + " ,Pos=" + offset);
2731
2732            // File is locked
2733

2734            m_sess.sendErrorResponseSMB(SMBStatus.NTLockConflict, SMBStatus.DOSLockConflict, SMBStatus.ErrDos);
2735            return;
2736        }
2737        catch (AccessDeniedException ex)
2738        {
2739
2740            // User does not have the required access rights or file is not accessible
2741

2742            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2743            return;
2744        }
2745        catch (java.io.IOException JavaDoc ex)
2746        {
2747
2748            // Failed to read the file
2749

2750            m_sess.sendErrorResponseSMB(SMBStatus.HRDReadFault, SMBStatus.ErrHrd);
2751            return;
2752        }
2753
2754        // Return the data block
2755

2756        outPkt.setAndXCommand(0xFF); // no chained command
2757
outPkt.setParameter(1, 0);
2758        outPkt.setParameter(2, 0); // bytes remaining, for pipes only
2759
outPkt.setParameter(3, 0); // data compaction mode
2760
outPkt.setParameter(4, 0); // reserved
2761
outPkt.setParameter(5, rdlen); // data length
2762
outPkt.setParameter(6, dataPos - RFCNetBIOSProtocol.HEADER_LEN); // offset to data
2763

2764        // Clear the reserved parameters
2765

2766        for (int i = 7; i < 12; i++)
2767            outPkt.setParameter(i, 0);
2768
2769        // Set the byte count
2770

2771        outPkt.setByteCount((dataPos + rdlen) - outPkt.getByteOffset());
2772
2773        // Check if there is a chained command, or commands
2774

2775        if (m_smbPkt.hasAndXCommand())
2776        {
2777
2778            // Process any chained commands, AndX
2779

2780            int pos = procAndXCommands(outPkt, outPkt.getPacketLength(), netFile);
2781
2782            // Send the read andX response
2783

2784            m_sess.sendResponseSMB(outPkt, pos);
2785        }
2786        else
2787        {
2788
2789            // Send the normal read andX response
2790

2791            m_sess.sendResponseSMB(outPkt);
2792        }
2793    }
2794
2795    /**
2796     * Rename a file.
2797     *
2798     * @param outPkt SMBSrvPacket
2799     * @exception java.io.IOException If an I/O error occurs
2800     * @exception SMBSrvException If an SMB protocol error occurs
2801     */

2802    protected void procRenameFile(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
2803    {
2804
2805        // Check that the received packet looks like a valid rename file request
2806

2807        if (m_smbPkt.checkPacketIsValid(1, 4) == false)
2808        {
2809            m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
2810            return;
2811        }
2812
2813        // Get the tree id from the received packet and validate that it is a valid
2814
// connection id.
2815

2816        int treeId = m_smbPkt.getTreeId();
2817        TreeConnection conn = m_sess.findConnection(treeId);
2818
2819        if (conn == null)
2820        {
2821            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
2822            return;
2823        }
2824
2825        // Check if the user has the required access permission
2826

2827        if (conn.hasWriteAccess() == false)
2828        {
2829
2830            // User does not have the required access rights
2831

2832            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2833            return;
2834        }
2835
2836        // Get the Unicode flag
2837

2838        boolean isUni = m_smbPkt.isUnicode();
2839
2840        // Read the data block
2841

2842        m_smbPkt.resetBytePointer();
2843
2844        // Extract the old file name
2845

2846        if (m_smbPkt.unpackByte() != DataType.ASCII)
2847        {
2848            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2849            return;
2850        }
2851
2852        String JavaDoc oldName = m_smbPkt.unpackString(isUni);
2853        if (oldName == null)
2854        {
2855            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2856            return;
2857        }
2858
2859        // Extract the new file name
2860

2861        if (m_smbPkt.unpackByte() != DataType.ASCII)
2862        {
2863            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2864            return;
2865        }
2866
2867        String JavaDoc newName = m_smbPkt.unpackString(isUni);
2868        if (newName == null)
2869        {
2870            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2871            return;
2872        }
2873
2874        // Debug
2875

2876        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
2877            logger.debug("File Rename [" + treeId + "] old name=" + oldName + ", new name=" + newName);
2878
2879        // Access the disk interface and rename the requested file
2880

2881        int fid;
2882        NetworkFile netFile = null;
2883
2884        try
2885        {
2886
2887            // Access the disk interface that is associated with the shared device
2888

2889            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
2890
2891            // Rename the requested file
2892

2893            disk.renameFile(m_sess, conn, oldName, newName);
2894        }
2895        catch (InvalidDeviceInterfaceException ex)
2896        {
2897
2898            // Failed to get/initialize the disk interface
2899

2900            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
2901            return;
2902        }
2903        catch (FileNotFoundException JavaDoc ex)
2904        {
2905
2906            // Source file/directory does not exist
2907

2908            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
2909            return;
2910        }
2911        catch (FileExistsException ex)
2912        {
2913
2914            // Destination file/directory already exists
2915

2916            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNameCollision, SMBStatus.DOSFileAlreadyExists,
2917                    SMBStatus.ErrDos);
2918            return;
2919        }
2920        catch (AccessDeniedException ex)
2921        {
2922
2923            // Not allowed to rename the file/directory
2924

2925            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2926            return;
2927        }
2928        catch (FileSharingException ex)
2929        {
2930
2931            // Return a sharing violation error
2932

2933            m_sess.sendErrorResponseSMB(SMBStatus.NTSharingViolation, SMBStatus.DOSFileSharingConflict,
2934                    SMBStatus.ErrDos);
2935            return;
2936        }
2937
2938        // Build the rename file response
2939

2940        outPkt.setParameterCount(0);
2941        outPkt.setByteCount(0);
2942
2943        // Send the response packet
2944

2945        m_sess.sendResponseSMB(outPkt);
2946
2947        // Check if there are any file/directory change notify requests active
2948

2949        DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
2950        if (diskCtx.hasChangeHandler())
2951            diskCtx.getChangeHandler().notifyRename(oldName, newName);
2952    }
2953
2954    /**
2955     * Delete a file.
2956     *
2957     * @param outPkt SMBSrvPacket
2958     * @exception IOException If an network error occurs
2959     * @exception SMBSrvException If an SMB error occurs
2960     */

2961    protected void procDeleteFile(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
2962    {
2963
2964        // Check that the received packet looks like a valid file delete request
2965

2966        if (m_smbPkt.checkPacketIsValid(1, 2) == false)
2967        {
2968            m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
2969            return;
2970        }
2971
2972        // Get the tree id from the received packet and validate that it is a valid
2973
// connection id.
2974

2975        int treeId = m_smbPkt.getTreeId();
2976        TreeConnection conn = m_sess.findConnection(treeId);
2977
2978        if (conn == null)
2979        {
2980            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
2981            return;
2982        }
2983
2984        // Check if the user has the required access permission
2985

2986        if (conn.hasWriteAccess() == false)
2987        {
2988
2989            // User does not have the required access rights
2990

2991            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
2992            return;
2993        }
2994
2995        // Get the Unicode flag
2996

2997        boolean isUni = m_smbPkt.isUnicode();
2998
2999        // Read the data block
3000

3001        m_smbPkt.resetBytePointer();
3002
3003        // Extract the old file name
3004

3005        if (m_smbPkt.unpackByte() != DataType.ASCII)
3006        {
3007            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
3008            return;
3009        }
3010
3011        String JavaDoc fileName = m_smbPkt.unpackString(isUni);
3012        if (fileName == null)
3013        {
3014            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
3015            return;
3016        }
3017
3018        // Debug
3019

3020        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
3021            logger.debug("File Delete [" + treeId + "] name=" + fileName);
3022
3023        // Access the disk interface and delete the file(s)
3024

3025        int fid;
3026        NetworkFile netFile = null;
3027
3028        try
3029        {
3030
3031            // Access the disk interface that is associated with the shared device
3032

3033            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
3034
3035            // Delete file(s)
3036

3037            disk.deleteFile(m_sess, conn, fileName);
3038        }
3039        catch (InvalidDeviceInterfaceException ex)
3040        {
3041
3042            // Failed to get/initialize the disk interface
3043

3044            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
3045            return;
3046        }
3047        catch (AccessDeniedException ex)
3048        {
3049
3050            // Not allowed to delete the file
3051

3052            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
3053            return;
3054        }
3055        catch (java.io.IOException JavaDoc ex)
3056        {
3057
3058            // Failed to open the file
3059

3060            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
3061            return;
3062        }
3063
3064        // Build the delete file response
3065

3066        outPkt.setParameterCount(0);
3067        outPkt.setByteCount(0);
3068
3069        // Send the response packet
3070

3071        m_sess.sendResponseSMB(outPkt);
3072
3073        // Check if there are any file/directory change notify requests active
3074

3075        DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
3076        if (diskCtx.hasChangeHandler())
3077            diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionRemoved, fileName);
3078    }
3079
3080    /**
3081     * Delete a directory.
3082     *
3083     * @param outPkt SMBSrvPacket
3084     * @exception IOException If a network error occurs
3085     * @exception SMBSrvException If an SMB error occurs
3086     */

3087    protected void procDeleteDirectory(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
3088    {
3089
3090        // Check that the received packet looks like a valid delete directory request
3091

3092        if (m_smbPkt.checkPacketIsValid(0, 2) == false)
3093        {
3094            m_sess.sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
3095            return;
3096        }
3097
3098        // Get the tree id from the received packet and validate that it is a valid
3099
// connection id.
3100

3101        int treeId = m_smbPkt.getTreeId();
3102        TreeConnection conn = m_sess.findConnection(treeId);
3103
3104        if (conn == null)
3105        {
3106            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
3107            return;
3108        }
3109
3110        // Check if the user has the required access permission
3111

3112        if (conn.hasWriteAccess() == false)
3113        {
3114
3115            // User does not have the required access rights
3116

3117            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
3118            return;
3119        }
3120
3121        // Get the Unicode flag
3122

3123        boolean isUni = m_smbPkt.isUnicode();
3124
3125        // Read the data block
3126

3127        m_smbPkt.resetBytePointer();
3128
3129        // Extract the old file name
3130

3131        if (m_smbPkt.unpackByte() != DataType.ASCII)
3132        {
3133            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
3134            return;
3135        }
3136
3137        String JavaDoc dirName = m_smbPkt.unpackString(isUni);
3138        if (dirName == null)
3139        {
3140            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
3141            return;
3142        }
3143
3144        // Debug
3145

3146        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
3147            logger.debug("Directory Delete [" + treeId + "] name=" + dirName);
3148
3149        // Access the disk interface and delete the directory
3150

3151        try
3152        {
3153
3154            // Access the disk interface that is associated with the shared device
3155

3156            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
3157
3158            // Delete the directory
3159

3160            disk.deleteDirectory(m_sess, conn, dirName);
3161        }
3162        catch (InvalidDeviceInterfaceException ex)
3163        {
3164
3165            // Failed to get/initialize the disk interface
3166

3167            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
3168            return;
3169        }
3170        catch (AccessDeniedException ex)
3171        {
3172
3173            // Not allowed to delete the directory
3174

3175            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
3176            return;
3177        }
3178        catch (DirectoryNotEmptyException ex)
3179        {
3180
3181            // Directory not empty
3182

3183            m_sess.sendErrorResponseSMB(SMBStatus.DOSDirectoryNotEmpty, SMBStatus.ErrDos);
3184            return;
3185        }
3186        catch (java.io.IOException JavaDoc ex)
3187        {
3188
3189            // Failed to delete the directory
3190

3191            m_sess.sendErrorResponseSMB(SMBStatus.DOSDirectoryInvalid, SMBStatus.ErrDos);
3192            return;
3193        }
3194
3195        // Build the delete directory response
3196

3197        outPkt.setParameterCount(0);
3198        outPkt.setByteCount(0);
3199
3200        // Send the response packet
3201

3202        m_sess.sendResponseSMB(outPkt);
3203
3204        // Check if there are any file/directory change notify requests active
3205

3206        DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
3207        if (diskCtx.hasChangeHandler())
3208            diskCtx.getChangeHandler().notifyDirectoryChanged(NotifyChange.ActionRemoved, dirName);
3209    }
3210
3211    /**
3212     * Process a transact2 file search request.
3213     *
3214     * @param tbuf Transaction request details
3215     * @param outPkt Packet to use for the reply.
3216     * @exception java.io.IOException If an I/O error occurs
3217     * @exception SMBSrvException If an SMB protocol error occurs
3218     */

3219    protected final void procTrans2FindFirst(SrvTransactBuffer tbuf, SMBSrvPacket outPkt) throws java.io.IOException JavaDoc,
3220            SMBSrvException
3221    {
3222
3223        // Get the tree connection details
3224

3225        int treeId = m_smbPkt.getTreeId();
3226        TreeConnection conn = m_sess.findConnection(treeId);
3227
3228        if (conn == null)
3229        {
3230            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
3231            return;
3232        }
3233
3234        // Check if the user has the required access permission
3235

3236        if (conn.hasReadAccess() == false)
3237        {
3238
3239            // User does not have the required access rights
3240

3241            m_sess.sendErrorResponseSMB(SMBStatus.SRVNoAccessRights, SMBStatus.ErrSrv);
3242            return;
3243        }
3244
3245        // Get the search parameters
3246

3247        DataBuffer paramBuf = tbuf.getParameterBuffer();
3248
3249        int srchAttr = paramBuf.getShort();
3250        int maxFiles = paramBuf.getShort();
3251        int srchFlag = paramBuf.getShort();
3252        int infoLevl = paramBuf.getShort();
3253        paramBuf.skipBytes(4);
3254
3255        String JavaDoc srchPath = paramBuf.getString(tbuf.isUnicode());
3256
3257        // Check if the search path is valid
3258

3259        if (srchPath == null || srchPath.length() == 0)
3260        {
3261
3262            // Invalid search request
3263

3264            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
3265            return;
3266        }
3267        else if (srchPath.endsWith("\\"))
3268        {
3269
3270            // Make the search a wildcard search
3271

3272            srchPath = srchPath + "*.*";
3273        }
3274
3275        // Check for the Macintosh information level, if the Macintosh extensions are not enabled
3276
// return an error
3277

3278        if (infoLevl == FindInfoPacker.InfoMacHfsInfo && getSession().hasMacintoshExtensions() == false)
3279        {
3280
3281            // Return an error status, Macintosh extensions are not enabled
3282

3283            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
3284            return;
3285        }
3286
3287        // Access the shared device disk interface
3288

3289        SearchContext ctx = null;
3290        DiskInterface disk = null;
3291        int searchId = -1;
3292        boolean wildcardSearch = false;
3293
3294        try
3295        {
3296
3297            // Access the disk interface
3298

3299            disk = (DiskInterface) conn.getSharedDevice().getInterface();
3300
3301            // Allocate a search slot for the new search
3302

3303            searchId = m_sess.allocateSearchSlot();
3304            if (searchId == -1)
3305            {
3306
3307                // Failed to allocate a slot for the new search
3308

3309                m_sess.sendErrorResponseSMB(SMBStatus.SRVNoResourcesAvailable, SMBStatus.ErrSrv);
3310                return;
3311            }
3312
3313            // Check if this is a wildcard search or single file search
3314

3315            if (WildCard.containsWildcards(srchPath) || WildCard.containsUnicodeWildcard(srchPath))
3316                wildcardSearch = true;
3317
3318            // Check if the search contains Unicode wildcards
3319

3320            if (tbuf.isUnicode() && WildCard.containsUnicodeWildcard(srchPath))
3321            {
3322
3323                // Translate the Unicode wildcards to standard DOS wildcards
3324

3325                srchPath = WildCard.convertUnicodeWildcardToDOS(srchPath);
3326
3327                // Debug
3328

3329                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
3330                    logger.debug("Converted Unicode wildcards to:" + srchPath);
3331            }
3332
3333            // Start a new search
3334

3335            ctx = disk.startSearch(m_sess, conn, srchPath, srchAttr);
3336            if (ctx != null)
3337            {
3338
3339                // Store details of the search in the context
3340

3341                ctx.setTreeId(treeId);
3342                ctx.setMaximumFiles(maxFiles);
3343            }
3344            else
3345            {
3346
3347                // Failed to start the search, return a no more files error
3348

3349                m_sess.sendErrorResponseSMB(SMBStatus.NTNoSuchFile, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
3350                return;
3351            }
3352
3353            // Save the search context
3354

3355            m_sess.setSearchContext(searchId, ctx);
3356
3357            // Create the reply transact buffer
3358

3359            SrvTransactBuffer replyBuf = new SrvTransactBuffer(tbuf);
3360            DataBuffer dataBuf = replyBuf.getDataBuffer();
3361
3362            // Determine the maximum return data length
3363

3364            int maxLen = replyBuf.getReturnDataLimit();
3365
3366            // Debug
3367

3368            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
3369                logger.debug("Start trans search [" + searchId + "] - " + srchPath + ", attr=0x"
3370                        + Integer.toHexString(srchAttr) + ", maxFiles=" + maxFiles + ", maxLen=" + maxLen
3371                        + ", infoLevel=" + infoLevl + ", flags=0x" + Integer.toHexString(srchFlag));
3372
3373            // Loop until we have filled the return buffer or there are no more files to return
3374

3375            int fileCnt = 0;
3376            int packLen = 0;
3377            int lastNameOff = 0;
3378
3379            // Flag to indicate if resume ids should be returned
3380

3381            boolean resumeIds = false;
3382            if (infoLevl == FindInfoPacker.InfoStandard && (srchFlag & FindFirstNext.ReturnResumeKey) != 0)
3383            {
3384
3385                // Windows servers only seem to return resume keys for the standard information
3386
// level
3387

3388                resumeIds = true;
3389            }
3390
3391            // If this is a wildcard search then add the '.' and '..' entries
3392

3393            if (wildcardSearch == true && ReturnDotFiles == true)
3394            {
3395
3396                // Pack the '.' file information
3397

3398                if (resumeIds == true)
3399                {
3400                    dataBuf.putInt(-1);
3401                    maxLen -= 4;
3402                }
3403
3404                lastNameOff = dataBuf.getPosition();
3405                FileInfo dotInfo = new FileInfo(".", 0, FileAttribute.Directory);
3406                dotInfo.setFileId(dotInfo.getFileName().hashCode());
3407
3408                packLen = FindInfoPacker.packInfo(dotInfo, dataBuf, infoLevl, tbuf.isUnicode());
3409
3410                // Update the file count for this packet, update the remaining buffer length
3411

3412                fileCnt++;
3413                maxLen -= packLen;
3414
3415                // Pack the '..' file information
3416

3417                if (resumeIds == true)
3418                {
3419                    dataBuf.putInt(-2);
3420                    maxLen -= 4;
3421                }
3422
3423                lastNameOff = dataBuf.getPosition();
3424                dotInfo.setFileName("..");
3425                dotInfo.setFileId(dotInfo.getFileName().hashCode());
3426
3427                packLen = FindInfoPacker.packInfo(dotInfo, dataBuf, infoLevl, tbuf.isUnicode());
3428
3429                // Update the file count for this packet, update the remaining buffer length
3430

3431                fileCnt++;
3432                maxLen -= packLen;
3433            }
3434
3435            boolean pktDone = false;
3436            boolean searchDone = false;
3437
3438            FileInfo info = new FileInfo();
3439
3440            while (pktDone == false && fileCnt < maxFiles)
3441            {
3442
3443                // Get file information from the search
3444

3445                if (ctx.nextFileInfo(info) == false)
3446                {
3447
3448                    // No more files
3449

3450                    pktDone = true;
3451                    searchDone = true;
3452                }
3453
3454                // Check if the file information will fit into the return buffer
3455

3456                else if (FindInfoPacker.calcInfoSize(info, infoLevl, false, true) <= maxLen)
3457                {
3458
3459                    // Pack the resume id, if required
3460

3461                    if (resumeIds == true)
3462                    {
3463                        dataBuf.putInt(ctx.getResumeId());
3464                        maxLen -= 4;
3465                    }
3466
3467                    // Save the offset to the last file information structure
3468

3469                    lastNameOff = dataBuf.getPosition();
3470
3471                    // Pack the file information
3472

3473                    packLen = FindInfoPacker.packInfo(info, dataBuf, infoLevl, tbuf.isUnicode());
3474
3475                    // Update the file count for this packet
3476

3477                    fileCnt++;
3478
3479                    // Recalculate the remaining buffer space
3480

3481                    maxLen -= packLen;
3482                }
3483                else
3484                {
3485
3486                    // Set the search restart point
3487

3488                    ctx.restartAt(info);
3489
3490                    // No more buffer space
3491

3492                    pktDone = true;
3493                }
3494            }
3495
3496            // Check for a single file search and the file was not found, in this case return an
3497
// error status
3498

3499            if (wildcardSearch == false && fileCnt == 0)
3500                throw new FileNotFoundException JavaDoc(srchPath);
3501
3502            // Check for a search where the maximum files is set to one, close the search
3503
// immediately.
3504

3505            if (maxFiles == 1 && fileCnt == 1)
3506                searchDone = true;
3507
3508            // Clear the next structure offset, if applicable
3509

3510            FindInfoPacker.clearNextOffset(dataBuf, infoLevl, lastNameOff);
3511
3512            // Pack the parameter block
3513

3514            paramBuf = replyBuf.getParameterBuffer();
3515
3516            paramBuf.putShort(searchId);
3517            paramBuf.putShort(fileCnt);
3518            paramBuf.putShort(ctx.hasMoreFiles() ? 0 : 1);
3519            paramBuf.putShort(0);
3520            paramBuf.putShort(lastNameOff);
3521
3522            // Send the transaction response
3523

3524            SMBSrvTransPacket tpkt = new SMBSrvTransPacket(outPkt.getBuffer());
3525            tpkt.doTransactionResponse(m_sess, replyBuf);
3526
3527            // Debug
3528

3529            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
3530                logger.debug("Search [" + searchId + "] Returned " + fileCnt + " files, dataLen=" + dataBuf.getLength()
3531                        + ", moreFiles=" + ctx.hasMoreFiles());
3532
3533            // Check if the search is complete
3534

3535            if (searchDone == true || ctx.hasMoreFiles() == false)
3536            {
3537
3538                // Debug
3539

3540                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
3541                    logger.debug("End start search [" + searchId + "] (Search complete)");
3542
3543                // Release the search context
3544

3545                m_sess.deallocateSearchSlot(searchId);
3546            }
3547        }
3548        catch (FileNotFoundException JavaDoc ex)
3549        {
3550
3551            // Search path does not exist
3552

3553            m_sess.sendErrorResponseSMB(SMBStatus.NTNoSuchFile, SMBStatus.DOSNoMoreFiles, SMBStatus.ErrDos);
3554        }
3555        catch (PathNotFoundException ex)
3556        {
3557
3558            // Deallocate the search
3559

3560            if (searchId != -1)
3561                m_sess.deallocateSearchSlot(searchId);
3562
3563            // Requested path does not exist
3564

3565            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectPathNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
3566            return;
3567        }
3568        catch (InvalidDeviceInterfaceException ex)
3569        {
3570
3571            // Deallocate the search
3572

3573            if (searchId != -1)
3574                m_sess.deallocateSearchSlot(searchId);
3575
3576            // Failed to get/initialize the disk interface
3577

3578            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
3579        }
3580        catch (UnsupportedInfoLevelException ex)
3581        {
3582
3583            // Deallocate the search
3584

3585            if (searchId != -1)
3586                m_sess.deallocateSearchSlot(searchId);
3587
3588            // Requested information level is not supported
3589

3590            m_sess.sendErrorResponseSMB(SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
3591        }
3592    }
3593
3594    /**
3595     * Process a transact2 file search continue request.
3596     *
3597     * @param tbuf Transaction request details
3598     * @param outPkt SMBSrvPacket
3599     * @exception java.io.IOException If an I/O error occurs
3600     * @exception SMBSrvException If an SMB protocol error occurs
3601     */

3602    protected final void procTrans2FindNext(SrvTransactBuffer tbuf, SMBSrvPacket outPkt) throws java.io.IOException JavaDoc,
3603            SMBSrvException
3604    {
3605
3606        // Get the tree connection details
3607

3608        int treeId = m_smbPkt.getTreeId();
3609        TreeConnection conn = m_sess.findConnection(treeId);
3610
3611        if (conn == null)
3612        {
3613            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
3614            return;
3615        }
3616
3617        // Check if the user has the required access permission
3618

3619        if (conn.hasReadAccess() == false)
3620        {
3621
3622            // User does not have the required access rights
3623

3624            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
3625            return;
3626        }
3627
3628        // Get the search parameters
3629

3630        DataBuffer paramBuf = tbuf.getParameterBuffer();
3631
3632        int searchId = paramBuf.getShort();
3633        int maxFiles = paramBuf.getShort();
3634        int infoLevl = paramBuf.getShort();
3635        int reskey = paramBuf.getInt();
3636        int srchFlag = paramBuf.getShort();
3637
3638        String JavaDoc resumeName = paramBuf.getString(tbuf.isUnicode());
3639
3640        // Access the shared device disk interface
3641

3642        SearchContext ctx = null;
3643        DiskInterface disk = null;
3644
3645        try
3646        {
3647
3648            // Access the disk interface
3649

3650            disk = (DiskInterface) conn.getSharedDevice().getInterface();
3651
3652            // Retrieve the search context
3653

3654            ctx = m_sess.getSearchContext(searchId);
3655            if (ctx == null)
3656            {
3657
3658                // DEBUG
3659

3660                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
3661                    logger.debug("Search context null - [" + searchId + "]");
3662
3663                // Invalid search handle
3664

3665                m_sess.sendErrorResponseSMB(SMBStatus.DOSNoMoreFiles, SMBStatus.ErrDos);
3666                return;
3667            }
3668
3669            // Create the reply transaction buffer
3670

3671            SrvTransactBuffer replyBuf = new SrvTransactBuffer(tbuf);
3672            DataBuffer dataBuf = replyBuf.getDataBuffer();
3673
3674            // Determine the maximum return data length
3675

3676            int maxLen = replyBuf.getReturnDataLimit();
3677
3678            // Debug
3679

3680            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
3681                logger.debug("Continue search [" + searchId + "] - " + resumeName + ", maxFiles=" + maxFiles
3682                        + ", maxLen=" + maxLen + ", infoLevel=" + infoLevl + ", flags=0x"
3683                        + Integer.toHexString(srchFlag));
3684
3685            // Loop until we have filled the return buffer or there are no more files to return
3686

3687            int fileCnt = 0;
3688            int packLen = 0;
3689            int lastNameOff = 0;
3690
3691            // Flag to indicate if resume ids should be returned
3692

3693            boolean resumeIds = false;
3694            if (infoLevl == FindInfoPacker.InfoStandard && (srchFlag & FindFirstNext.ReturnResumeKey) != 0)
3695            {
3696
3697                // Windows servers only seem to return resume keys for the standard information
3698
// level
3699

3700                resumeIds = true;
3701            }
3702
3703            // Flags to indicate packet full or search complete
3704

3705            boolean pktDone = false;
3706            boolean searchDone = false;
3707
3708            FileInfo info = new FileInfo();
3709
3710            while (pktDone == false && fileCnt < maxFiles)
3711            {
3712
3713                // Get file information from the search
3714

3715                if (ctx.nextFileInfo(info) == false)
3716                {
3717
3718                    // No more files
3719

3720                    pktDone = true;
3721                    searchDone = true;
3722                }
3723
3724                // Check if the file information will fit into the return buffer
3725

3726                else if (FindInfoPacker.calcInfoSize(info, infoLevl, false, true) <= maxLen)
3727                {
3728
3729                    // Pack the resume id, if required
3730

3731                    if (resumeIds == true)
3732                    {
3733                        dataBuf.putInt(ctx.getResumeId());
3734                        maxLen -= 4;
3735                    }
3736
3737                    // Save the offset to the last file information structure
3738

3739                    lastNameOff = dataBuf.getPosition();
3740
3741                    // Pack the file information
3742

3743                    packLen = FindInfoPacker.packInfo(info, dataBuf, infoLevl, tbuf.isUnicode());
3744
3745                    // Update the file count for this packet
3746

3747                    fileCnt++;
3748
3749                    // Recalculate the remaining buffer space
3750

3751                    maxLen -= packLen;
3752                }
3753                else
3754                {
3755
3756                    // Set the search restart point
3757

3758                    ctx.restartAt(info);
3759
3760                    // No more buffer space
3761

3762                    pktDone = true;
3763                }
3764            }
3765
3766            // Pack the parameter block
3767

3768            paramBuf = replyBuf.getParameterBuffer();
3769
3770            paramBuf.putShort(fileCnt);
3771            paramBuf.putShort(ctx.hasMoreFiles() ? 0 : 1);
3772            paramBuf.putShort(0);
3773            paramBuf.putShort(lastNameOff);
3774
3775            // Send the transaction response
3776

3777            SMBSrvTransPacket tpkt = new SMBSrvTransPacket(outPkt.getBuffer());
3778            tpkt.doTransactionResponse(m_sess, replyBuf);
3779
3780            // Debug
3781

3782            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
3783                logger.debug("Search [" + searchId + "] Returned " + fileCnt + " files, dataLen=" + dataBuf.getLength()
3784                        + ", moreFiles=" + ctx.hasMoreFiles());
3785
3786            // Check if the search is complete
3787

3788            if (searchDone == true || ctx.hasMoreFiles() == false)
3789            {
3790
3791                // Debug
3792

3793                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
3794                    logger.debug("End start search [" + searchId + "] (Search complete)");
3795
3796                // Release the search context
3797

3798                m_sess.deallocateSearchSlot(searchId);
3799            }
3800        }
3801        catch (FileNotFoundException JavaDoc ex)
3802        {
3803
3804            // Deallocate the search
3805

3806            if (searchId != -1)
3807                m_sess.deallocateSearchSlot(searchId);
3808
3809            // Search path does not exist
3810

3811            m_sess.sendErrorResponseSMB(SMBStatus.DOSNoMoreFiles, SMBStatus.ErrDos);
3812        }
3813        catch (InvalidDeviceInterfaceException ex)
3814        {
3815
3816            // Deallocate the search
3817

3818            if (searchId != -1)
3819                m_sess.deallocateSearchSlot(searchId);
3820
3821            // Failed to get/initialize the disk interface
3822

3823            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
3824        }
3825        catch (UnsupportedInfoLevelException ex)
3826        {
3827
3828            // Deallocate the search
3829

3830            if (searchId != -1)
3831                m_sess.deallocateSearchSlot(searchId);
3832
3833            // Requested information level is not supported
3834

3835            m_sess.sendErrorResponseSMB(SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
3836        }
3837    }
3838
3839    /**
3840     * Process a transact2 file system query request.
3841     *
3842     * @param tbuf Transaction request details
3843     * @param outPkt SMBSrvPacket
3844     * @exception java.io.IOException If an I/O error occurs
3845     * @exception SMBSrvException If an SMB protocol error occurs
3846     */

3847    protected final void procTrans2QueryFileSys(SrvTransactBuffer tbuf, SMBSrvPacket outPkt)
3848            throws java.io.IOException JavaDoc, SMBSrvException
3849    {
3850
3851        // Get the tree connection details
3852

3853        int treeId = m_smbPkt.getTreeId();
3854        TreeConnection conn = m_sess.findConnection(treeId);
3855
3856        if (conn == null)
3857        {
3858            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
3859            return;
3860        }
3861
3862        // Check if the user has the required access permission
3863

3864        if (conn.hasReadAccess() == false)
3865        {
3866
3867            // User does not have the required access rights
3868

3869            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
3870            return;
3871        }
3872
3873        // Get the query file system required information level
3874

3875        DataBuffer paramBuf = tbuf.getParameterBuffer();
3876
3877        int infoLevl = paramBuf.getShort();
3878
3879        // Debug
3880

3881        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
3882            logger.debug("Query File System Info - level = 0x" + Integer.toHexString(infoLevl));
3883
3884        // Access the shared device disk interface
3885

3886        try
3887        {
3888
3889            // Access the disk interface and context
3890

3891            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
3892            DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
3893
3894            // Set the return parameter count, so that the data area position can be calculated.
3895

3896            outPkt.setParameterCount(10);
3897
3898            // Pack the disk information into the data area of the transaction reply
3899

3900            byte[] buf = outPkt.getBuffer();
3901            int prmPos = DataPacker.longwordAlign(outPkt.getByteOffset());
3902            int dataPos = prmPos; // no parameters returned
3903

3904            // Create a data buffer using the SMB packet. The response should always fit into a
3905
// single
3906
// reply packet.
3907

3908            DataBuffer replyBuf = new DataBuffer(buf, dataPos, buf.length - dataPos);
3909
3910            // Determine the information level requested
3911

3912            SrvDiskInfo diskInfo = null;
3913            VolumeInfo volInfo = null;
3914
3915            switch (infoLevl)
3916            {
3917
3918            // Standard disk information
3919

3920            case DiskInfoPacker.InfoStandard:
3921
3922                // Get the disk information
3923

3924                diskInfo = getDiskInformation(disk, diskCtx);
3925
3926                // Pack the disk information into the return data packet
3927

3928                DiskInfoPacker.packStandardInfo(diskInfo, replyBuf);
3929                break;
3930
3931            // Volume label information
3932

3933            case DiskInfoPacker.InfoVolume:
3934
3935                // Get the volume label information
3936

3937                volInfo = getVolumeInformation(disk, diskCtx);
3938
3939                // Pack the volume label information
3940

3941                DiskInfoPacker.packVolumeInfo(volInfo, replyBuf, tbuf.isUnicode());
3942                break;
3943
3944            // Full volume information
3945

3946            case DiskInfoPacker.InfoFsVolume:
3947
3948                // Get the volume information
3949

3950                volInfo = getVolumeInformation(disk, diskCtx);
3951
3952                // Pack the volume information
3953

3954                DiskInfoPacker.packFsVolumeInformation(volInfo, replyBuf, tbuf.isUnicode());
3955                break;
3956
3957            // Filesystem size information
3958

3959            case DiskInfoPacker.InfoFsSize:
3960
3961                // Get the disk information
3962

3963                diskInfo = getDiskInformation(disk, diskCtx);
3964
3965                // Pack the disk information into the return data packet
3966

3967                DiskInfoPacker.packFsSizeInformation(diskInfo, replyBuf);
3968                break;
3969
3970            // Filesystem device information
3971

3972            case DiskInfoPacker.InfoFsDevice:
3973                DiskInfoPacker.packFsDevice(NTIOCtl.DeviceDisk, diskCtx.getDeviceAttributes(), replyBuf);
3974                break;
3975
3976            // Filesystem attribute information
3977

3978            case DiskInfoPacker.InfoFsAttribute:
3979                String JavaDoc fsType = diskCtx.getFilesystemType();
3980                
3981                if (disk instanceof NTFSStreamsInterface)
3982                {
3983
3984                    // Check if NTFS streams are enabled
3985

3986                    NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) disk;
3987                    if (ntfsStreams.hasStreamsEnabled(m_sess, conn))
3988                        fsType = "NTFS";
3989                }
3990
3991                // Pack the filesystem type
3992

3993                DiskInfoPacker.packFsAttribute(diskCtx.getFilesystemAttributes(), 255, fsType, tbuf.isUnicode(),
3994                        replyBuf);
3995                break;
3996
3997            // Mac filesystem information
3998

3999            case DiskInfoPacker.InfoMacFsInfo:
4000
4001                // Check if the filesystem supports NTFS streams
4002
//
4003
// We should only return a valid response to the Macintosh information level if the
4004
// filesystem
4005
// does NOT support NTFS streams. By returning an error status the Thursby DAVE
4006
// software will treat
4007
// the filesystem as a WinXP/2K filesystem with full streams support.
4008

4009                boolean ntfs = false;
4010
4011                if (disk instanceof NTFSStreamsInterface)
4012                {
4013
4014                    // Check if streams are enabled
4015

4016                    NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) disk;
4017                    ntfs = ntfsStreams.hasStreamsEnabled(m_sess, conn);
4018                }
4019
4020                // If the filesystem does not support NTFS streams then send a valid response.
4021

4022                if (ntfs == false)
4023                {
4024
4025                    // Get the disk and volume information
4026

4027                    diskInfo = getDiskInformation(disk, diskCtx);
4028                    volInfo = getVolumeInformation(disk, diskCtx);
4029
4030                    // Pack the disk information into the return data packet
4031

4032                    DiskInfoPacker.packMacFsInformation(diskInfo, volInfo, ntfs, replyBuf);
4033                }
4034                break;
4035
4036            // Filesystem size information, including per user allocation limit
4037

4038            case DiskInfoPacker.InfoFullFsSize:
4039
4040                // Get the disk information
4041

4042                diskInfo = getDiskInformation(disk, diskCtx);
4043                long userLimit = diskInfo.getTotalUnits();
4044
4045                // Pack the disk information into the return data packet
4046

4047                DiskInfoPacker.packFullFsSizeInformation(userLimit, diskInfo, replyBuf);
4048                break;
4049            }
4050
4051            // Check if any data was packed, if not then the information level is not supported
4052

4053            if (replyBuf.getPosition() == dataPos)
4054            {
4055                m_sess.sendErrorResponseSMB(SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
4056                return;
4057            }
4058
4059            int bytCnt = replyBuf.getPosition() - outPkt.getByteOffset();
4060            replyBuf.setEndOfBuffer();
4061            int dataLen = replyBuf.getLength();
4062            SMBSrvTransPacket.initTransactReply(outPkt, 0, prmPos, dataLen, dataPos);
4063            outPkt.setByteCount(bytCnt);
4064
4065            // Send the transact reply
4066

4067            m_sess.sendResponseSMB(outPkt);
4068        }
4069        catch (InvalidDeviceInterfaceException ex)
4070        {
4071
4072            // Failed to get/initialize the disk interface
4073

4074            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
4075            return;
4076        }
4077    }
4078
4079    /**
4080     * Process a transact2 query path information request.
4081     *
4082     * @param tbuf Transaction request details
4083     * @param outPkt SMBSrvPacket
4084     * @exception java.io.IOException If an I/O error occurs
4085     * @exception SMBSrvException If an SMB protocol error occurs
4086     */

4087    protected final void procTrans2QueryPath(SrvTransactBuffer tbuf, SMBSrvPacket outPkt) throws java.io.IOException JavaDoc,
4088            SMBSrvException
4089    {
4090
4091        // Get the tree connection details
4092

4093        int treeId = m_smbPkt.getTreeId();
4094        TreeConnection conn = m_sess.findConnection(treeId);
4095
4096        if (conn == null)
4097        {
4098            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
4099            return;
4100        }
4101
4102        // Check if the user has the required access permission
4103

4104        if (conn.hasReadAccess() == false)
4105        {
4106
4107            // User does not have the required access rights
4108

4109            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
4110            return;
4111        }
4112
4113        // Get the query path information level and file/directory name
4114

4115        DataBuffer paramBuf = tbuf.getParameterBuffer();
4116
4117        int infoLevl = paramBuf.getShort();
4118        paramBuf.skipBytes(4);
4119
4120        String JavaDoc path = paramBuf.getString(tbuf.isUnicode());
4121
4122        // Debug
4123

4124        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
4125            logger.debug("Query Path - level = 0x" + Integer.toHexString(infoLevl) + ", path = " + path);
4126
4127        // Access the shared device disk interface
4128

4129        try
4130        {
4131
4132            // Access the disk interface
4133

4134            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
4135
4136            // Set the return parameter count, so that the data area position can be calculated.
4137

4138            outPkt.setParameterCount(10);
4139
4140            // Pack the file information into the data area of the transaction reply
4141

4142            byte[] buf = outPkt.getBuffer();
4143            int prmPos = DataPacker.longwordAlign(outPkt.getByteOffset());
4144            int dataPos = prmPos + 4;
4145
4146            // Pack the return parametes, EA error offset
4147

4148            outPkt.setPosition(prmPos);
4149            outPkt.packWord(0);
4150
4151            // Create a data buffer using the SMB packet. The response should always fit into a
4152
// single
4153
// reply packet.
4154

4155            DataBuffer replyBuf = new DataBuffer(buf, dataPos, buf.length - dataPos);
4156
4157            // Check if the virtual filesystem supports streams, and streams are enabled
4158

4159            boolean streams = false;
4160
4161            if (disk instanceof NTFSStreamsInterface)
4162            {
4163
4164                // Check if NTFS streams are enabled
4165

4166                NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) disk;
4167                streams = ntfsStreams.hasStreamsEnabled(m_sess, conn);
4168            }
4169
4170            // Check if the path is for an NTFS stream, return an error if streams are not supported or not enabled
4171

4172            if ( streams == false && path.indexOf(FileOpenParams.StreamSeparator) != -1)
4173            {
4174                // NTFS streams not supported, return an error status
4175

4176                m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNameInvalid, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
4177                return;
4178            }
4179            
4180            // Check for the file streams information level
4181

4182            int dataLen = 0;
4183
4184            if (streams == true
4185                    && (infoLevl == FileInfoLevel.PathFileStreamInfo || infoLevl == FileInfoLevel.NTFileStreamInfo))
4186            {
4187
4188                // Debug
4189

4190                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_STREAMS))
4191                    logger.debug("Get NTFS streams list path=" + path);
4192
4193                // Get the list of streams from the share driver
4194

4195                NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) disk;
4196                StreamInfoList streamList = ntfsStreams.getStreamList(m_sess, conn, path);
4197
4198                if (streamList == null)
4199                {
4200                    m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.SRVNonSpecificError,
4201                            SMBStatus.ErrSrv);
4202                    return;
4203                }
4204
4205                // Pack the file streams information into the return data packet
4206

4207                dataLen = QueryInfoPacker.packStreamFileInfo(streamList, replyBuf, true);
4208            }
4209            else
4210            {
4211
4212                // Get the file information
4213

4214                FileInfo fileInfo = disk.getFileInformation(m_sess, conn, path);
4215
4216                if (fileInfo == null)
4217                {
4218                    m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound,
4219                                    SMBStatus.ErrDos);
4220                    return;
4221                }
4222
4223                // Pack the file information into the return data packet
4224

4225                dataLen = QueryInfoPacker.packInfo(fileInfo, replyBuf, infoLevl, true);
4226            }
4227
4228            // Check if any data was packed, if not then the information level is not supported
4229

4230            if (dataLen == 0)
4231            {
4232                m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError,
4233                        SMBStatus.ErrSrv);
4234                return;
4235            }
4236
4237            SMBSrvTransPacket.initTransactReply(outPkt, 2, prmPos, dataLen, dataPos);
4238            outPkt.setByteCount(replyBuf.getPosition() - outPkt.getByteOffset());
4239
4240            // Send the transact reply
4241

4242            m_sess.sendResponseSMB(outPkt);
4243        }
4244        catch (AccessDeniedException ex)
4245        {
4246
4247            // Not allowed to access the file/folder
4248

4249            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
4250            return;
4251        }
4252        catch (FileNotFoundException JavaDoc ex)
4253        {
4254
4255            // Requested file does not exist
4256

4257            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
4258            return;
4259        }
4260        catch (PathNotFoundException ex)
4261        {
4262
4263            // Requested path does not exist
4264

4265            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectPathNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
4266            return;
4267        }
4268        catch (InvalidDeviceInterfaceException ex)
4269        {
4270
4271            // Failed to get/initialize the disk interface
4272

4273            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
4274            return;
4275        }
4276        catch (UnsupportedInfoLevelException ex)
4277        {
4278
4279            // Requested information level is not supported
4280

4281            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
4282            return;
4283        }
4284    }
4285
4286    /**
4287     * Process a transact2 query file information (via handle) request.
4288     *
4289     * @param tbuf Transaction request details
4290     * @param outPkt SMBSrvPacket
4291     * @exception java.io.IOException If an I/O error occurs
4292     * @exception SMBSrvException SMB protocol exception
4293     */

4294    protected final void procTrans2QueryFile(SrvTransactBuffer tbuf, SMBSrvPacket outPkt) throws java.io.IOException JavaDoc,
4295            SMBSrvException
4296    {
4297
4298        // Get the tree connection details
4299

4300        int treeId = m_smbPkt.getTreeId();
4301        TreeConnection conn = m_sess.findConnection(treeId);
4302
4303        if (conn == null)
4304        {
4305            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
4306            return;
4307        }
4308
4309        // Check if the user has the required access permission
4310

4311        if (conn.hasReadAccess() == false)
4312        {
4313
4314            // User does not have the required access rights
4315

4316            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
4317            return;
4318        }
4319
4320        // Get the file id and query path information level
4321

4322        DataBuffer paramBuf = tbuf.getParameterBuffer();
4323
4324        int fid = paramBuf.getShort();
4325        int infoLevl = paramBuf.getShort();
4326
4327        // Get the file details via the file id
4328

4329        NetworkFile netFile = conn.findFile(fid);
4330
4331        if (netFile == null)
4332        {
4333            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos);
4334            return;
4335        }
4336
4337        // Debug
4338

4339        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
4340            logger.debug("Query File - level=0x" + Integer.toHexString(infoLevl) + ", fid=" + fid + ", stream="
4341                    + netFile.getStreamId() + ", name=" + netFile.getFullName());
4342
4343        // Access the shared device disk interface
4344

4345        try
4346        {
4347
4348            // Access the disk interface
4349

4350            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
4351
4352            // Set the return parameter count, so that the data area position can be calculated.
4353

4354            outPkt.setParameterCount(10);
4355
4356            // Pack the file information into the data area of the transaction reply
4357

4358            byte[] buf = outPkt.getBuffer();
4359            int prmPos = DataPacker.longwordAlign(outPkt.getByteOffset());
4360            int dataPos = prmPos + 4;
4361
4362            // Pack the return parametes, EA error offset
4363

4364            outPkt.setPosition(prmPos);
4365            outPkt.packWord(0);
4366
4367            // Create a data buffer using the SMB packet. The response should always fit into a
4368
// single
4369
// reply packet.
4370

4371            DataBuffer replyBuf = new DataBuffer(buf, dataPos, buf.length - dataPos);
4372
4373            // Check if the virtual filesystem supports streams, and streams are enabled
4374

4375            boolean streams = false;
4376
4377            if (disk instanceof NTFSStreamsInterface)
4378            {
4379
4380                // Check if NTFS streams are enabled
4381

4382                NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) disk;
4383                streams = ntfsStreams.hasStreamsEnabled(m_sess, conn);
4384            }
4385
4386            // Check for the file streams information level
4387

4388            int dataLen = 0;
4389
4390            if (streams == true
4391                    && (infoLevl == FileInfoLevel.PathFileStreamInfo || infoLevl == FileInfoLevel.NTFileStreamInfo))
4392            {
4393
4394                // Debug
4395

4396                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_STREAMS))
4397                    logger.debug("Get NTFS streams list fid=" + fid + ", name=" + netFile.getFullName());
4398
4399                // Get the list of streams from the share driver
4400

4401                NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) disk;
4402                StreamInfoList streamList = ntfsStreams.getStreamList(m_sess, conn, netFile.getFullName());
4403
4404                if (streamList == null)
4405                {
4406                    m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.SRVNonSpecificError,
4407                            SMBStatus.ErrSrv);
4408                    return;
4409                }
4410
4411                // Pack the file streams information into the return data packet
4412

4413                dataLen = QueryInfoPacker.packStreamFileInfo(streamList, replyBuf, true);
4414            }
4415            else
4416            {
4417
4418                // Get the file information
4419

4420                FileInfo fileInfo = disk.getFileInformation(m_sess, conn, netFile.getFullNameStream());
4421
4422                if (fileInfo == null)
4423                {
4424                    m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.SRVNonSpecificError,
4425                            SMBStatus.ErrSrv);
4426                    return;
4427                }
4428
4429                // Pack the file information into the return data packet
4430

4431                dataLen = QueryInfoPacker.packInfo(fileInfo, replyBuf, infoLevl, true);
4432            }
4433
4434            // Check if any data was packed, if not then the information level is not supported
4435

4436            if (dataLen == 0)
4437            {
4438                m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError,
4439                        SMBStatus.ErrSrv);
4440                return;
4441            }
4442
4443            SMBSrvTransPacket.initTransactReply(outPkt, 2, prmPos, dataLen, dataPos);
4444            outPkt.setByteCount(replyBuf.getPosition() - outPkt.getByteOffset());
4445
4446            // Send the transact reply
4447

4448            m_sess.sendResponseSMB(outPkt);
4449        }
4450        catch (AccessDeniedException ex)
4451        {
4452
4453            // Not allowed to access the file/folder
4454

4455            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
4456            return;
4457        }
4458        catch (FileNotFoundException JavaDoc ex)
4459        {
4460
4461            // Requested file does not exist
4462

4463            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
4464            return;
4465        }
4466        catch (PathNotFoundException ex)
4467        {
4468
4469            // Requested path does not exist
4470

4471            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectPathNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
4472            return;
4473        }
4474        catch (InvalidDeviceInterfaceException ex)
4475        {
4476
4477            // Failed to get/initialize the disk interface
4478

4479            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
4480            return;
4481        }
4482        catch (UnsupportedInfoLevelException ex)
4483        {
4484
4485            // Requested information level is not supported
4486

4487            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
4488            return;
4489        }
4490    }
4491
4492    /**
4493     * Process a transact2 set file information (via handle) request.
4494     *
4495     * @param tbuf Transaction request details
4496     * @param outPkt SMBSrvPacket
4497     * @exception java.io.IOException If an I/O error occurs
4498     * @exception SMBSrvException SMB protocol exception
4499     */

4500    protected final void procTrans2SetFile(SrvTransactBuffer tbuf, SMBSrvPacket outPkt) throws java.io.IOException JavaDoc,
4501            SMBSrvException
4502    {
4503
4504        // Get the tree connection details
4505

4506        int treeId = m_smbPkt.getTreeId();
4507        TreeConnection conn = m_sess.findConnection(treeId);
4508
4509        if (conn == null)
4510        {
4511            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
4512            return;
4513        }
4514
4515        // Check if the user has the required access permission
4516

4517        if (conn.hasWriteAccess() == false)
4518        {
4519
4520            // User does not have the required access rights
4521

4522            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
4523            return;
4524        }
4525
4526        // Get the file id and information level
4527

4528        DataBuffer paramBuf = tbuf.getParameterBuffer();
4529
4530        int fid = paramBuf.getShort();
4531        int infoLevl = paramBuf.getShort();
4532
4533        // Get the file details via the file id
4534

4535        NetworkFile netFile = conn.findFile(fid);
4536
4537        if (netFile == null)
4538        {
4539            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos);
4540            return;
4541        }
4542
4543        // Debug
4544

4545        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
4546            logger.debug("Set File - level=0x" + Integer.toHexString(infoLevl) + ", fid=" + fid + ", name="
4547                    + netFile.getFullName());
4548
4549        // Access the shared device disk interface
4550

4551        try
4552        {
4553
4554            // Access the disk interface
4555

4556            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
4557
4558            // Process the set file information request
4559

4560            DataBuffer dataBuf = tbuf.getDataBuffer();
4561            FileInfo finfo = null;
4562
4563            switch (infoLevl)
4564            {
4565
4566            // Set basic file information (dates/attributes)
4567

4568            case FileInfoLevel.SetBasicInfo:
4569
4570                // Create the file information template
4571

4572                int setFlags = 0;
4573                finfo = new FileInfo(netFile.getFullName(), 0, -1);
4574
4575                // Set the creation date/time, if specified
4576

4577                long timeNow = System.currentTimeMillis();
4578
4579                long nttim = dataBuf.getLong();
4580                boolean hasSetTime = false;
4581
4582                if (nttim != 0L)
4583                {
4584                    if (nttim != -1L)
4585                    {
4586                        finfo.setCreationDateTime(NTTime.toJavaDate(nttim));
4587                        setFlags += FileInfo.SetCreationDate;
4588                    }
4589                    hasSetTime = true;
4590                }
4591
4592                // Set the last access date/time, if specified
4593

4594                nttim = dataBuf.getLong();
4595
4596                if (nttim != 0L)
4597                {
4598                    if (nttim != -1L)
4599                    {
4600                        finfo.setAccessDateTime(NTTime.toJavaDate(nttim));
4601                        setFlags += FileInfo.SetAccessDate;
4602                    }
4603                    else
4604                    {
4605                        finfo.setAccessDateTime(timeNow);
4606                        setFlags += FileInfo.SetAccessDate;
4607                    }
4608                    hasSetTime = true;
4609                }
4610
4611                // Set the last write date/time, if specified
4612

4613                nttim = dataBuf.getLong();
4614
4615                if (nttim > 0L)
4616                {
4617                    if (nttim != -1L)
4618                    {
4619                        finfo.setModifyDateTime(NTTime.toJavaDate(nttim));
4620                        setFlags += FileInfo.SetModifyDate;
4621                    }
4622                    else
4623                    {
4624                        finfo.setModifyDateTime(timeNow);
4625                        setFlags += FileInfo.SetModifyDate;
4626                    }
4627                    hasSetTime = true;
4628                }
4629
4630                // Set the modify date/time, if specified
4631

4632                nttim = dataBuf.getLong();
4633
4634                if (nttim > 0L)
4635                {
4636                    if (nttim != -1L)
4637                    {
4638                        finfo.setChangeDateTime(NTTime.toJavaDate(nttim));
4639                        setFlags += FileInfo.SetChangeDate;
4640                    }
4641                    hasSetTime = true;
4642                }
4643
4644                // Set the attributes
4645

4646                int attr = dataBuf.getInt();
4647                int unknown = dataBuf.getInt();
4648
4649                if (hasSetTime == false && unknown == 0)
4650                {
4651                    finfo.setFileAttributes(attr);
4652                    setFlags += FileInfo.SetAttributes;
4653                }
4654
4655                // Set the file information for the specified file/directory
4656

4657                finfo.setFileInformationFlags(setFlags);
4658                disk.setFileInformation(m_sess, conn, netFile.getFullName(), finfo);
4659
4660                // Debug
4661

4662                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
4663                    logger.debug(" Set Basic Info [" + treeId + "] name=" + netFile.getFullName() + ", attr=0x"
4664                            + Integer.toHexString(attr) + ", setTime=" + hasSetTime + ", setFlags=0x"
4665                            + Integer.toHexString(setFlags) + ", unknown=" + unknown);
4666                break;
4667
4668            // Set end of file position for a file
4669

4670            case FileInfoLevel.SetEndOfFileInfo:
4671
4672                // Get the new end of file position
4673

4674                long eofPos = dataBuf.getLong();
4675
4676                // Set the new end of file position
4677

4678                disk.truncateFile(m_sess, conn, netFile, eofPos);
4679
4680                // Debug
4681

4682                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
4683                    logger.debug(" Set end of file position fid=" + fid + ", eof=" + eofPos);
4684                break;
4685
4686            // Set the allocation size for a file
4687

4688            case FileInfoLevel.SetAllocationInfo:
4689
4690                // Get the new end of file position
4691

4692                long allocSize = dataBuf.getLong();
4693
4694                // Set the new end of file position
4695

4696                disk.truncateFile(m_sess, conn, netFile, allocSize);
4697
4698                // Debug
4699

4700                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
4701                    logger.debug(" Set allocation size fid=" + fid + ", allocSize=" + allocSize);
4702                break;
4703
4704            // Rename a stream
4705

4706            case FileInfoLevel.NTFileRenameInfo:
4707
4708                // Check if the virtual filesystem supports streams, and streams are enabled
4709

4710                boolean streams = false;
4711
4712                if (disk instanceof NTFSStreamsInterface)
4713                {
4714
4715                    // Check if NTFS streams are enabled
4716

4717                    NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) disk;
4718                    streams = ntfsStreams.hasStreamsEnabled(m_sess, conn);
4719                }
4720
4721                // If streams are not supported or are not enabled then return an error status
4722

4723                if (streams == false)
4724                {
4725
4726                    // Return a not supported error status
4727

4728                    m_sess.sendErrorResponseSMB(SMBStatus.NTNotSupported, SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
4729                    return;
4730                }
4731
4732                // Get the overwrite flag
4733

4734                boolean overwrite = dataBuf.getByte() == 1 ? true : false;
4735                dataBuf.skipBytes(3);
4736
4737                int rootFid = dataBuf.getInt();
4738                int nameLen = dataBuf.getInt();
4739                String JavaDoc newName = dataBuf.getString(nameLen, true);
4740
4741                // Debug
4742

4743                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
4744                    logger.debug(" Set rename fid=" + fid + ", newName=" + newName + ", overwrite=" + overwrite
4745                            + ", rootFID=" + rootFid);
4746
4747                // Check if the new path contains a directory, only rename of a stream on the same
4748
// file is supported
4749

4750                if (newName.indexOf(FileName.DOS_SEPERATOR_STR) != -1)
4751                {
4752
4753                    // Return a not supported error status
4754

4755                    m_sess.sendErrorResponseSMB(SMBStatus.NTNotSupported, SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
4756                    return;
4757                }
4758
4759                // Debug
4760

4761                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_STREAMS))
4762                    logger.debug("Rename stream fid=" + fid + ", name=" + netFile.getFullNameStream() + ", newName="
4763                            + newName + ", overwrite=" + overwrite);
4764
4765                // Rename the stream
4766

4767                NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) disk;
4768                ntfsStreams.renameStream(m_sess, conn, netFile.getFullNameStream(), newName, overwrite);
4769                break;
4770
4771            // Mark or unmark a file/directory for delete
4772

4773            case FileInfoLevel.SetDispositionInfo:
4774            case FileInfoLevel.NTFileDispositionInfo:
4775
4776                // Get the delete flag
4777

4778                int flag = dataBuf.getByte();
4779                boolean delFlag = flag == 1 ? true : false;
4780
4781                // Call the filesystem driver set file information to see if the file can be marked
4782
// for
4783
// delete.
4784

4785                FileInfo delInfo = new FileInfo();
4786                delInfo.setDeleteOnClose(delFlag);
4787                delInfo.setFileInformationFlags(FileInfo.SetDeleteOnClose);
4788
4789                disk.setFileInformation(m_sess, conn, netFile.getFullName(), delInfo);
4790
4791                // Mark/unmark the file/directory for deletion
4792

4793                netFile.setDeleteOnClose(delFlag);
4794
4795                // Debug
4796

4797                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
4798                    logger.debug(" Set file disposition fid=" + fid + ", name=" + netFile.getName() + ", delete="
4799                            + delFlag);
4800                break;
4801            }
4802
4803            // Set the return parameter count, so that the data area position can be calculated.
4804

4805            outPkt.setParameterCount(10);
4806
4807            // Pack the return information into the data area of the transaction reply
4808

4809            byte[] buf = outPkt.getBuffer();
4810            int prmPos = outPkt.getByteOffset();
4811
4812            // Longword align the parameters, return an unknown word parameter
4813
//
4814
// Note: Make sure the data offset is on a longword boundary, NT has problems if this is
4815
// not done
4816

4817            prmPos = DataPacker.longwordAlign(prmPos);
4818            DataPacker.putIntelShort(0, buf, prmPos);
4819
4820            SMBSrvTransPacket.initTransactReply(outPkt, 2, prmPos, 0, prmPos + 4);
4821            outPkt.setByteCount((prmPos - outPkt.getByteOffset()) + 4);
4822
4823            // Send the transact reply
4824

4825            m_sess.sendResponseSMB(outPkt);
4826
4827            // Check if there are any file/directory change notify requests active
4828

4829            DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
4830
4831            if (diskCtx.hasChangeHandler() && netFile.getFullName() != null)
4832            {
4833
4834                // Get the change handler
4835

4836                NotifyChangeHandler changeHandler = diskCtx.getChangeHandler();
4837
4838                // Check for file attributes and last write time changes
4839

4840                if (finfo != null)
4841                {
4842
4843                    // File attributes changed
4844

4845                    if (finfo.hasSetFlag(FileInfo.SetAttributes))
4846                        changeHandler.notifyAttributesChanged(netFile.getFullName(), netFile.isDirectory());
4847
4848                    // Last write time changed
4849

4850                    if (finfo.hasSetFlag(FileInfo.SetModifyDate))
4851                        changeHandler.notifyLastWriteTimeChanged(netFile.getFullName(), netFile.isDirectory());
4852                }
4853                else if (infoLevl == FileInfoLevel.SetAllocationInfo || infoLevl == FileInfoLevel.SetEndOfFileInfo)
4854                {
4855
4856                    // File size changed
4857

4858                    changeHandler.notifyFileSizeChanged(netFile.getFullName());
4859                }
4860            }
4861        }
4862        catch (FileNotFoundException JavaDoc ex)
4863        {
4864
4865            // Requested file does not exist
4866

4867            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
4868            return;
4869        }
4870        catch (AccessDeniedException ex)
4871        {
4872
4873            // Not allowed to change file attributes/settings
4874

4875            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
4876            return;
4877        }
4878        catch (DiskFullException ex)
4879        {
4880
4881            // Disk is full
4882

4883            m_sess.sendErrorResponseSMB(SMBStatus.NTDiskFull, SMBStatus.HRDWriteFault, SMBStatus.ErrHrd);
4884            return;
4885        }
4886        catch (InvalidDeviceInterfaceException ex)
4887        {
4888
4889            // Failed to get/initialize the disk interface
4890

4891            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
4892            return;
4893        }
4894    }
4895
4896    /**
4897     * Process a transact2 set path information request.
4898     *
4899     * @param tbuf Transaction request details
4900     * @param outPkt SMBSrvPacket
4901     * @exception java.io.IOException If an I/O error occurs
4902     * @exception SMBSrvException SMB protocol exception
4903     */

4904    protected final void procTrans2SetPath(SrvTransactBuffer tbuf, SMBSrvPacket outPkt) throws java.io.IOException JavaDoc,
4905            SMBSrvException
4906    {
4907
4908        // Get the tree connection details
4909

4910        int treeId = m_smbPkt.getTreeId();
4911        TreeConnection conn = m_sess.findConnection(treeId);
4912
4913        if (conn == null)
4914        {
4915            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
4916            return;
4917        }
4918
4919        // Check if the user has the required access permission
4920

4921        if (conn.hasWriteAccess() == false)
4922        {
4923
4924            // User does not have the required access rights
4925

4926            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
4927            return;
4928        }
4929
4930        // Get the path and information level
4931

4932        DataBuffer paramBuf = tbuf.getParameterBuffer();
4933
4934        int infoLevl = paramBuf.getShort();
4935        paramBuf.skipBytes(4);
4936
4937        String JavaDoc path = paramBuf.getString(tbuf.isUnicode());
4938
4939        // Debug
4940

4941        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
4942            logger.debug("Set Path - path=" + path + ", level=0x" + Integer.toHexString(infoLevl));
4943
4944        // Access the shared device disk interface
4945

4946        try
4947        {
4948
4949            // Access the disk interface
4950

4951            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
4952
4953            // Process the set file information request
4954

4955            DataBuffer dataBuf = tbuf.getDataBuffer();
4956            FileInfo finfo = null;
4957
4958            switch (infoLevl)
4959            {
4960
4961            // Set standard file information (dates/attributes)
4962

4963            case FileInfoLevel.SetStandard:
4964
4965                // Create the file information template
4966

4967                int setFlags = 0;
4968                finfo = new FileInfo(path, 0, -1);
4969
4970                // Set the creation date/time, if specified
4971

4972                int smbDate = dataBuf.getShort();
4973                int smbTime = dataBuf.getShort();
4974
4975                boolean hasSetTime = false;
4976
4977                if (smbDate != 0 && smbTime != 0)
4978                {
4979                    finfo.setCreationDateTime(new SMBDate(smbDate, smbTime).getTime());
4980                    setFlags += FileInfo.SetCreationDate;
4981                    hasSetTime = true;
4982                }
4983
4984                // Set the last access date/time, if specified
4985

4986                smbDate = dataBuf.getShort();
4987                smbTime = dataBuf.getShort();
4988
4989                if (smbDate != 0 && smbTime != 0)
4990                {
4991                    finfo.setAccessDateTime(new SMBDate(smbDate, smbTime).getTime());
4992                    setFlags += FileInfo.SetAccessDate;
4993                    hasSetTime = true;
4994                }
4995
4996                // Set the last write date/time, if specified
4997

4998                smbDate = dataBuf.getShort();
4999                smbTime = dataBuf.getShort();
5000
5001                if (smbDate != 0 && smbTime != 0)
5002                {
5003                    finfo.setModifyDateTime(new SMBDate(smbDate, smbTime).getTime());
5004                    setFlags += FileInfo.SetModifyDate;
5005                    hasSetTime = true;
5006                }
5007
5008                // Set the file size/allocation size
5009

5010                int fileSize = dataBuf.getInt();
5011                if (fileSize != 0)
5012                {
5013                    finfo.setFileSize(fileSize);
5014                    setFlags += FileInfo.SetFileSize;
5015                }
5016
5017                fileSize = dataBuf.getInt();
5018                if (fileSize != 0)
5019                {
5020                    finfo.setAllocationSize(fileSize);
5021                    setFlags += FileInfo.SetAllocationSize;
5022                }
5023
5024                // Set the attributes
5025

5026                int attr = dataBuf.getInt();
5027                int eaListLen = dataBuf.getInt();
5028
5029                if (hasSetTime == false && eaListLen == 0)
5030                {
5031                    finfo.setFileAttributes(attr);
5032                    setFlags += FileInfo.SetAttributes;
5033                }
5034
5035                // Set the file information for the specified file/directory
5036

5037                finfo.setFileInformationFlags(setFlags);
5038                disk.setFileInformation(m_sess, conn, path, finfo);
5039
5040                // Debug
5041

5042                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_INFO))
5043                    logger.debug(" Set Standard Info [" + treeId + "] name=" + path + ", attr=0x"
5044                            + Integer.toHexString(attr) + ", setTime=" + hasSetTime + ", setFlags=0x"
5045                            + Integer.toHexString(setFlags) + ", eaListLen=" + eaListLen);
5046                break;
5047            }
5048
5049            // Set the return parameter count, so that the data area position can be calculated.
5050

5051            outPkt.setParameterCount(10);
5052
5053            // Pack the return information into the data area of the transaction reply
5054

5055            byte[] buf = outPkt.getBuffer();
5056            int prmPos = outPkt.getByteOffset();
5057
5058            // Longword align the parameters, return an unknown word parameter
5059
//
5060
// Note: Make sure the data offset is on a longword boundary, NT has problems if this is
5061
// not done
5062

5063            prmPos = DataPacker.longwordAlign(prmPos);
5064            DataPacker.putIntelShort(0, buf, prmPos);
5065
5066            SMBSrvTransPacket.initTransactReply(outPkt, 2, prmPos, 0, prmPos + 4);
5067            outPkt.setByteCount((prmPos - outPkt.getByteOffset()) + 4);
5068
5069            // Send the transact reply
5070

5071            m_sess.sendResponseSMB(outPkt);
5072
5073            // Check if there are any file/directory change notify requests active
5074

5075            DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
5076
5077            if (diskCtx.hasChangeHandler() && path != null)
5078            {
5079
5080                // Get the change handler
5081

5082                NotifyChangeHandler changeHandler = diskCtx.getChangeHandler();
5083
5084                // Check for file attributes and last write time changes
5085

5086                if (finfo != null)
5087                {
5088
5089                    // Check if the path refers to a file or directory
5090

5091                    int fileSts = disk.fileExists(m_sess, conn, path);
5092
5093                    // File attributes changed
5094

5095                    if (finfo.hasSetFlag(FileInfo.SetAttributes))
5096                        changeHandler.notifyAttributesChanged(path, fileSts == FileStatus.DirectoryExists ? true
5097                                : false);
5098
5099                    // Last write time changed
5100

5101                    if (finfo.hasSetFlag(FileInfo.SetModifyDate))
5102                        changeHandler.notifyLastWriteTimeChanged(path, fileSts == FileStatus.DirectoryExists ? true
5103                                : false);
5104                }
5105            }
5106        }
5107        catch (FileNotFoundException JavaDoc ex)
5108        {
5109
5110            // Requested file does not exist
5111

5112            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
5113            return;
5114        }
5115        catch (AccessDeniedException ex)
5116        {
5117
5118            // Not allowed to change file attributes/settings
5119

5120            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
5121            return;
5122        }
5123        catch (DiskFullException ex)
5124        {
5125
5126            // Disk is full
5127

5128            m_sess.sendErrorResponseSMB(SMBStatus.NTDiskFull, SMBStatus.HRDWriteFault, SMBStatus.ErrHrd);
5129            return;
5130        }
5131        catch (InvalidDeviceInterfaceException ex)
5132        {
5133
5134            // Failed to get/initialize the disk interface
5135

5136            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
5137            return;
5138        }
5139    }
5140
5141    /**
5142     * Process the file write request.
5143     *
5144     * @param outPkt SMBSrvPacket
5145     */

5146    protected final void procWriteAndX(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
5147    {
5148
5149        // Check that the received packet looks like a valid write andX request
5150

5151        if (m_smbPkt.checkPacketIsValid(12, 0) == false)
5152        {
5153            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
5154            return;
5155        }
5156
5157        // Get the tree connection details
5158

5159        int treeId = m_smbPkt.getTreeId();
5160        TreeConnection conn = m_sess.findConnection(treeId);
5161
5162        if (conn == null)
5163        {
5164            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
5165            return;
5166        }
5167
5168        // Check if the user has the required access permission
5169

5170        if (conn.hasWriteAccess() == false)
5171        {
5172
5173            // User does not have the required access rights
5174

5175            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
5176            return;
5177        }
5178
5179        // If the connection is to the IPC$ remote admin named pipe pass the request to the IPC
5180
// handler.
5181

5182        if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
5183        {
5184
5185            // Use the IPC$ handler to process the request
5186

5187            IPCHandler.processIPCRequest(m_sess, outPkt);
5188            return;
5189        }
5190
5191        // Extract the write file parameters
5192

5193        int fid = m_smbPkt.getParameter(2);
5194        long offset = (long) (((long) m_smbPkt.getParameterLong(3)) & 0xFFFFFFFFL); // bottom 32bits
5195
// of file
5196
// offset
5197
int dataPos = m_smbPkt.getParameter(11) + RFCNetBIOSProtocol.HEADER_LEN;
5198
5199        int dataLen = m_smbPkt.getParameter(10);
5200        int dataLenHigh = 0;
5201
5202        if (m_smbPkt.getReceivedLength() > 0xFFFF)
5203            dataLenHigh = m_smbPkt.getParameter(9) & 0x0001;
5204
5205        if (dataLenHigh > 0)
5206            dataLen += (dataLenHigh << 16);
5207
5208        // Check for the NT format request that has the top 32bits of the file offset
5209

5210        if (m_smbPkt.getParameterCount() == 14)
5211        {
5212            long topOff = (long) (((long) m_smbPkt.getParameterLong(12)) & 0xFFFFFFFFL);
5213            offset += topOff << 32;
5214        }
5215
5216        NetworkFile netFile = conn.findFile(fid);
5217
5218        if (netFile == null)
5219        {
5220            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidHandle, SMBStatus.ErrDos);
5221            return;
5222        }
5223
5224        // Debug
5225

5226        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO))
5227            logger.debug("File Write AndX [" + netFile.getFileId() + "] : Size=" + dataLen + " ,Pos=" + offset);
5228
5229        // Write data to the file
5230

5231        byte[] buf = m_smbPkt.getBuffer();
5232        int wrtlen = 0;
5233
5234        // Access the disk interface and write to the file
5235

5236        try
5237        {
5238
5239            // Access the disk interface that is associated with the shared device
5240

5241            DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
5242
5243            // Write to the file
5244

5245            wrtlen = disk.writeFile(m_sess, conn, netFile, buf, dataPos, dataLen, offset);
5246        }
5247        catch (InvalidDeviceInterfaceException ex)
5248        {
5249
5250            // Failed to get/initialize the disk interface
5251

5252            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
5253            return;
5254        }
5255        catch (AccessDeniedException ex)
5256        {
5257
5258            // Debug
5259

5260            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO))
5261                logger.debug("File Write Error [" + netFile.getFileId() + "] : " + ex.toString());
5262
5263            // Not allowed to write to the file
5264

5265            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
5266            return;
5267        }
5268        catch (LockConflictException ex)
5269        {
5270
5271            // Debug
5272

5273            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_LOCK))
5274                logger.debug("Write Lock Error [" + netFile.getFileId() + "] : Size=" + dataLen + " ,Pos=" + offset);
5275
5276            // File is locked
5277

5278            m_sess.sendErrorResponseSMB(SMBStatus.NTLockConflict, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
5279            return;
5280        }
5281        catch (DiskFullException ex)
5282        {
5283
5284            // Debug
5285

5286            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO))
5287                logger.debug("Write Quota Error [" + netFile.getFileId() + "] Disk full : Size=" + dataLen + " ,Pos="
5288                        + offset);
5289
5290            // Disk is full
5291

5292            m_sess.sendErrorResponseSMB(SMBStatus.NTDiskFull, SMBStatus.HRDWriteFault, SMBStatus.ErrHrd);
5293            return;
5294        }
5295        catch (java.io.IOException JavaDoc ex)
5296        {
5297
5298            // Debug
5299

5300            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILEIO))
5301                logger.debug("File Write Error [" + netFile.getFileId() + "] : " + ex.toString());
5302
5303            // Failed to read the file
5304

5305            m_sess.sendErrorResponseSMB(SMBStatus.HRDWriteFault, SMBStatus.ErrHrd);
5306            return;
5307        }
5308
5309        // Return the count of bytes actually written
5310

5311        outPkt.setParameterCount(6);
5312        outPkt.setAndXCommand(0xFF);
5313        outPkt.setParameter(1, 0); // AndX offset
5314
outPkt.setParameter(2, wrtlen);
5315        outPkt.setParameter(3, 0xFFFF);
5316
5317        if (dataLenHigh > 0)
5318        {
5319            outPkt.setParameter(4, dataLen >> 16);
5320            outPkt.setParameter(5, 0);
5321        }
5322        else
5323        {
5324            outPkt.setParameterLong(4, 0);
5325        }
5326
5327        outPkt.setByteCount(0);
5328        outPkt.setParameter(1, outPkt.getLength());
5329
5330        // Send the write response
5331

5332        m_sess.sendResponseSMB(outPkt);
5333
5334        // Report file size change notifications every so often
5335
//
5336
// We do not report every write due to the increased overhead of change notifications
5337

5338        DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
5339
5340        if (netFile.getWriteCount() % FileSizeChangeRate == 0 && diskCtx.hasChangeHandler()
5341                && netFile.getFullName() != null)
5342        {
5343
5344            // Get the change handler
5345

5346            NotifyChangeHandler changeHandler = diskCtx.getChangeHandler();
5347
5348            // File size changed
5349

5350            changeHandler.notifyFileSizeChanged(netFile.getFullName());
5351        }
5352    }
5353
5354    /**
5355     * Process the file create/open request.
5356     *
5357     * @param outPkt SMBSrvPacket
5358     */

5359    protected final void procNTCreateAndX(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
5360    {
5361
5362        // Check that the received packet looks like a valid NT create andX request
5363

5364        if (m_smbPkt.checkPacketIsValid(24, 1) == false)
5365        {
5366            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
5367            return;
5368        }
5369
5370        // Get the tree connection details
5371

5372        int treeId = m_smbPkt.getTreeId();
5373        TreeConnection conn = m_sess.findConnection(treeId);
5374
5375        if (conn == null)
5376        {
5377            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
5378            return;
5379        }
5380
5381        // Check if the user has the required access permission
5382

5383        if (conn.hasReadAccess() == false)
5384        {
5385
5386            // User does not have the required access rights
5387

5388            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
5389            return;
5390        }
5391
5392        // If the connection is to the IPC$ remote admin named pipe pass the request to the IPC
5393
// handler. If the device is
5394
// not a disk type device then return an error.
5395

5396        if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
5397        {
5398
5399            // Use the IPC$ handler to process the request
5400

5401            IPCHandler.processIPCRequest(m_sess, outPkt);
5402            return;
5403        }
5404        else if (conn.getSharedDevice().getType() != ShareType.DISK)
5405        {
5406
5407            // Return an access denied error
5408

5409            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
5410            return;
5411        }
5412
5413        // Extract the NT create andX parameters
5414

5415        NTParameterPacker prms = new NTParameterPacker(m_smbPkt.getBuffer(), SMBSrvPacket.PARAMWORDS + 5);
5416
5417        int nameLen = prms.unpackWord();
5418        int flags = prms.unpackInt();
5419        int rootFID = prms.unpackInt();
5420        int accessMask = prms.unpackInt();
5421        long allocSize = prms.unpackLong();
5422        int attrib = prms.unpackInt();
5423        int shrAccess = prms.unpackInt();
5424        int createDisp = prms.unpackInt();
5425        int createOptn = prms.unpackInt();
5426        int impersonLev = prms.unpackInt();
5427        int secFlags = prms.unpackByte();
5428
5429        // Extract the filename string
5430

5431        String JavaDoc fileName = DataPacker.getUnicodeString(m_smbPkt.getBuffer(), DataPacker.wordAlign(m_smbPkt
5432                .getByteOffset()), nameLen / 2);
5433        if (fileName == null)
5434        {
5435            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
5436            return;
5437        }
5438
5439        // Access the disk interface that is associated with the shared device
5440

5441        DiskInterface disk = null;
5442        try
5443        {
5444
5445            // Get the disk interface for the share
5446

5447            disk = (DiskInterface) conn.getSharedDevice().getInterface();
5448        }
5449        catch (InvalidDeviceInterfaceException ex)
5450        {
5451
5452            // Failed to get/initialize the disk interface
5453

5454            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
5455            return;
5456        }
5457
5458        // Check if the file name contains a file stream name. If the disk interface does not
5459
// implement the optional NTFS
5460
// streams interface then return an error status, not supported.
5461

5462        if ( FileName.containsStreamName(fileName))
5463        {
5464
5465            // Check if the driver implements the NTFS streams interface and it is enabled
5466

5467            boolean streams = false;
5468
5469            if (disk instanceof NTFSStreamsInterface)
5470            {
5471
5472                // Check if streams are enabled
5473

5474                NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) disk;
5475                streams = ntfsStreams.hasStreamsEnabled(m_sess, conn);
5476            }
5477
5478            // Check if streams are enabled/available
5479

5480            if (streams == false)
5481            {
5482                m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNameInvalid, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
5483                return;
5484            }
5485        }
5486
5487        // Create the file open parameters to be passed to the disk interface
5488

5489        FileOpenParams params = new FileOpenParams(fileName, createDisp, accessMask, attrib, shrAccess, allocSize,
5490                createOptn, rootFID, impersonLev, secFlags);
5491        // Debug
5492

5493        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
5494            logger.debug("NT Create AndX [" + treeId + "] params=" + params);
5495
5496        // Access the disk interface and open the requested file
5497

5498        int fid;
5499        NetworkFile netFile = null;
5500        int respAction = 0;
5501
5502        try
5503        {
5504
5505            // Check if the requested file already exists
5506

5507            int fileSts = disk.fileExists(m_sess, conn, fileName);
5508
5509            if (fileSts == FileStatus.NotExist)
5510            {
5511
5512                // Check if the file should be created if it does not exist
5513

5514                if (createDisp == FileAction.NTCreate || createDisp == FileAction.NTOpenIf
5515                        || createDisp == FileAction.NTOverwriteIf || createDisp == FileAction.NTSupersede)
5516                {
5517
5518                    // Check if the user has the required access permission
5519

5520                    if (conn.hasWriteAccess() == false)
5521                    {
5522
5523                        // User does not have the required access rights
5524

5525                        m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied,
5526                                SMBStatus.ErrDos);
5527                        return;
5528                    }
5529
5530                    // Check if a new file or directory should be created
5531

5532                    if ((createOptn & WinNT.CreateDirectory) == 0)
5533                    {
5534
5535                        // Create a new file
5536

5537                        netFile = disk.createFile(m_sess, conn, params);
5538                    }
5539                    else
5540                    {
5541
5542                        // Create a new directory and open it
5543

5544                        disk.createDirectory(m_sess, conn, params);
5545                        netFile = disk.openFile(m_sess, conn, params);
5546                    }
5547
5548                    // Check if the delete on close option is set
5549

5550                    if (netFile != null && (createOptn & WinNT.CreateDeleteOnClose) != 0)
5551                        netFile.setDeleteOnClose(true);
5552
5553                    // Indicate that the file did not exist and was created
5554

5555                    respAction = FileAction.FileCreated;
5556                }
5557                else
5558                {
5559
5560                    // Check if the path is a directory
5561

5562                    if (fileSts == FileStatus.DirectoryExists)
5563                    {
5564
5565                        // Return an access denied error
5566

5567                        m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNameCollision, SMBStatus.DOSFileAlreadyExists,
5568                                SMBStatus.ErrDos);
5569                        return;
5570                    }
5571                    else
5572                    {
5573
5574                        // Return a file not found error
5575

5576                        m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound,
5577                                SMBStatus.ErrDos);
5578                        return;
5579                    }
5580                }
5581            }
5582            else if (createDisp == FileAction.NTCreate)
5583            {
5584
5585                // Check for a file or directory
5586

5587                if (fileSts == FileStatus.FileExists || fileSts == FileStatus.DirectoryExists)
5588                {
5589
5590                    // Return a file exists error
5591

5592                    m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNameCollision, SMBStatus.DOSFileAlreadyExists,
5593                            SMBStatus.ErrDos);
5594                    return;
5595                }
5596                else
5597                {
5598
5599                    // Return an access denied exception
5600

5601                    m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
5602                    return;
5603                }
5604            }
5605            else
5606            {
5607
5608                // Open the requested file/directory
5609

5610                netFile = disk.openFile(m_sess, conn, params);
5611
5612                // Check if the file should be truncated
5613

5614                if (createDisp == FileAction.NTSupersede || createDisp == FileAction.NTOverwriteIf)
5615                {
5616
5617                    // Truncate the file
5618

5619                    disk.truncateFile(m_sess, conn, netFile, 0L);
5620
5621                    // Debug
5622

5623                    if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
5624                        logger.debug(" [" + treeId + "] name=" + fileName + " truncated");
5625                }
5626
5627                // Set the file action response
5628

5629                respAction = FileAction.FileExisted;
5630            }
5631
5632            // Add the file to the list of open files for this tree connection
5633

5634            fid = conn.addFile(netFile, getSession());
5635
5636        }
5637        catch (TooManyFilesException ex)
5638        {
5639
5640            // Too many files are open on this connection, cannot open any more files.
5641

5642            m_sess.sendErrorResponseSMB(SMBStatus.NTTooManyOpenFiles, SMBStatus.DOSTooManyOpenFiles, SMBStatus.ErrDos);
5643            return;
5644        }
5645        catch (AccessDeniedException ex)
5646        {
5647
5648            // Return an access denied error
5649

5650            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
5651            return;
5652        }
5653        catch (FileExistsException ex)
5654        {
5655
5656            // File/directory already exists
5657

5658            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNameCollision, SMBStatus.DOSFileAlreadyExists,
5659                    SMBStatus.ErrDos);
5660            return;
5661        }
5662        catch (FileSharingException ex)
5663        {
5664
5665            // Return a sharing violation error
5666

5667            m_sess.sendErrorResponseSMB(SMBStatus.NTSharingViolation, SMBStatus.DOSFileSharingConflict,
5668                    SMBStatus.ErrDos);
5669            return;
5670        }
5671        catch (FileOfflineException ex)
5672        {
5673
5674            // File data is unavailable
5675

5676            m_sess.sendErrorResponseSMB(SMBStatus.NTFileOffline, SMBStatus.HRDDriveNotReady, SMBStatus.ErrHrd);
5677            return;
5678        }
5679        catch (java.io.IOException JavaDoc ex)
5680        {
5681
5682            // Failed to open the file
5683

5684            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
5685            return;
5686        }
5687
5688        // Build the NT create andX response
5689

5690        outPkt.setParameterCount( 34);
5691
5692        outPkt.setAndXCommand(0xFF);
5693        outPkt.setParameter(1, 0); // AndX offset
5694

5695        prms.reset(outPkt.getBuffer(), SMBSrvPacket.PARAMWORDS + 4);
5696
5697        // Fake the oplock for certain file types
5698

5699        boolean fakeOpLocks = FakeOpLocks;
5700        String JavaDoc fname = params.getPath().toUpperCase();
5701        
5702        if ( fname.endsWith( ".URL")){
5703        
5704            // Fake the oplock
5705

5706            fakeOpLocks = true;
5707        }
5708        
5709        // Check if oplocks should be faked
5710

5711        if (fakeOpLocks == true)
5712        {
5713
5714            // If an oplock was requested indicate it was granted, for now
5715

5716            if ((flags & WinNT.RequestBatchOplock) != 0)
5717            {
5718
5719                // Batch oplock granted
5720

5721                prms.packByte(2);
5722            }
5723            else if ((flags & WinNT.RequestOplock) != 0)
5724            {
5725
5726                // Exclusive oplock granted
5727

5728                prms.packByte(1);
5729            }
5730            else
5731            {
5732
5733                // No oplock granted
5734

5735                prms.packByte(0);
5736            }
5737        }
5738        else
5739            prms.packByte(0);
5740
5741        // Pack the file id
5742

5743        prms.packWord(fid);
5744        prms.packInt(respAction);
5745
5746        // Pack the file/directory dates
5747

5748        if (netFile.hasCreationDate())
5749            prms.packLong(NTTime.toNTTime(netFile.getCreationDate()));
5750        else
5751            prms.packLong(0);
5752
5753        if ( netFile.hasAccessDate())
5754            prms.packLong(NTTime.toNTTime(netFile.getAccessDate()));
5755        else
5756            prms.packLong(0);
5757        
5758        if (netFile.hasModifyDate())
5759        {
5760            long modDate = NTTime.toNTTime(netFile.getModifyDate());
5761            prms.packLong(modDate);
5762            prms.packLong(modDate);
5763        }
5764        else
5765        {
5766            prms.packLong(0); // Last write time
5767
prms.packLong(0); // Change time
5768
}
5769
5770        prms.packInt(netFile.getFileAttributes());
5771
5772        // Pack the file size/allocation size
5773

5774        long fileSize = netFile.getFileSize();
5775        if (fileSize > 0L)
5776            fileSize = (fileSize + 512L) & 0xFFFFFFFFFFFFFE00L;
5777
5778        prms.packLong(fileSize); // Allocation size
5779
prms.packLong(netFile.getFileSize()); // End of file
5780
prms.packWord(0); // File type - disk file
5781
prms.packWord((flags & WinNT.ExtendedResponse) != 0 ? 7 : 0); // Device state
5782
prms.packByte(netFile.isDirectory() ? 1 : 0);
5783
5784        prms.packWord(0); // byte count = 0
5785

5786        // Set the AndX offset
5787

5788        int endPos = prms.getPosition();
5789        outPkt.setParameter(1, endPos - RFCNetBIOSProtocol.HEADER_LEN);
5790
5791        // Check if there is a chained request
5792

5793        if (m_smbPkt.hasAndXCommand())
5794        {
5795
5796            // Process the chained requests
5797

5798            endPos = procAndXCommands(outPkt, endPos, netFile);
5799        }
5800
5801        // Send the response packet
5802

5803        m_sess.sendResponseSMB(outPkt, endPos - RFCNetBIOSProtocol.HEADER_LEN);
5804
5805        // Check if there are any file/directory change notify requests active
5806

5807        DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
5808        if (diskCtx.hasChangeHandler() && respAction == FileAction.FileCreated)
5809        {
5810
5811            // Check if a file or directory has been created
5812

5813            if (netFile.isDirectory())
5814                diskCtx.getChangeHandler().notifyDirectoryChanged(NotifyChange.ActionAdded, fileName);
5815            else
5816                diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionAdded, fileName);
5817        }
5818    }
5819
5820    /**
5821     * Process the cancel request.
5822     *
5823     * @param outPkt SMBSrvPacket
5824     */

5825    protected final void procNTCancel(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
5826    {
5827
5828        // Check that the received packet looks like a valid NT cancel request
5829

5830        if (m_smbPkt.checkPacketIsValid(0, 0) == false)
5831        {
5832            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
5833            return;
5834        }
5835
5836        // Get the tree connection details
5837

5838        int treeId = m_smbPkt.getTreeId();
5839        TreeConnection conn = m_sess.findConnection(treeId);
5840
5841        if (conn == null)
5842        {
5843            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
5844            return;
5845        }
5846
5847        // Find the matching notify request and remove it
5848

5849        NotifyRequest req = m_sess.findNotifyRequest(m_smbPkt.getMultiplexId(), m_smbPkt.getTreeId(), m_smbPkt
5850                .getUserId(), m_smbPkt.getProcessId());
5851        if (req != null)
5852        {
5853
5854            // Remove the request
5855

5856            m_sess.removeNotifyRequest(req);
5857
5858            // Return a cancelled status
5859

5860            m_smbPkt.setParameterCount(0);
5861            m_smbPkt.setByteCount(0);
5862
5863            // Enable the long error status flag
5864

5865            if (m_smbPkt.isLongErrorCode() == false)
5866                m_smbPkt.setFlags2(m_smbPkt.getFlags2() + SMBSrvPacket.FLG2_LONGERRORCODE);
5867
5868            // Set the NT status code
5869

5870            m_smbPkt.setLongErrorCode(SMBStatus.NTCancelled);
5871
5872            // Set the Unicode strings flag
5873

5874            if (m_smbPkt.isUnicode() == false)
5875                m_smbPkt.setFlags2(m_smbPkt.getFlags2() + SMBSrvPacket.FLG2_UNICODE);
5876
5877            // Return the error response to the client
5878

5879            m_sess.sendResponseSMB(m_smbPkt);
5880
5881            // Debug
5882

5883            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NOTIFY))
5884            {
5885                DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
5886                logger.debug("NT Cancel notify mid=" + req.getMultiplexId() + ", dir=" + req.getWatchPath()
5887                        + ", queue=" + diskCtx.getChangeHandler().getRequestQueueSize());
5888            }
5889        }
5890        else
5891        {
5892
5893            // Nothing to cancel
5894

5895            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
5896        }
5897    }
5898
5899    /**
5900     * Process an NT transaction
5901     *
5902     * @param outPkt SMBSrvPacket
5903     */

5904    protected final void procNTTransaction(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
5905    {
5906
5907        // Check that we received enough parameters for a transact2 request
5908

5909        if (m_smbPkt.checkPacketIsValid(19, 0) == false)
5910        {
5911
5912            // Not enough parameters for a valid transact2 request
5913

5914            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
5915            return;
5916        }
5917
5918        // Get the tree id from the received packet and validate that it is a valid
5919
// connection id.
5920

5921        int treeId = m_smbPkt.getTreeId();
5922        TreeConnection conn = m_sess.findConnection(treeId);
5923
5924        if (conn == null)
5925        {
5926            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
5927            return;
5928        }
5929
5930        // Check if the user has the required access permission
5931

5932        if (conn.hasReadAccess() == false)
5933        {
5934
5935            // User does not have the required access rights
5936

5937            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
5938            return;
5939        }
5940
5941        // Check if the transaction request is for the IPC$ pipe
5942

5943        if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
5944        {
5945            IPCHandler.processIPCRequest(m_sess, outPkt);
5946            return;
5947        }
5948
5949        // Create an NT transaction using the received packet
5950

5951        NTTransPacket ntTrans = new NTTransPacket(m_smbPkt.getBuffer());
5952        int subCmd = ntTrans.getNTFunction();
5953
5954        // Check for a notfy change request, this needs special processing
5955

5956        if (subCmd == PacketType.NTTransNotifyChange)
5957        {
5958
5959            // Handle the notify change setup request
5960

5961            procNTTransactNotifyChange(ntTrans, outPkt);
5962            return;
5963        }
5964
5965        // Create a transact buffer to hold the transaction parameter block and data block
5966

5967        SrvTransactBuffer transBuf = null;
5968
5969        if (ntTrans.getTotalParameterCount() == ntTrans.getParameterBlockCount()
5970                && ntTrans.getTotalDataCount() == ntTrans.getDataBlockCount())
5971        {
5972
5973            // Create a transact buffer using the packet buffer, the entire request is contained in
5974
// a single
5975
// packet
5976

5977            transBuf = new SrvTransactBuffer(ntTrans);
5978        }
5979        else
5980        {
5981
5982            // Create a transact buffer to hold the multiple transact request parameter/data blocks
5983

5984            transBuf = new SrvTransactBuffer(ntTrans.getSetupCount(), ntTrans.getTotalParameterCount(), ntTrans
5985                    .getTotalDataCount());
5986            transBuf.setType(ntTrans.getCommand());
5987            transBuf.setFunction(subCmd);
5988
5989            // Debug
5990

5991            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
5992                logger.debug("NT Transaction [" + treeId + "] transbuf=" + transBuf);
5993
5994            // Append the setup, parameter and data blocks to the transaction data
5995

5996            byte[] buf = ntTrans.getBuffer();
5997            int cnt = ntTrans.getSetupCount();
5998
5999            if (cnt > 0)
6000                transBuf.appendSetup(buf, ntTrans.getSetupOffset(), cnt * 2);
6001
6002            // Debug
6003

6004            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
6005                logger.debug("NT Transaction [" + treeId + "] pcnt=" + ntTrans.getNTParameter(4) + ", offset="
6006                        + ntTrans.getNTParameter(5));
6007
6008            cnt = ntTrans.getParameterBlockCount();
6009
6010            if (cnt > 0)
6011                transBuf.appendParameter(buf, ntTrans.getParameterBlockOffset(), cnt);
6012
6013            cnt = ntTrans.getDataBlockCount();
6014            if (cnt > 0)
6015                transBuf.appendData(buf, ntTrans.getDataBlockOffset(), cnt);
6016        }
6017
6018        // Debug
6019

6020        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
6021            logger.debug("NT Transaction [" + treeId + "] cmd=0x" + Integer.toHexString(subCmd) + ", multiPkt="
6022                    + transBuf.isMultiPacket());
6023
6024        // Check for a multi-packet transaction, for a multi-packet transaction we just acknowledge
6025
// the receive with
6026
// an empty response SMB
6027

6028        if (transBuf.isMultiPacket())
6029        {
6030
6031            // Save the partial transaction data
6032

6033            m_sess.setTransaction(transBuf);
6034
6035            // Send an intermediate acknowedgement response
6036

6037            m_sess.sendSuccessResponseSMB();
6038            return;
6039        }
6040
6041        // Process the transaction buffer
6042

6043        processNTTransactionBuffer(transBuf, ntTrans);
6044    }
6045
6046    /**
6047     * Process an NT transaction secondary packet
6048     *
6049     * @param outPkt SMBSrvPacket
6050     */

6051    protected final void procNTTransactionSecondary(SMBSrvPacket outPkt) throws java.io.IOException JavaDoc, SMBSrvException
6052    {
6053
6054        // Check that we received enough parameters for a transact2 request
6055

6056        if (m_smbPkt.checkPacketIsValid(18, 0) == false)
6057        {
6058
6059            // Not enough parameters for a valid transact2 request
6060

6061            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
6062            return;
6063        }
6064
6065        // Get the tree id from the received packet and validate that it is a valid
6066
// connection id.
6067

6068        int treeId = m_smbPkt.getTreeId();
6069        TreeConnection conn = m_sess.findConnection(treeId);
6070
6071        if (conn == null)
6072        {
6073            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
6074            return;
6075        }
6076
6077        // Check if the user has the required access permission
6078

6079        if (conn.hasReadAccess() == false)
6080        {
6081
6082            // User does not have the required access rights
6083

6084            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
6085            return;
6086        }
6087
6088        // Check if the transaction request is for the IPC$ pipe
6089

6090        if (conn.getSharedDevice().getType() == ShareType.ADMINPIPE)
6091        {
6092            IPCHandler.processIPCRequest(m_sess, outPkt);
6093            return;
6094        }
6095
6096        // Check if there is an active transaction, and it is an NT transaction
6097

6098        if (m_sess.hasTransaction() == false || m_sess.getTransaction().isType() != PacketType.NTTransact)
6099        {
6100
6101            // No NT transaction to continue, return an error
6102

6103            m_sess.sendErrorResponseSMB(SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
6104            return;
6105        }
6106
6107        // Create an NT transaction using the received packet
6108

6109        NTTransPacket ntTrans = new NTTransPacket(m_smbPkt.getBuffer());
6110        byte[] buf = ntTrans.getBuffer();
6111        SrvTransactBuffer transBuf = m_sess.getTransaction();
6112
6113        // Append the parameter data to the transaction buffer, if any
6114

6115        int plen = ntTrans.getParameterBlockCount();
6116        if (plen > 0)
6117        {
6118
6119            // Append the data to the parameter buffer
6120

6121            DataBuffer paramBuf = transBuf.getParameterBuffer();
6122            paramBuf.appendData(buf, ntTrans.getParameterBlockOffset(), plen);
6123        }
6124
6125        // Append the data block to the transaction buffer, if any
6126

6127        int dlen = ntTrans.getDataBlockCount();
6128        if (dlen > 0)
6129        {
6130
6131            // Append the data to the data buffer
6132

6133            DataBuffer dataBuf = transBuf.getDataBuffer();
6134            dataBuf.appendData(buf, ntTrans.getDataBlockOffset(), dlen);
6135        }
6136
6137        // Debug
6138

6139        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
6140            logger.debug("NT Transaction Secondary [" + treeId + "] paramLen=" + plen + ", dataLen=" + dlen);
6141
6142        // Check if the transaction has been received or there are more sections to be received
6143

6144        int totParam = ntTrans.getTotalParameterCount();
6145        int totData = ntTrans.getTotalDataCount();
6146
6147        int paramDisp = ntTrans.getParameterBlockDisplacement();
6148        int dataDisp = ntTrans.getDataBlockDisplacement();
6149
6150        if ((paramDisp + plen) == totParam && (dataDisp + dlen) == totData)
6151        {
6152
6153            // Debug
6154

6155            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
6156                logger.debug("NT Transaction complete, processing ...");
6157
6158            // Clear the in progress transaction
6159

6160            m_sess.setTransaction(null);
6161
6162            // Process the transaction
6163

6164            processNTTransactionBuffer(transBuf, ntTrans);
6165        }
6166
6167        // No response is sent for a transaction secondary
6168
}
6169
6170    /**
6171     * Process an NT transaction buffer
6172     *
6173     * @param tbuf TransactBuffer
6174     * @param outPkt NTTransPacket
6175     * @exception IOException If a network error occurs
6176     * @exception SMBSrvException If an SMB error occurs
6177     */

6178    private final void processNTTransactionBuffer(SrvTransactBuffer tbuf, NTTransPacket outPkt) throws IOException JavaDoc,
6179            SMBSrvException
6180    {
6181
6182        // Process the NT transaction buffer
6183

6184        switch (tbuf.getFunction())
6185        {
6186
6187        // Create file/directory
6188

6189        case PacketType.NTTransCreate:
6190            procNTTransactCreate(tbuf, outPkt);
6191            break;
6192
6193        // I/O control
6194

6195        case PacketType.NTTransIOCtl:
6196            procNTTransactIOCtl(tbuf, outPkt);
6197            break;
6198
6199        // Query security descriptor
6200

6201        case PacketType.NTTransQuerySecurityDesc:
6202            procNTTransactQuerySecurityDesc(tbuf, outPkt);
6203            break;
6204
6205        // Set security descriptor
6206

6207        case PacketType.NTTransSetSecurityDesc:
6208            procNTTransactSetSecurityDesc(tbuf, outPkt);
6209            break;
6210
6211        // Rename file/directory via handle
6212

6213        case PacketType.NTTransRename:
6214            procNTTransactRename(tbuf, outPkt);
6215            break;
6216
6217        // Get user quota
6218

6219        case PacketType.NTTransGetUserQuota:
6220
6221            // Return a not implemented error status
6222

6223            m_sess.sendErrorResponseSMB(SMBStatus.NTNotImplemented, SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
6224            break;
6225
6226        // Set user quota
6227

6228        case PacketType.NTTransSetUserQuota:
6229
6230            // Return a not implemented error status
6231

6232            m_sess.sendErrorResponseSMB(SMBStatus.NTNotImplemented, SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
6233            break;
6234
6235        // Unknown NT transaction command
6236

6237        default:
6238            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
6239            break;
6240        }
6241    }
6242
6243    /**
6244     * Process an NT create file/directory transaction
6245     *
6246     * @param tbuf TransactBuffer
6247     * @param outPkt NTTransPacket
6248     * @exception IOException
6249     * @exception SMBSrvException
6250     */

6251    protected final void procNTTransactCreate(SrvTransactBuffer tbuf, NTTransPacket outPkt) throws IOException JavaDoc,
6252            SMBSrvException
6253    {
6254
6255        // Debug
6256

6257        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
6258            logger.debug("NT TransactCreate");
6259
6260        // Check that the received packet looks like a valid NT create transaction
6261

6262        if (tbuf.hasParameterBuffer() && tbuf.getParameterBuffer().getLength() < 52)
6263        {
6264            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
6265            return;
6266        }
6267
6268        // Get the tree connection details
6269

6270        int treeId = tbuf.getTreeId();
6271        TreeConnection conn = m_sess.findConnection(treeId);
6272
6273        if (conn == null)
6274        {
6275            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
6276            return;
6277        }
6278
6279        // Check if the user has the required access permission
6280

6281        if (conn.hasWriteAccess() == false)
6282        {
6283
6284            // User does not have the required access rights
6285

6286            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
6287            return;
6288        }
6289
6290        // If the connection is not a disk share then return an error.
6291

6292        if (conn.getSharedDevice().getType() != ShareType.DISK)
6293        {
6294
6295            // Return an access denied error
6296

6297            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
6298            return;
6299        }
6300
6301        // Extract the file create parameters
6302

6303        DataBuffer tparams = tbuf.getParameterBuffer();
6304
6305        int flags = tparams.getInt();
6306        int rootFID = tparams.getInt();
6307        int accessMask = tparams.getInt();
6308        long allocSize = tparams.getLong();
6309        int attrib = tparams.getInt();
6310        int shrAccess = tparams.getInt();
6311        int createDisp = tparams.getInt();
6312        int createOptn = tparams.getInt();
6313        int sdLen = tparams.getInt();
6314        int eaLen = tparams.getInt();
6315        int nameLen = tparams.getInt();
6316        int impersonLev = tparams.getInt();
6317        int secFlags = tparams.getByte();
6318
6319        // Extract the filename string
6320

6321        tparams.wordAlign();
6322        String JavaDoc fileName = tparams.getString(nameLen, true);
6323
6324        if (fileName == null)
6325        {
6326            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
6327            return;
6328        }
6329
6330        // Access the disk interface that is associated with the shared device
6331

6332        DiskInterface disk = null;
6333        try
6334        {
6335
6336            // Get the disk interface for the share
6337

6338            disk = (DiskInterface) conn.getSharedDevice().getInterface();
6339        }
6340        catch (InvalidDeviceInterfaceException ex)
6341        {
6342
6343            // Failed to get/initialize the disk interface
6344

6345            m_sess.sendErrorResponseSMB(SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
6346            return;
6347        }
6348
6349        // Check if the file name contains a file stream name. If the disk interface does not
6350
// implement the optional NTFS
6351
// streams interface then return an error status, not supported.
6352

6353        if (fileName.indexOf(FileOpenParams.StreamSeparator) != -1)
6354        {
6355
6356            // Check if the driver implements the NTFS streams interface and it is enabled
6357

6358            boolean streams = false;
6359
6360            if (disk instanceof NTFSStreamsInterface)
6361            {
6362
6363                // Check if streams are enabled
6364

6365                NTFSStreamsInterface ntfsStreams = (NTFSStreamsInterface) disk;
6366                streams = ntfsStreams.hasStreamsEnabled(m_sess, conn);
6367            }
6368
6369            // Check if streams are enabled/available
6370

6371            if (streams == false)
6372            {
6373
6374                // Return a file not found error
6375

6376                m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
6377                return;
6378            }
6379        }
6380
6381        // Create the file open parameters to be passed to the disk interface
6382

6383        FileOpenParams params = new FileOpenParams(fileName, createDisp, accessMask, attrib, shrAccess, allocSize,
6384                createOptn, rootFID, impersonLev, secFlags);
6385        // Debug
6386

6387        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
6388            logger.debug("NT TransactCreate [" + treeId + "] params=" + params + " secDescLen=" + sdLen
6389                    + ", extAttribLen=" + eaLen);
6390
6391        // Access the disk interface and open/create the requested file
6392

6393        int fid;
6394        NetworkFile netFile = null;
6395        int respAction = 0;
6396
6397        try
6398        {
6399
6400            // Check if the requested file already exists
6401

6402            int fileSts = disk.fileExists(m_sess, conn, fileName);
6403
6404            if (fileSts == FileStatus.NotExist)
6405            {
6406
6407                // Check if the file should be created if it does not exist
6408

6409                if (createDisp == FileAction.NTCreate || createDisp == FileAction.NTOpenIf
6410                        || createDisp == FileAction.NTOverwriteIf || createDisp == FileAction.NTSupersede)
6411                {
6412
6413                    // Check if a new file or directory should be created
6414

6415                    if ((createOptn & WinNT.CreateDirectory) == 0)
6416                    {
6417
6418                        // Create a new file
6419

6420                        netFile = disk.createFile(m_sess, conn, params);
6421                    }
6422                    else
6423                    {
6424
6425                        // Create a new directory and open it
6426

6427                        disk.createDirectory(m_sess, conn, params);
6428                        netFile = disk.openFile(m_sess, conn, params);
6429                    }
6430
6431                    // Indicate that the file did not exist and was created
6432

6433                    respAction = FileAction.FileCreated;
6434                }
6435                else
6436                {
6437
6438                    // Check if the path is a directory
6439

6440                    if (fileSts == FileStatus.DirectoryExists)
6441                    {
6442
6443                        // Return an access denied error
6444

6445                        m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNameCollision, SMBStatus.DOSFileAlreadyExists,
6446                                SMBStatus.ErrDos);
6447                        return;
6448                    }
6449                    else
6450                    {
6451
6452                        // Return a file not found error
6453

6454                        m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound,
6455                                SMBStatus.ErrDos);
6456                        return;
6457                    }
6458                }
6459            }
6460            else if (createDisp == FileAction.NTCreate)
6461            {
6462
6463                // Check for a file or directory
6464

6465                if (fileSts == FileStatus.FileExists || fileSts == FileStatus.DirectoryExists)
6466                {
6467
6468                    // Return a file exists error
6469

6470                    m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNameCollision, SMBStatus.DOSFileAlreadyExists,
6471                            SMBStatus.ErrDos);
6472                    return;
6473                }
6474                else
6475                {
6476
6477                    // Return an access denied exception
6478

6479                    m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
6480                    return;
6481                }
6482            }
6483            else
6484            {
6485
6486                // Open the requested file/directory
6487

6488                netFile = disk.openFile(m_sess, conn, params);
6489
6490                // Check if the file should be truncated
6491

6492                if (createDisp == FileAction.NTSupersede || createDisp == FileAction.NTOverwriteIf)
6493                {
6494
6495                    // Truncate the file
6496

6497                    disk.truncateFile(m_sess, conn, netFile, 0L);
6498
6499                    // Debug
6500

6501                    if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_FILE))
6502                        logger.debug(" [" + treeId + "] name=" + fileName + " truncated");
6503                }
6504
6505                // Set the file action response
6506

6507                respAction = FileAction.FileExisted;
6508            }
6509
6510            // Add the file to the list of open files for this tree connection
6511

6512            fid = conn.addFile(netFile, getSession());
6513        }
6514        catch (TooManyFilesException ex)
6515        {
6516
6517            // Too many files are open on this connection, cannot open any more files.
6518

6519            m_sess.sendErrorResponseSMB(SMBStatus.NTTooManyOpenFiles, SMBStatus.DOSTooManyOpenFiles, SMBStatus.ErrDos);
6520            return;
6521        }
6522        catch (AccessDeniedException ex)
6523        {
6524
6525            // Return an access denied error
6526

6527            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
6528            return;
6529        }
6530        catch (FileExistsException ex)
6531        {
6532
6533            // File/directory already exists
6534

6535            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNameCollision, SMBStatus.DOSFileAlreadyExists,
6536                    SMBStatus.ErrDos);
6537            return;
6538        }
6539        catch (FileSharingException ex)
6540        {
6541
6542            // Return a sharing violation error
6543

6544            m_sess.sendErrorResponseSMB(SMBStatus.NTSharingViolation, SMBStatus.DOSFileSharingConflict,
6545                    SMBStatus.ErrDos);
6546            return;
6547        }
6548        catch (FileOfflineException ex)
6549        {
6550
6551            // File data is unavailable
6552

6553            m_sess.sendErrorResponseSMB(SMBStatus.NTFileOffline, SMBStatus.HRDDriveNotReady, SMBStatus.ErrHrd);
6554            return;
6555        }
6556        catch (java.io.IOException JavaDoc ex)
6557        {
6558
6559            // Failed to open the file
6560

6561            m_sess.sendErrorResponseSMB(SMBStatus.NTObjectNotFound, SMBStatus.DOSFileNotFound, SMBStatus.ErrDos);
6562            return;
6563        }
6564
6565        // Build the NT transaction create response
6566

6567        DataBuffer prms = new DataBuffer(128);
6568
6569        // If an oplock was requested indicate it was granted, for now
6570

6571        if ((flags & WinNT.RequestBatchOplock) != 0)
6572        {
6573
6574            // Batch oplock granted
6575

6576            prms.putByte(2);
6577        }
6578        else if ((flags & WinNT.RequestOplock) != 0)
6579        {
6580
6581            // Exclusive oplock granted
6582

6583            prms.putByte(1);
6584        }
6585        else
6586        {
6587
6588            // No oplock granted
6589

6590            prms.putByte(0);
6591        }
6592        prms.putByte(0); // alignment
6593

6594        // Pack the file id
6595

6596        prms.putShort(fid);
6597        prms.putInt(respAction);
6598
6599        // EA error offset
6600

6601        prms.putInt(0);
6602
6603        // Pack the file/directory dates
6604

6605        if (netFile.hasCreationDate())
6606            prms.putLong(NTTime.toNTTime(netFile.getCreationDate()));
6607        else
6608            prms.putLong(0);
6609
6610        if (netFile.hasModifyDate())
6611        {
6612            long modDate = NTTime.toNTTime(netFile.getModifyDate());
6613            prms.putLong(modDate);
6614            prms.putLong(modDate);
6615            prms.putLong(modDate);
6616        }
6617        else
6618        {
6619            prms.putLong(0); // Last access time
6620
prms.putLong(0); // Last write time
6621
prms.putLong(0); // Change time
6622
}
6623
6624        prms.putInt(netFile.getFileAttributes());
6625
6626        // Pack the file size/allocation size
6627

6628        prms.putLong(netFile.getFileSize()); // Allocation size
6629
prms.putLong(netFile.getFileSize()); // End of file
6630
prms.putShort(0); // File type - disk file
6631
prms.putShort(0); // Device state
6632
prms.putByte(netFile.isDirectory() ? 1 : 0);
6633
6634        // Initialize the transaction response
6635

6636        outPkt.initTransactReply(prms.getBuffer(), prms.getLength(), null, 0);
6637
6638        // Send back the response
6639

6640        m_sess.sendResponseSMB(outPkt);
6641
6642        // Check if there are any file/directory change notify requests active
6643

6644        DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
6645        if (diskCtx.hasChangeHandler() && respAction == FileAction.FileCreated)
6646        {
6647
6648            // Check if a file or directory has been created
6649

6650            if (netFile.isDirectory())
6651                diskCtx.getChangeHandler().notifyDirectoryChanged(NotifyChange.ActionAdded, fileName);
6652            else
6653                diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionAdded, fileName);
6654        }
6655    }
6656
6657    /**
6658     * Process an NT I/O control transaction
6659     *
6660     * @param tbuf TransactBuffer
6661     * @param outPkt NTTransPacket
6662     * @exception IOException
6663     * @exception SMBSrvException
6664     */

6665    protected final void procNTTransactIOCtl(SrvTransactBuffer tbuf, NTTransPacket outPkt) throws IOException JavaDoc,
6666            SMBSrvException
6667    {
6668        
6669        // Get the tree connection details
6670

6671        int treeId = tbuf.getTreeId();
6672        TreeConnection conn = m_sess.findConnection(treeId);
6673
6674        if (conn == null) {
6675            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
6676            return;
6677        }
6678
6679        // Unpack the request details
6680

6681        DataBuffer setupBuf = tbuf.getSetupBuffer();
6682    
6683        int ctrlCode = setupBuf.getInt();
6684        int fid = setupBuf.getShort();
6685        boolean fsctrl = setupBuf.getByte() == 1 ? true : false;
6686        int filter = setupBuf.getByte();
6687
6688        // Debug
6689

6690        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
6691            logger.debug("NT IOCtl code=" + NTIOCtl.asString(ctrlCode) + ", fid=" + fid + ", fsctrl=" + fsctrl + ", filter=" + filter);
6692
6693        // Access the disk interface that is associated with the shared device
6694

6695        DiskInterface disk = null;
6696        try {
6697            
6698            // Get the disk interface for the share
6699

6700            disk = (DiskInterface) conn.getSharedDevice().getInterface();
6701        }
6702        catch (InvalidDeviceInterfaceException ex) {
6703
6704            // Failed to get/initialize the disk interface
6705

6706            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidData, SMBStatus.ErrDos);
6707            return;
6708        }
6709
6710        // Check if the disk interface implements the optional IO control interface
6711

6712        if ( disk instanceof IOCtlInterface) {
6713
6714            // Access the IO control interface
6715

6716            IOCtlInterface ioControl = (IOCtlInterface) disk;
6717      
6718            try {
6719        
6720                // Pass the request to the IO control interface for processing
6721

6722                DataBuffer response = ioControl.processIOControl(m_sess, conn, ctrlCode, fid, tbuf.getDataBuffer(), fsctrl, filter);
6723                
6724                // Pack the response
6725

6726                if ( response != null) {
6727                  
6728                    // Pack the response data block
6729

6730                    outPkt.initTransactReply(null, 0, response.getBuffer(), response.getLength(), 1);
6731                    outPkt.setSetupParameter(0, response.getLength());
6732                }
6733                else {
6734                  
6735                    // Pack an empty response data block
6736

6737                    outPkt.initTransactReply(null, 0, null, 0, 1);
6738                    outPkt.setSetupParameter(0, 0);
6739                }
6740            }
6741            catch (IOControlNotImplementedException ex) {
6742            
6743                // Return a not implemented error status
6744

6745                m_sess.sendErrorResponseSMB(SMBStatus.NTNotImplemented, SMBStatus.SRVInternalServerError, SMBStatus.ErrSrv);
6746                return;
6747            }
6748            catch (SMBException ex) {
6749            
6750                // Return the specified SMB status, this should be an NT status code
6751

6752                m_sess.sendErrorResponseSMB(ex.getErrorCode(), SMBStatus.SRVInternalServerError, SMBStatus.ErrSrv);
6753                return;
6754            }
6755          
6756            // Send the IOCtl response
6757

6758            m_sess.sendResponseSMB(outPkt);
6759        }
6760        else {
6761          
6762            // Send back an error, IOctl not supported
6763

6764            m_sess.sendErrorResponseSMB(SMBStatus.NTNotImplemented, SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
6765        }
6766    }
6767    
6768    /**
6769     * Process an NT query security descriptor transaction
6770     *
6771     * @param tbuf TransactBuffer
6772     * @param outPkt NTTransPacket
6773     * @exception IOException
6774     * @exception SMBSrvException
6775     */

6776    protected final void procNTTransactQuerySecurityDesc(SrvTransactBuffer tbuf, NTTransPacket outPkt)
6777            throws IOException JavaDoc, SMBSrvException
6778    {
6779
6780        // Get the tree connection details
6781

6782        int treeId = tbuf.getTreeId();
6783        TreeConnection conn = m_sess.findConnection(treeId);
6784
6785        if (conn == null)
6786        {
6787            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
6788            return;
6789        }
6790
6791        // Check if the user has the required access permission
6792

6793        if (conn.hasReadAccess() == false)
6794        {
6795
6796            // User does not have the required access rights
6797

6798            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
6799            return;
6800        }
6801
6802        // Unpack the request details
6803

6804        DataBuffer paramBuf = tbuf.getParameterBuffer();
6805
6806        int fid = paramBuf.getShort();
6807        int flags = paramBuf.getShort();
6808
6809        // Debug
6810

6811        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
6812            logger.debug("NT QuerySecurityDesc fid=" + fid + ", flags=" + flags);
6813
6814        // Get the file details
6815

6816        NetworkFile netFile = conn.findFile(fid);
6817
6818        if (netFile == null)
6819        {
6820            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
6821            return;
6822        }
6823
6824        // Check if this is a buffer length check, if so the maximum returned data count will be
6825
// zero
6826

6827        if (tbuf.getReturnDataLimit() == 0)
6828        {
6829
6830            // Return the security descriptor length in the parameter block
6831

6832            byte[] paramblk = new byte[4];
6833            DataPacker.putIntelInt(_sdEveryOne.length, paramblk, 0);
6834
6835            // Initialize the transaction reply
6836

6837            outPkt.initTransactReply(paramblk, paramblk.length, null, 0);
6838
6839            // Set a warning status to indicate the supplied data buffer was too small to return the
6840
// security
6841
// descriptor
6842

6843            outPkt.setLongErrorCode(SMBStatus.NTBufferTooSmall);
6844        }
6845        else
6846        {
6847
6848            // Return the security descriptor length in the parameter block
6849

6850            byte[] paramblk = new byte[4];
6851            DataPacker.putIntelInt(_sdEveryOne.length, paramblk, 0);
6852
6853            // Initialize the transaction reply. Return the fixed security descriptor that allows
6854
// anyone to access the
6855
// file/directory
6856

6857            outPkt.initTransactReply(paramblk, paramblk.length, _sdEveryOne, _sdEveryOne.length);
6858        }
6859
6860        // Send back the response
6861

6862        m_sess.sendResponseSMB(outPkt);
6863    }
6864
6865    /**
6866     * Process an NT set security descriptor transaction
6867     *
6868     * @param tbuf TransactBuffer
6869     * @param outPkt NTTransPacket
6870     * @exception IOException
6871     * @exception SMBSrvException
6872     */

6873    protected final void procNTTransactSetSecurityDesc(SrvTransactBuffer tbuf, NTTransPacket outPkt)
6874            throws IOException JavaDoc, SMBSrvException
6875    {
6876
6877        // Unpack the request details
6878

6879        DataBuffer paramBuf = tbuf.getParameterBuffer();
6880
6881        // Get the tree connection details
6882

6883        int treeId = tbuf.getTreeId();
6884        TreeConnection conn = m_sess.findConnection(treeId);
6885
6886        if (conn == null)
6887        {
6888            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
6889            return;
6890        }
6891
6892        // Check if the user has the required access permission
6893

6894        if (conn.hasWriteAccess() == false)
6895        {
6896
6897            // User does not have the required access rights
6898

6899            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
6900            return;
6901        }
6902
6903        // Get the file details
6904

6905        int fid = paramBuf.getShort();
6906        paramBuf.skipBytes(2);
6907        int flags = paramBuf.getInt();
6908
6909        // Debug
6910

6911        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
6912            logger.debug("NT SetSecurityDesc fid=" + fid + ", flags=" + flags);
6913
6914        // Send back an error, security descriptors not supported
6915

6916        m_sess.sendErrorResponseSMB(SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
6917    }
6918
6919    /**
6920     * Process an NT change notification transaction
6921     *
6922     * @param ntpkt NTTransPacket
6923     * @param outPkt SMBSrvPacket
6924     * @exception IOException
6925     * @exception SMBSrvException
6926     */

6927    protected final void procNTTransactNotifyChange(NTTransPacket ntpkt, SMBSrvPacket outPkt) throws IOException JavaDoc,
6928            SMBSrvException
6929    {
6930
6931        // Get the tree connection details
6932

6933        int treeId = ntpkt.getTreeId();
6934        TreeConnection conn = m_sess.findConnection(treeId);
6935
6936        if (conn == null)
6937        {
6938            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
6939            return;
6940        }
6941
6942        // Check if the user has the required access permission
6943

6944        if (conn.hasReadAccess() == false)
6945        {
6946
6947            // User does not have the required access rights
6948

6949            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
6950            return;
6951        }
6952
6953        // Make sure the tree connection is for a disk device
6954

6955        if (conn.getContext() == null || conn.getContext() instanceof DiskDeviceContext == false)
6956        {
6957            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
6958            return;
6959        }
6960
6961        // Check if the device has change notification enabled
6962

6963        DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
6964        if (diskCtx.hasChangeHandler() == false)
6965        {
6966
6967            // Return an error status, share does not have change notification enabled
6968

6969            m_sess.sendErrorResponseSMB(SMBStatus.NTNotImplemented, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
6970            return;
6971        }
6972
6973        // Unpack the request details
6974

6975        ntpkt.resetSetupPointer();
6976
6977        int filter = ntpkt.unpackInt();
6978        int fid = ntpkt.unpackWord();
6979        boolean watchTree = ntpkt.unpackByte() == 1 ? true : false;
6980        int mid = ntpkt.getMultiplexId();
6981
6982        // Get the file details
6983

6984        NetworkFile dir = conn.findFile(fid);
6985        if (dir == null)
6986        {
6987            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
6988            return;
6989        }
6990
6991        // Get the maximum notifications to buffer whilst waiting for the request to be reset after
6992
// a notification
6993
// has been triggered
6994

6995        int maxQueue = 0;
6996
6997        // Debug
6998

6999        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NOTIFY))
7000            logger.debug("NT NotifyChange fid=" + fid + ", mid=" + mid + ", filter=0x" + Integer.toHexString(filter)
7001                    + ", dir=" + dir.getFullName() + ", maxQueue=" + maxQueue);
7002
7003        // Check if there is an existing request in the notify list that matches the new request and
7004
// is in a completed
7005
// state. If so then the client is resetting the notify request so reuse the existing
7006
// request.
7007

7008        NotifyRequest req = m_sess.findNotifyRequest(dir, filter, watchTree);
7009
7010        if (req != null && req.isCompleted())
7011        {
7012
7013            // Reset the existing request with the new multiplex id
7014

7015            req.setMultiplexId(mid);
7016            req.setCompleted(false);
7017
7018            // Check if there are any buffered notifications for this session
7019

7020            if (req.hasBufferedEvents() || req.hasNotifyEnum())
7021            {
7022
7023                // Get the buffered events from the request, clear the list from the request
7024

7025                NotifyChangeEventList bufList = req.getBufferedEventList();
7026                req.clearBufferedEvents();
7027
7028                // Send the buffered events
7029

7030                diskCtx.getChangeHandler().sendBufferedNotifications(req, bufList);
7031
7032                // DEBUG
7033

7034                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NOTIFY))
7035                {
7036                    if (bufList == null)
7037                        logger.debug(" Sent buffered notifications, req=" + req.toString() + ", Enum");
7038                    else
7039                        logger.debug(" Sent buffered notifications, req=" + req.toString() + ", count="
7040                                + bufList.numberOfEvents());
7041                }
7042            }
7043            else
7044            {
7045
7046                // DEBUG
7047

7048                if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NOTIFY))
7049                    logger.debug(" Reset notify request, " + req.toString());
7050            }
7051        }
7052        else
7053        {
7054
7055            // Create a change notification request
7056

7057            req = new NotifyRequest(filter, watchTree, m_sess, dir, mid, ntpkt.getTreeId(), ntpkt.getProcessId(), ntpkt
7058                    .getUserId(), maxQueue);
7059
7060            // Add the request to the pending notify change lists
7061

7062            m_sess.addNotifyRequest(req, diskCtx);
7063
7064            // Debug
7065

7066            if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_NOTIFY))
7067                logger.debug(" Added new request, " + req.toString());
7068        }
7069
7070        // NOTE: If the change notification request is accepted then no reply is sent to the client.
7071
// A reply will be sent
7072
// asynchronously if the change notification is triggered.
7073
}
7074
7075    /**
7076     * Process an NT rename via handle transaction
7077     *
7078     * @param tbuf TransactBuffer
7079     * @param outPkt NTTransPacket
7080     * @exception IOException
7081     * @exception SMBSrvException
7082     */

7083    protected final void procNTTransactRename(SrvTransactBuffer tbuf, NTTransPacket outPkt) throws IOException JavaDoc,
7084            SMBSrvException
7085    {
7086
7087        // Unpack the request details
7088

7089        DataBuffer paramBuf = tbuf.getParameterBuffer();
7090
7091        // Get the tree connection details
7092

7093        int treeId = tbuf.getTreeId();
7094        TreeConnection conn = m_sess.findConnection(treeId);
7095
7096        if (conn == null)
7097        {
7098            m_sess.sendErrorResponseSMB(SMBStatus.NTInvalidParameter, SMBStatus.DOSInvalidDrive, SMBStatus.ErrDos);
7099            return;
7100        }
7101
7102        // Check if the user has the required access permission
7103

7104        if (conn.hasWriteAccess() == false)
7105        {
7106
7107            // User does not have the required access rights
7108

7109            m_sess.sendErrorResponseSMB(SMBStatus.NTAccessDenied, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
7110            return;
7111        }
7112
7113        // Debug
7114

7115        if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_TRAN))
7116            logger.debug("NT TransactRename");
7117
7118        // Send back an error, NT rename not supported
7119

7120        m_sess.sendErrorResponseSMB(SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
7121    }
7122}
Popular Tags