Package com.knowgate.jcifs.smb

Source Code of com.knowgate.jcifs.smb.SmbTransport$Mid

/* jcifs smb client library in Java
* Copyright (C) 2000  "Michael B. Allen" <jcifs at samba dot org>
*                  "Eric Glass" <jcifs at samba dot org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package com.knowgate.jcifs.smb;

import com.knowgate.jcifs.netbios.NbtSocket;
import com.knowgate.jcifs.netbios.NbtException;
import com.knowgate.jcifs.netbios.NbtAddress;
import com.knowgate.jcifs.UniAddress;
import com.knowgate.jcifs.Config;
import com.knowgate.debug.*;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Enumeration;
import java.util.HashMap;


class SmbTransport implements Runnable {

    private static final int DEFAULT_MAX_MPX_COUNT = 10;
    private static final int DEFAULT_RESPONSE_TIMEOUT = 10000;
    private static final int DEFAULT_SO_TIMEOUT = 15000;
    private static final int DEFAULT_RCV_BUF_SIZE = 60416;
    private static final int DEFAULT_SND_BUF_SIZE = 5000;
    private static final int DEFAULT_SSN_LIMIT = 250;

    private static final InetAddress LADDR = Config.getInetAddress( "jcifs.smb.client.laddr", null );
    private static final int LPORT = Config.getInt( "jcifs.smb.client.lport", 0 );
    private static final int SSN_LIMIT = Config.getInt( "jcifs.smb.client.ssnLimit", DEFAULT_SSN_LIMIT );
    private static final int MAX_MPX_COUNT = Config.getInt( "jcifs.smb.client.maxMpxCount", DEFAULT_MAX_MPX_COUNT );
    private static final int SND_BUF_SIZE = Config.getInt( "jcifs.smb.client.snd_buf_size", DEFAULT_SND_BUF_SIZE );
    private static final int RCV_BUF_SIZE = Config.getInt( "jcifs.smb.client.rcv_buf_size", DEFAULT_RCV_BUF_SIZE );
    private static final boolean USE_UNICODE = Config.getBoolean( "jcifs.smb.client.useUnicode", true );
    private static final boolean FORCE_UNICODE = Config.getBoolean( "jcifs.smb.client.useUnicode", false );
    private static final boolean USE_NTSTATUS = Config.getBoolean( "jcifs.smb.client.useNtStatus", true );
    private static final boolean SIGNPREF = Config.getBoolean("jcifs.smb.client.signingPreferred", false );
    private static final boolean USE_NTSMBS = Config.getBoolean( "jcifs.smb.client.useNTSmbs", true );
    private static final int DEFAULT_FLAGS2 =
                ServerMessageBlock.FLAGS2_LONG_FILENAMES |
                ServerMessageBlock.FLAGS2_EXTENDED_ATTRIBUTES |
                ( SIGNPREF ? ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES : 0 ) |
                ( USE_NTSTATUS ? ServerMessageBlock.FLAGS2_STATUS32 : 0 ) |
                ( USE_UNICODE ? ServerMessageBlock.FLAGS2_UNICODE : 0 );
    private static final int DEFAULT_CAPABILITIES =
                ( USE_NTSMBS ? ServerMessageBlock.CAP_NT_SMBS : 0 ) |
                ( USE_NTSTATUS ? ServerMessageBlock.CAP_STATUS32 : 0 ) |
                ( USE_UNICODE ? ServerMessageBlock.CAP_UNICODE : 0 ) |
                ServerMessageBlock.CAP_DFS;
    private static final int FLAGS2 = Config.getInt( "jcifs.smb.client.flags2", DEFAULT_FLAGS2 );
    private static final int CAPABILITIES = Config.getInt( "jcifs.smb.client.capabilities", DEFAULT_CAPABILITIES );
    private static final int SO_TIMEOUT = Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_TIMEOUT );
    private static final boolean TCP_NODELAY = Config.getBoolean( "jcifs.smb.client.tcpNoDelay", false );
    private static final int RESPONSE_TIMEOUT =
                Config.getInt( "jcifs.smb.client.responseTimeout", DEFAULT_RESPONSE_TIMEOUT );

    private static final int PUSHBACK_BUF_SIZE = 64;
    private static final int MID_OFFSET = 30;
    private static final int FLAGS_RESPONSE = 0x80;
    private static final int ST_GROUND = 0;
    private static final int ST_NEGOTIATING = 1;
    private static final LinkedList CONNECTIONS = new LinkedList();
    private static final int MAGIC[] = { 0xFF, 'S', 'M', 'B' };

private static byte[] snd_buf = new byte[0xFFFF];
private static byte[] rcv_buf = new byte[0xFFFF];

    private NbtSocket socket;
    private HashMap responseTable;
    private InputStream in;
    private OutputStream out;
    private int localPort;
    private InetAddress localAddr;
    private Thread thread;
    private Object outLock;
    private UniAddress address;
    private int port;
    private LinkedList sessions;
    private LinkedList referrals = new LinkedList();
    private int state;
    private Mid[] mids = new Mid[MAX_MPX_COUNT];
    private short mid_next;

    static final String NATIVE_OS =
            Config.getProperty( "jcifs.smb.client.nativeOs", System.getProperty( "os.name" ));
    static final String NATIVE_LANMAN =
            Config.getProperty( "jcifs.smb.client.nativeLanMan", "jCIFS" );
    static final int VC_NUMBER = 1;

    static final SmbTransport NULL_TRANSPORT = new SmbTransport();

    class Mid {
        short mid;

        public int hashCode() {
            return mid;
        }
        public boolean equals( Object obj ) {
            return ((Mid)obj).mid == mid;
        }
    }
    class ServerData {
        byte flags;
        int flags2;
        int maxMpxCount;
        int maxBufferSize;
        int sessionKey;
        // NT 4 Workstation is 0x43FD
        int capabilities;
        String oemDomainName;
        int securityMode;
        int security;
        boolean encryptedPasswords;
        boolean signaturesEnabled;
        boolean signaturesRequired;
        int maxNumberVcs;
        int maxRawSize;
        long serverTime;
        int serverTimeZone;
        int encryptionKeyLength;
        byte[] encryptionKey;
    }

    int flags2 = FLAGS2;
    int maxMpxCount = MAX_MPX_COUNT;
    int snd_buf_size = SND_BUF_SIZE;
    int rcv_buf_size = RCV_BUF_SIZE;
    int capabilities = CAPABILITIES;
    int sessionKey = 0x00000000;
    boolean useUnicode = USE_UNICODE;
    String tconHostName;
    ServerData server;
    SigningDigest digest = null;

    static synchronized SmbTransport getSmbTransport( UniAddress address, int port ) {
        return getSmbTransport( address, port, LADDR, LPORT );
    }
    static synchronized SmbTransport getSmbTransport( UniAddress address, int port,
                                    InetAddress localAddr, int localPort ) {
        SmbTransport conn;

        synchronized( CONNECTIONS ) {
            if( SSN_LIMIT != 1 ) {
                ListIterator iter = CONNECTIONS.listIterator();
                while( iter.hasNext() ) {
                    conn = (SmbTransport)iter.next();
                    if( conn.matches( address, port, localAddr, localPort ) &&
                            ( SSN_LIMIT == 0 || conn.sessions.size() < SSN_LIMIT )) {
                        return conn;
                    }
                }
            }

            conn = new SmbTransport( address, port, localAddr, localPort );
            CONNECTIONS.add( 0, conn );
        }

        return conn;
    }

    SmbTransport( UniAddress address, int port, InetAddress localAddr, int localPort ) {
        this.address = address;
        this.port = port;
        this.localAddr = localAddr;
        this.localPort = localPort;

        sessions = new LinkedList();
        responseTable = new HashMap();
        outLock = new Object();
        state = ST_GROUND;

        int i;
        for( i = 0; i < MAX_MPX_COUNT; i++ ) {
            mids[i] = new Mid();
        }
    }
    SmbTransport() {
    }

    synchronized SmbSession getSmbSession() {
        return getSmbSession( new NtlmPasswordAuthentication( null, null, null ));
    }
    synchronized SmbSession getSmbSession( NtlmPasswordAuthentication auth ) {
        SmbSession ssn;

        ListIterator iter = sessions.listIterator();
        while( iter.hasNext() ) {
            ssn = (SmbSession)iter.next();
            if( ssn.matches( auth )) {
                ssn.auth = auth;
                return ssn;
            }
        }
        ssn = new SmbSession( address, port, localAddr, localPort, auth );
        ssn.transport = this;
        sessions.add( ssn );

        return ssn;
    }
    boolean matches( UniAddress address, int port, InetAddress localAddr, int localPort ) {
        InetAddress defaultLocal = null;
        try {
            defaultLocal = InetAddress.getLocalHost();
        } catch( UnknownHostException uhe ) {
        }
        int p1 = ( port == 0 || port == 139 ) ? 0 : port;
        int p2 = ( this.port == 0 || this.port == 139 ) ? 0 : this.port;
        InetAddress la1 = localAddr == null ? defaultLocal : localAddr;
        InetAddress la2 = this.localAddr == null ? defaultLocal : this.localAddr;
        return address.equals( this.address ) &&
                    p1 == p2 &&
                    la1.equals( la2 ) &&
                    localPort == this.localPort;
    }
    boolean hasCapability( int cap ) throws SmbException {
        if (state == ST_GROUND) {
            negotiate();
        }
        return (capabilities & cap) == cap;
    }
    boolean isSignatureSetupRequired( NtlmPasswordAuthentication auth ) {
        return ( flags2 & ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES ) != 0 &&
                digest == null &&
                auth != NtlmPasswordAuthentication.NULL &&
                NtlmPasswordAuthentication.NULL.equals( auth ) == false;
    }
    void ensureOpen() throws IOException {
        if( socket == null ) {
            Object obj;
            NbtAddress naddr;
            String calledName;

            obj = address.getAddress();
            if( obj instanceof NbtAddress ) {
                naddr = (NbtAddress)obj;
            } else {
                try {
                    naddr = NbtAddress.getByName( ((InetAddress)obj).getHostAddress() );
                } catch( UnknownHostException uhe ) {
                    naddr = null; // never happen
                }
            }

            calledName = address.firstCalledName();
            do {
                try {
                    socket = new NbtSocket( naddr, calledName, port, localAddr, localPort );
                    break;
                } catch( NbtException ne ) {
                    if( ne.errorClass == NbtException.ERR_SSN_SRVC &&
                                ( ne.errorCode == NbtException.CALLED_NOT_PRESENT ||
                                ne.errorCode == NbtException.NOT_LISTENING_CALLED )) {
                        if( DebugFile.trace )
                            new ErrorHandler(ne);
                    } else {
                        throw ne;
                    }
                }
            } while(( calledName = address.nextCalledName()) != null );

            if( calledName == null ) {
                throw new IOException( "Failed to establish session with " + address );
            }

            /* Save the calledName for using on SMB_COM_TREE_CONNECT
             */
            if( calledName == NbtAddress.SMBSERVER_NAME ) {
                tconHostName = address.getHostAddress();
            } else {
                tconHostName = calledName;
            }

            if( TCP_NODELAY ) {
                socket.setTcpNoDelay( true );
            }
            in = new PushbackInputStream( socket.getInputStream(), PUSHBACK_BUF_SIZE );
            out = socket.getOutputStream();
            thread = new Thread( this, "JCIFS-SmbTransport" );
            thread.setDaemon( true );
            thread.start();
        }
    }
    void tryClose( boolean inError ) {
        SmbSession ssn;

        if( socket == null ) {
            inError = true;
        }

        ListIterator iter = sessions.listIterator();
        while( iter.hasNext() ) {
            ssn = (SmbSession)iter.next();
            ssn.logoff( inError );
        }
        if( socket != null ) {
            try {
                socket.close();
            } catch( IOException ioe ) {
            }
        }
        digest = null;
        in = null;
        out = null;
        socket = null;
        thread = null;
        responseTable.clear();
        referrals.clear();
        sessions.clear();
        synchronized( CONNECTIONS ) {
            CONNECTIONS.remove( this );
        }
        state = ST_GROUND;
    }
    public void run() {
        Mid mid = new Mid();
        int i, m, nbtlen;
        ServerMessageBlock response;

        while( thread == Thread.currentThread() ) {
            try {
                socket.setSoTimeout( SO_TIMEOUT );

                m = 0;
                while( m < 4 ) {
                    if(( i = in.read() ) < 0 ) {
                        return;
                    }
                    if(( i & 0xFF ) == MAGIC[m] ) {
                        m++;
                    } else if(( i & 0xFF ) == 0xFF ) {
                        m = 1;
                    } else {
                        m = 0;
                    }
                }

                nbtlen = 4 + in.available();

synchronized( rcv_buf ) {
                rcv_buf[0] = (byte)0xFF;
                rcv_buf[1] = (byte)'S';
                rcv_buf[2] = (byte)'M';
                rcv_buf[3] = (byte)'B';

                if( in.read( rcv_buf, 4, ServerMessageBlock.HEADER_LENGTH - 4 ) !=
                                    ( ServerMessageBlock.HEADER_LENGTH - 4 )) {
                    /* Read on a netbios SocketInputStream does not
                     * return until len bytes have been read or the stream is
                     * closed. This must be the latter case.
                     */
                    break;
                }
                ((PushbackInputStream)in).unread( rcv_buf, 0, ServerMessageBlock.HEADER_LENGTH );
                if( rcv_buf[0] != (byte)0xFF ||
                                rcv_buf[1] != (byte)'S' ||
                                rcv_buf[2] != (byte)'M' ||
                                rcv_buf[3] != (byte)'B' ) {
                    if( DebugFile.trace )
                        DebugFile.writeln( "bad smb header, purging session message: " + address );
                    in.skip( in.available() );
                    continue;
                }
                if(( rcv_buf[ServerMessageBlock.FLAGS_OFFSET] &
                            ServerMessageBlock.FLAGS_RESPONSE ) ==
                            ServerMessageBlock.FLAGS_RESPONSE ) {
                    mid.mid = (short)(ServerMessageBlock.readInt2( rcv_buf, MID_OFFSET ) & 0xFFFF);

                    response = (ServerMessageBlock)responseTable.get( mid );
                    if( response == null ) {
                        if( DebugFile.trace) {
                            DebugFile.writeln( "no handler for mid=" + mid.mid +
                                    ", purging session message: " + address );
                        }
                        in.skip( in.available() );
                        continue;
                    }
                    synchronized( response ) {
                        response.useUnicode = useUnicode;

                        if( DebugFile.trace )
                            DebugFile.writeln( "new data read from socket: " + address );

                        if( response instanceof SmbComTransactionResponse ) {
                            Enumeration e = (Enumeration)response;
                            if( e.hasMoreElements() ) {
                                e.nextElement();
                            } else {
                                if( DebugFile.trace )
                                    DebugFile.writeln( "more responses to transaction than expected" );
                                continue;
                            }
                            if((m = response.readWireFormat( in, rcv_buf, 0 )) != nbtlen ) {
                                if( DebugFile.trace ) {
                                    DebugFile.writeln( "decoded " + m + " but nbtlen=" +
                                            nbtlen + ", purging session message" );
                                }
                                in.skip( in.available() );
                            }
                            response.received = true;

                            if( response.errorCode != 0 || e.hasMoreElements() == false ) {
                                ((SmbComTransactionResponse)response).hasMore = false;
                                if( digest != null ) {
                                    synchronized( outLock ) {
                                        digest.verify(rcv_buf, 0, response);
                                    }
                                }
                                response.notify();
                            } else {
                                ensureOpen();
                            }
                        } else {
                            response.readWireFormat( in, rcv_buf, 0 );
                            response.received = true;

                            if( digest != null ) {
                                synchronized( outLock ) {
                                    digest.verify(rcv_buf, 0, response);
                                }
                            }

                            response.notify();
                        }
                    }
                } else {
                    // it's a request(break oplock)
                }
}
            } catch( InterruptedIOException iioe ) {
                if( responseTable.size() == 0 ) {
                    tryClose( false );
                } else if( DebugFile.trace ) {
                    DebugFile.writeln( "soTimeout has occured but there are " +
                            responseTable.size() + " pending requests" );
                }
            } catch( IOException ioe ) {
                synchronized( this ) {
                    tryClose( true );
                }
                if( DebugFile.trace &&
                            ioe.getMessage().startsWith( "Connection reset" ) == false ) {
                    DebugFile.writeln( ioe.getMessage() + ": " + address );
                    new ErrorHandler(ioe);
                }
            }
        }
    }

    synchronized DfsReferral getDfsReferral( NtlmPasswordAuthentication auth, String path ) throws SmbException {
        String subpath, node, host;
        DfsReferral dr = new DfsReferral();
        int p, n, i, s;
        UniAddress addr;

        SmbTree ipc = getSmbSession( auth ).getSmbTree( "IPC$", null );
        Trans2GetDfsReferralResponse resp = new Trans2GetDfsReferralResponse();
        ipc.sendTransaction( new Trans2GetDfsReferral( path ), resp );

        subpath = path.substring( 0, resp.pathConsumed );
        node = resp.referral.node;
        if( subpath.charAt( 0 ) != '\\' ||
                (i = subpath.indexOf( '\\', 1 )) < 2 ||
                (p = subpath.indexOf( '\\', i + 1 )) < (i + 2) ||
                node.charAt( 0 ) != '\\' ||
                (s = node.indexOf( '\\', 1 )) < 2) {
            throw new SmbException( "Invalid DFS path: " + path );
        }
        if ((n = node.indexOf( '\\', s + 1 )) == -1) {
            n = node.length();
        }

        dr.path = subpath.substring( p );
        dr.node = node.substring( 0, n );
        dr.nodepath = node.substring( n );
        dr.server = node.substring( 1, s );
        dr.share = node.substring( s + 1, n );
        dr.resolveHashes = auth.hashesExternal;
                        /* NTLM HTTP Authentication must be re-negotiated
                         * with challenge from 'server' to access DFS vol. */
        return dr;
    }
    synchronized DfsReferral lookupReferral( String unc ) {
        DfsReferral dr;
        ListIterator iter = referrals.listIterator();
        int i, len;

        while( iter.hasNext() ) {
            dr = (DfsReferral)iter.next();
            len = dr.path.length();
            for( i = 0; i < len && i < unc.length(); i++ ) {
                if( dr.path.charAt( i ) != unc.charAt( i )) {
                    break;
                }
            }
            if( i == len && (len == unc.length() || unc.charAt( len ) == '\\')) {
                return dr;
            }
        }

        return null;
    }
    void send( ServerMessageBlock request,
                            ServerMessageBlock response ) throws SmbException {
        Mid mid = null;

        if (state == ST_GROUND) {
            negotiate();
        }

        request.flags2 |= flags2;
        request.useUnicode = useUnicode;

        if( response == null ) {
            try {
                synchronized( outLock ) {
                    mid = aquireMid();
                    request.mid = mid.mid;
                    ensureOpen();
synchronized( snd_buf ) {
                    request.digest = digest;
                    request.response = null;
                    int length = request.writeWireFormat(snd_buf, 4);
                    out.write(snd_buf, 4, length);
                    out.flush();
}
                }
            } catch( IOException ioe ) {
                tryClose( true );
                throw new SmbException( "An error occured sending the request.", ioe );
            } finally {
                synchronized( outLock ) {
                    releaseMid( mid );
                }
            }

            return;
        }

        // now for the normal case where response is not null

        try {
            synchronized( response ) {
                synchronized( outLock ) {
                    response.received = false;
                    mid = aquireMid();
                    request.mid = mid.mid;
                    responseTable.put( mid, response );
                    ensureOpen();
synchronized( snd_buf ) {
                    if( digest != null ) {
                        request.digest = digest;
                        request.response = response;
                    }
                    int length = request.writeWireFormat(snd_buf, 4);
                    out.write(snd_buf, 4, length);
                    out.flush();
}
                }

                // default it 1 so that 0 can be used as forever
                response.wait( response.responseTimeout == 1 ? RESPONSE_TIMEOUT : response.responseTimeout );
            }
        } catch( InterruptedException ie ) {
            tryClose( true );
        } catch( IOException ioe ) {
            tryClose( true );
            throw new SmbException( "An error occured sending the request.", ioe );
        } finally {
            synchronized( outLock ) {
                responseTable.remove( mid );
                releaseMid( mid );
            }
        }

        if( response.received == false ) {
            tryClose( true );
            throw new SmbException( "Timeout waiting for response from server: " + address );
        } else if( response.verifyFailed ) {
            tryClose( true );
            throw new SmbException( "Unverifiable signature: " + address );
        }
        response.errorCode = SmbException.getStatusByCode( response.errorCode );
        switch( response.errorCode ) {
            case NtStatus.NT_STATUS_OK:
                break;
            case NtStatus.NT_STATUS_ACCESS_DENIED:
            case NtStatus.NT_STATUS_WRONG_PASSWORD:
            case NtStatus.NT_STATUS_LOGON_FAILURE:
            case NtStatus.NT_STATUS_ACCOUNT_RESTRICTION:
            case NtStatus.NT_STATUS_INVALID_LOGON_HOURS:
            case NtStatus.NT_STATUS_INVALID_WORKSTATION:
            case NtStatus.NT_STATUS_PASSWORD_EXPIRED:
            case NtStatus.NT_STATUS_ACCOUNT_DISABLED:
            case NtStatus.NT_STATUS_ACCOUNT_LOCKED_OUT:
                throw new SmbAuthException( response.errorCode );
            case NtStatus.NT_STATUS_PATH_NOT_COVERED:
                if( request.auth == null ) {
                    throw new SmbException( response.errorCode, null );
                }
                DfsReferral dr = getDfsReferral( request.auth, request.path );
                referrals.add( dr );
                throw dr;
            default:
                throw new SmbException( response.errorCode, null );
        }
    }
    void sendTransaction( SmbComTransaction request,
                            SmbComTransactionResponse response ) throws SmbException {
        Mid mid = null;

        negotiate();

        request.flags2 |= flags2;
        request.useUnicode = useUnicode;
        request.maxBufferSize = snd_buf_size;
        response.received = false;
        response.hasMore = true;
        response.isPrimary = true;

        try {
            request.txn_buf = BufferCache.getBuffer();
            response.txn_buf = BufferCache.getBuffer();

            request.nextElement();
            if( request.hasMoreElements() ) {
                // multi-part request

                SmbComBlankResponse interimResponse = new SmbComBlankResponse();

                synchronized( interimResponse ) {
                    synchronized( outLock ) {
                        mid = aquireMid();
                        request.mid = mid.mid;
                        responseTable.put( mid, interimResponse );
                        ensureOpen();
synchronized(snd_buf) {
                        request.digest = digest;
                        request.response = response;
                        int length = request.writeWireFormat(snd_buf, 4);
                        out.write(snd_buf, 4, length);
                        out.flush();
}
                    }

                    interimResponse.wait( RESPONSE_TIMEOUT );

                    if( interimResponse.received == false ) {
                        throw new SmbException( "Timeout waiting for response from server: " + address );
                    }
                    interimResponse.errorCode = SmbException.getStatusByCode( interimResponse.errorCode );
                    switch( interimResponse.errorCode ) {
                        case NtStatus.NT_STATUS_OK:
                            break;
                        case NtStatus.NT_STATUS_ACCESS_DENIED:
                        case NtStatus.NT_STATUS_WRONG_PASSWORD:
                        case NtStatus.NT_STATUS_LOGON_FAILURE:
                        case NtStatus.NT_STATUS_ACCOUNT_RESTRICTION:
                        case NtStatus.NT_STATUS_INVALID_LOGON_HOURS:
                        case NtStatus.NT_STATUS_INVALID_WORKSTATION:
                        case NtStatus.NT_STATUS_PASSWORD_EXPIRED:
                        case NtStatus.NT_STATUS_ACCOUNT_DISABLED:
                        case NtStatus.NT_STATUS_ACCOUNT_LOCKED_OUT:
                            throw new SmbAuthException( interimResponse.errorCode );
                        case NtStatus.NT_STATUS_PATH_NOT_COVERED:
                            if( request.auth == null ) {
                                throw new SmbException( interimResponse.errorCode, null );
                            }
                            DfsReferral dr = getDfsReferral( request.auth, request.path );
                            referrals.add( dr );
                            throw dr;
                        default:
                            throw new SmbException( interimResponse.errorCode, null );
                    }
                }
                request.nextElement();
            }

            synchronized( response ) {
                synchronized( outLock ) {
                    mid = aquireMid();
                    request.mid = mid.mid;
                    responseTable.put( mid, response );
                }
                do {
                    synchronized( outLock ) {
                        ensureOpen();
synchronized( snd_buf ) {
                        request.digest = digest;
                        request.response = response;
                        int length = request.writeWireFormat(snd_buf, 4);
                        out.write(snd_buf, 4, length);
                        out.flush();
}
                    }
                } while( request.hasMoreElements() && request.nextElement() != null );

                do {
                    // default it 1 so that 0 can be used as forever
                    response.received = false;
                    response.wait( response.responseTimeout == 1 ? RESPONSE_TIMEOUT : response.responseTimeout );
                } while( response.received && response.hasMoreElements() );
            }
        } catch( InterruptedException ie ) {
            tryClose( true );
        } catch( IOException ioe ) {
            tryClose( true );
            throw new SmbException( "An error occured sending the request.", ioe );
        } finally {
            synchronized( outLock ) {
                responseTable.remove( mid );
                releaseMid( mid );
            }
            BufferCache.releaseBuffer( request.txn_buf );
            BufferCache.releaseBuffer( response.txn_buf );
        }

        if( response.received == false ) {
            tryClose( true );
            throw new SmbException( "Timeout waiting for response from server: " + address );
        } else if( response.verifyFailed ) {
            tryClose( true );
            throw new SmbException( "Unverifiable signature: " + address );
        }
        response.errorCode = SmbException.getStatusByCode( response.errorCode );
        switch( response.errorCode ) {
            case NtStatus.NT_STATUS_OK:
                break;
            case NtStatus.NT_STATUS_ACCESS_DENIED:
            case NtStatus.NT_STATUS_WRONG_PASSWORD:
            case NtStatus.NT_STATUS_LOGON_FAILURE:
            case NtStatus.NT_STATUS_ACCOUNT_RESTRICTION:
            case NtStatus.NT_STATUS_INVALID_LOGON_HOURS:
            case NtStatus.NT_STATUS_INVALID_WORKSTATION:
            case NtStatus.NT_STATUS_PASSWORD_EXPIRED:
            case NtStatus.NT_STATUS_ACCOUNT_DISABLED:
            case NtStatus.NT_STATUS_ACCOUNT_LOCKED_OUT:
                throw new SmbAuthException( response.errorCode );
            case NtStatus.NT_STATUS_PATH_NOT_COVERED:
                if( request.auth == null ) {
                    throw new SmbException( response.errorCode, null );
                }
                DfsReferral dr = getDfsReferral( request.auth, request.path );
                referrals.add( dr );
                throw dr;
            default:
                throw new SmbException( response.errorCode, null );
        }
    }
    synchronized void negotiate() throws SmbException {

        if( this == NULL_TRANSPORT ) {
            throw new RuntimeException( "Null transport cannot be used" );
        }
        if( state >= ST_NEGOTIATING ) {
            return;
        }
        state = ST_NEGOTIATING;

        if( DebugFile.trace )
            DebugFile.writeln( "requesting negotiation with " + address );

        /*
         * Negotiate Protocol Request / Response
         */

        SmbComNegotiateResponse response = new SmbComNegotiateResponse();
        send( new SmbComNegotiate(), response );

        if( response.dialectIndex > 10 ) {
            tryClose( true );
            throw new SmbException( "This client does not support the negotiated dialect." );
        }

        server = new ServerData();
        server.securityMode = response.securityMode;
        server.security = response.security;
        server.encryptedPasswords = response.encryptedPasswords;
        server.signaturesEnabled = response.signaturesEnabled;
        server.signaturesRequired = response.signaturesRequired;
        server.maxMpxCount = response.maxMpxCount;
        server.maxNumberVcs = response.maxNumberVcs;
        server.maxBufferSize = response.maxBufferSize;
        server.maxRawSize = response.maxRawSize;
        server.sessionKey = response.sessionKey;
        server.capabilities = response.capabilities;
        server.serverTime = response.serverTime;
        server.serverTimeZone = response.serverTimeZone;
        server.encryptionKeyLength = response.encryptionKeyLength;
        server.encryptionKey = response.encryptionKey;
        server.oemDomainName = response.oemDomainName;

        if (server.signaturesRequired || (server.signaturesEnabled && SIGNPREF)) {
            flags2 |= ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
        } else {
            flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
        }

        maxMpxCount = maxMpxCount < server.maxMpxCount ? maxMpxCount : server.maxMpxCount;
        maxMpxCount = maxMpxCount < 1 ? 1 : maxMpxCount;

        snd_buf_size = snd_buf_size < server.maxBufferSize ? snd_buf_size : server.maxBufferSize;

        capabilities &= server.capabilities;
        if(( capabilities & ServerMessageBlock.CAP_UNICODE ) == 0 ) {
            // server doesn't want unicode
            if( FORCE_UNICODE ) {
                capabilities |= ServerMessageBlock.CAP_UNICODE;
            } else {
                useUnicode = false;
                flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_UNICODE;
            }
        }
    }
    public String toString() {
        String ret = "SmbTransport[address=" + address;
        if( socket == null ) {
            ret += ",port=,localAddr=,localPort=]";
        } else {
            ret += ",port=" + socket.getPort() +
            ",localAddr=" + socket.getLocalAddress() +
            ",localPort=" + socket.getLocalPort() + "]";
        }
        return ret;
    }

    /* Manage MIDs */

    Mid aquireMid() throws SmbException {
        int i;

        if( mid_next == 0 ) {
            mid_next++;
        }

        for( ;; ) {
            for( i = 0; i < maxMpxCount; i++ ) {
                if( mids[i].mid == 0 ) {
                    break;
                }
            }
            if( i == maxMpxCount ) {
                try {
                    outLock.wait();
                } catch( InterruptedException ie ) {
                    throw new SmbException( "Interrupted aquiring mid", ie );
                }
            } else {
                break;
            }
        }

        mids[i].mid = mid_next++;

        return mids[i];
    }
    void releaseMid( Mid mid ) {
        int i;

        for( i = 0; i < maxMpxCount; i++ ) {
            if( mids[i].mid == mid.mid ) {
                mid.mid = 0;
                outLock.notify();
                return;
            }
        }
        if( DebugFile.trace )
            DebugFile.writeln( "mid not found" );
    }
}
TOP

Related Classes of com.knowgate.jcifs.smb.SmbTransport$Mid

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.