FileDocCategorySizeDatePackage
SmbSession.javaAPI DocJCIFS 1.3.17 API19467Tue Oct 18 15:26:24 BST 2011jcifs.smb

SmbSession

public final class SmbSession extends Object

Fields Summary
private static final String
LOGON_SHARE
private static final int
LOOKUP_RESP_LIMIT
private static final String
DOMAIN
private static final String
USERNAME
private static final int
CACHE_POLICY
static jcifs.netbios.NbtAddress[]
dc_list
static long
dc_list_expiration
static int
dc_list_counter
int
connectionState
int
uid
Vector
trees
private jcifs.UniAddress
address
private int
port
private int
localPort
private InetAddress
localAddr
SmbTransport
transport
NtlmPasswordAuthentication
auth
long
expiration
String
netbiosName
Constructors Summary
SmbSession(jcifs.UniAddress address, int port, InetAddress localAddr, int localPort, NtlmPasswordAuthentication auth)


        
                   
                   
        this.address = address;
        this.port = port;
        this.localAddr = localAddr;
        this.localPort = localPort;
        this.auth = auth;
        trees = new Vector();
        connectionState = 0;
    
Methods Summary
public static byte[]getChallenge(jcifs.UniAddress dc)

        return getChallenge(dc, 0);
    
public static byte[]getChallenge(jcifs.UniAddress dc, int port)

        SmbTransport trans = SmbTransport.getSmbTransport( dc, port );
        trans.connect();
        return trans.server.encryptionKey;
    
public static NtlmChallengegetChallengeForDomain()

        if( DOMAIN == null ) {
            throw new SmbException( "A domain was not specified" );
        }
synchronized (DOMAIN) {
            long now = System.currentTimeMillis();
            int retry = 1;

            do {
                if (dc_list_expiration < now) {
                    NbtAddress[] list = NbtAddress.getAllByName( DOMAIN, 0x1C, null, null );
                    dc_list_expiration = now + CACHE_POLICY * 1000L;
                    if (list != null && list.length > 0) {
                        dc_list = list;
                    } else { /* keep using the old list */
                        dc_list_expiration = now + 1000 * 60 * 15; /* 15 min */
                        if (SmbTransport.log.level >= 2) {
                            SmbTransport.log.println( "Failed to retrieve DC list from WINS" );
                        }
                    }
                }

                int max = Math.min( dc_list.length, LOOKUP_RESP_LIMIT );
                for (int j = 0; j < max; j++) {
                    int i = dc_list_counter++ % max;
                    if (dc_list[i] != null) {
                        try {
                            return interrogate( dc_list[i] );
                        } catch (SmbException se) {
                            if (SmbTransport.log.level >= 2) {
                                SmbTransport.log.println( "Failed validate DC: " + dc_list[i] );
                                if (SmbTransport.log.level > 2)
                                    se.printStackTrace( SmbTransport.log );
                            }
                        }
                        dc_list[i] = null;
                    }
                }

                /* No DCs found, for retieval of list by expiring it and retry.
                 */
                dc_list_expiration = 0;
            } while (retry-- > 0);

            dc_list_expiration = now + 1000 * 60 * 15; /* 15 min */
}

        throw new UnknownHostException(
                "Failed to negotiate with a suitable domain controller for " + DOMAIN );
    
synchronized SmbTreegetSmbTree(java.lang.String share, java.lang.String service)

        SmbTree t;

        if( share == null ) {
            share = "IPC$";
        }
        for( Enumeration e = trees.elements(); e.hasMoreElements(); ) {
            t = (SmbTree)e.nextElement();
            if( t.matches( share, service )) {
                return t;
            }
        }
        t = new SmbTree( this, share, service );
        trees.addElement( t );
        return t;
    
private static NtlmChallengeinterrogate(jcifs.netbios.NbtAddress addr)


             
        UniAddress dc = new UniAddress( addr );
        SmbTransport trans = SmbTransport.getSmbTransport( dc, 0 );
        if (USERNAME == null) {
            trans.connect();
            if (SmbTransport.log.level >= 3)
                SmbTransport.log.println(
                    "Default credentials (jcifs.smb.client.username/password)" +
                    " not specified. SMB signing may not work propertly." +
                    "  Skipping DC interrogation." );
        } else {
            SmbSession ssn = trans.getSmbSession( NtlmPasswordAuthentication.DEFAULT );
            ssn.getSmbTree( LOGON_SHARE, null ).treeConnect( null, null );
        }
        return new NtlmChallenge( trans.server.encryptionKey, dc );
    
voidlogoff(boolean inError)

synchronized (transport()) {

        if (connectionState != 2) // not-connected
            return;
        connectionState = 3; // disconnecting

        netbiosName = null;

        for( Enumeration e = trees.elements(); e.hasMoreElements(); ) {
            SmbTree t = (SmbTree)e.nextElement();
            t.treeDisconnect( inError );
        }

        if( !inError && transport.server.security != ServerMessageBlock.SECURITY_SHARE ) {
            /*
             * Logoff And X Request / Response
             */

            SmbComLogoffAndX request = new SmbComLogoffAndX( null );
            request.uid = uid;
            try {
                transport.send( request, null );
            } catch( SmbException se ) {
            }
            uid = 0;
        }

        connectionState = 0;
        transport.notifyAll();
}
    
public static voidlogon(jcifs.UniAddress dc, NtlmPasswordAuthentication auth)
Authenticate arbitrary credentials represented by the NtlmPasswordAuthentication object against the domain controller specified by the UniAddress parameter. If the credentials are not accepted, an SmbAuthException will be thrown. If an error occurs an SmbException will be thrown. If the credentials are valid, the method will return without throwing an exception. See the last FAQ question.

See also the jcifs.smb.client.logonShare property.

        logon(dc, 0, auth);
    
public static voidlogon(jcifs.UniAddress dc, int port, NtlmPasswordAuthentication auth)

        SmbTree tree = SmbTransport.getSmbTransport( dc, port ).getSmbSession( auth ).getSmbTree( LOGON_SHARE, null );
        if( LOGON_SHARE == null ) {
            tree.treeConnect( null, null );
        } else {
            Trans2FindFirst2 req = new Trans2FindFirst2( "\\", "*", SmbFile.ATTR_DIRECTORY );
            Trans2FindFirst2Response resp = new Trans2FindFirst2Response();
            tree.send( req, resp );
        }
    
booleanmatches(NtlmPasswordAuthentication auth)

        return this.auth == auth || this.auth.equals( auth );
    
voidsend(ServerMessageBlock request, ServerMessageBlock response)

synchronized (transport()) {
        if( response != null ) {
            response.received = false;
        }

        expiration = System.currentTimeMillis() + SmbTransport.SO_TIMEOUT;
        sessionSetup( request, response );
        if( response != null && response.received ) {
            return;
        }

        if (request instanceof SmbComTreeConnectAndX) {
            SmbComTreeConnectAndX tcax = (SmbComTreeConnectAndX)request;
            if (netbiosName != null && tcax.path.endsWith("\\IPC$")) {
                /* Some pipes may require that the hostname in the tree connect
                 * be the netbios name. So if we have the netbios server name
                 * from the NTLMSSP type 2 message, and the share is IPC$, we
                 * assert that the tree connect path uses the netbios hostname.
                 */
                tcax.path = "\\\\" + netbiosName + "\\IPC$";
            }
        }

        request.uid = uid;
        request.auth = auth;
        try {
            transport.send( request, response );
        } catch (SmbException se) {
            if (request instanceof SmbComTreeConnectAndX) {
                logoff(true);
            }
            request.digest = null;
            throw se;
        }
}
    
voidsessionSetup(ServerMessageBlock andx, ServerMessageBlock andxResponse)

synchronized (transport()) {
        NtlmContext nctx = null;
        SmbException ex = null;
        SmbComSessionSetupAndX request;
        SmbComSessionSetupAndXResponse response;
        byte[] token = new byte[0];
        int state = 10;

        while (connectionState != 0) {
            if (connectionState == 2 || connectionState == 3) // connected or disconnecting
                return;
            try {
                transport.wait();
            } catch (InterruptedException ie) {
                throw new SmbException(ie.getMessage(), ie);
            }
        }
        connectionState = 1; // trying ...

        try {
            transport.connect();

            /*
             * Session Setup And X Request / Response
             */
    
            if( transport.log.level >= 4 )
                transport.log.println( "sessionSetup: accountName=" + auth.username + ",primaryDomain=" + auth.domain );
    
            /* We explicitly set uid to 0 here to prevent a new
             * SMB_COM_SESSION_SETUP_ANDX from having it's uid set to an
             * old value when the session is re-established. Otherwise a
             * "The parameter is incorrect" error can occur.
             */
            uid = 0;
    
            do {
                switch (state) {
                    case 10: /* NTLM */
                        if (auth != NtlmPasswordAuthentication.ANONYMOUS &&
                                transport.hasCapability(SmbConstants.CAP_EXTENDED_SECURITY)) {
                            state = 20; /* NTLMSSP */
                            break;
                        }
    
                        request = new SmbComSessionSetupAndX( this, andx, auth );
                        response = new SmbComSessionSetupAndXResponse( andxResponse );
    
                        /* Create SMB signature digest if necessary
                         * Only the first SMB_COM_SESSION_SETUP_ANX with non-null or
                         * blank password initializes signing.
                         */
                        if (transport.isSignatureSetupRequired( auth )) {
                            if( auth.hashesExternal && NtlmPasswordAuthentication.DEFAULT_PASSWORD != NtlmPasswordAuthentication.BLANK ) {
                                /* preauthentication
                                 */
                                transport.getSmbSession( NtlmPasswordAuthentication.DEFAULT ).getSmbTree( LOGON_SHARE, null ).treeConnect( null, null );
                            } else {
                                byte[] signingKey = auth.getSigningKey(transport.server.encryptionKey);
                                request.digest = new SigningDigest(signingKey, false);
                            }
                        }
    
                        request.auth = auth;
    
                        try {
                            transport.send( request, response );
                        } catch (SmbAuthException sae) {
                            throw sae;
                        } catch (SmbException se) {
                            ex = se;
                        }
    
                        if( response.isLoggedInAsGuest &&
                                    "GUEST".equalsIgnoreCase( auth.username ) == false &&
                                    transport.server.security != SmbConstants.SECURITY_SHARE &&
                                    auth != NtlmPasswordAuthentication.ANONYMOUS) {
                            throw new SmbAuthException( NtStatus.NT_STATUS_LOGON_FAILURE );
                        }
    
                        if (ex != null)
                            throw ex;
    
                        uid = response.uid;
    
                        if( request.digest != null ) {
                            /* success - install the signing digest */
                            transport.digest = request.digest;
                        }
    
                        connectionState = 2;    

                        state = 0;
    
                        break;
                    case 20:
                        if (nctx == null) {
                            boolean doSigning = (transport.flags2 & ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES) != 0;
                            nctx = new NtlmContext(auth, doSigning);
                        }
    
                        if (SmbTransport.log.level >= 4)
                            SmbTransport.log.println(nctx);
    
                        if (nctx.isEstablished()) {

                            netbiosName = nctx.getNetbiosName();

                            connectionState = 2;

                            state = 0;
                            break;
                        }
    
                        try {
                            token = nctx.initSecContext(token, 0, token.length);
                        } catch (SmbException se) {
                            /* We must close the transport or the server will be expecting a
                             * Type3Message. Otherwise, when we send a Type1Message it will return
                             * "Invalid parameter".
                             */
                            try { transport.disconnect(true); } catch (IOException ioe) {}
                            uid = 0;
                            throw se;
                        }
    
                        if (token != null) {
                            request = new SmbComSessionSetupAndX(this, null, token);
                            response = new SmbComSessionSetupAndXResponse(null);
    
                            if (transport.isSignatureSetupRequired( auth )) {
                                byte[] signingKey = nctx.getSigningKey();
                                if (signingKey != null)
                                    request.digest = new SigningDigest(signingKey, true);
                            }
    
                            request.uid = uid;
                            uid = 0;
    
                            try {
                                transport.send( request, response );
                            } catch (SmbAuthException sae) {
                                throw sae;
                            } catch (SmbException se) {
                                ex = se;
                                /* Apparently once a successfull NTLMSSP login occurs, the
                                 * server will return "Access denied" even if a logoff is
                                 * sent. Unfortunately calling disconnect() doesn't always
                                 * actually shutdown the connection before other threads
                                 * have committed themselves (e.g. InterruptTest example).
                                 */
                                try { transport.disconnect(true); } catch (Exception e) {}
                            }
    
                            if( response.isLoggedInAsGuest &&
                                        "GUEST".equalsIgnoreCase( auth.username ) == false) {
                                throw new SmbAuthException( NtStatus.NT_STATUS_LOGON_FAILURE );
                            }
    
                            if (ex != null)
                                throw ex;
    
                            uid = response.uid;
    
                            if (request.digest != null) {
                                /* success - install the signing digest */
                                transport.digest = request.digest;
                            }
    
                            token = response.blob;
                        }
    
                        break;
                    default:
                        throw new SmbException("Unexpected session setup state: " + state);
                }
            } while (state != 0);
        } catch (SmbException se) {
            logoff(true);
            connectionState = 0;
            throw se;
        } finally {
            transport.notifyAll();
        }
}
    
public java.lang.StringtoString()

        return "SmbSession[accountName=" + auth.username +
                ",primaryDomain=" + auth.domain +
                ",uid=" + uid +
                ",connectionState=" + connectionState + "]";
    
synchronized SmbTransporttransport()

        if( transport == null ) {
            transport = SmbTransport.getSmbTransport( address, port, localAddr, localPort, null );
        }
        return transport;